C# マウスホバー状態のコントロールにホイールでスクロールさせる


C# マウスホバー状態のコントロールにホイールでスクロールさせる

例えば一覧上にマウスカーソルがある状態でホイールをコロコロすると

コントロールが選択状態ならスクロールするものの、

未選択の状態ではスクロールしてくれません。

これは結構不便で、私はクライアントにWheelRedirectorとかのアプリを

常駐させているのですが、これと同じことを

C#で実装する方法です。

 

ほぼ転載です。

この記事を参考にしました。

要するにマウスホバーした状態で発生したメッセージを

ホバーしているコントロールに引き渡すようにします。

参照元のソースをベースにちょっと手を加えてこんな感じにしてみました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace hoge
{
    /// <summary>
    /// マウスホバーによるメッセージリダイレクトを行うクラス
    /// </summary>
    class MessageRedirector : NativeWindow, IMessageFilter
    {
        private const int MSG_WHEEL_SCROLL = 0x20A;

        private System.Windows.Forms.Control _Control;
        private System.Windows.Forms.Control _PreviousParent;
        private HashSet<int> _Messages;
        private bool _IsMouseOverControl;

        public MessageRedirector(System.Windows.Forms.Control control)
            : this(control, new int[] { MSG_WHEEL_SCROLL })
        {
        }
        public MessageRedirector(System.Windows.Forms.Control control, int message) 
            : this(control, new int[] { message })
        { 
        }
        public MessageRedirector(System.Windows.Forms.Control control, IEnumerable<int> messages)
        {
            _Control = control;
            AssignHandle(control.Handle);
            _Messages = new HashSet<int>(messages);
            _PreviousParent = control.Parent;
            _IsMouseOverControl = false;

            control.ParentChanged += new EventHandler(control_ParentChanged);
            control.MouseEnter += new EventHandler(control_MouseEnter);
            control.MouseLeave += new EventHandler(control_MouseLeave);
            control.Leave += new EventHandler(control_Leave);

            if (control.Parent != null)
            {
                Application.AddMessageFilter(this);
            }
        }

        public bool PreFilterMessage(ref System.Windows.Forms.Message m)
        {
            if (_Messages.Contains(m.Msg) && 
                _Control.CanFocus && 
                !_Control.Focused && 
                _IsMouseOverControl)
            {
                m.HWnd = _Control.Handle;
                WndProc(ref m);
                return true;
            }

            return false;
        }

        void control_ParentChanged(object sender, EventArgs e)
        {
            if (_Control.Parent == null)
            {
                Application.RemoveMessageFilter(this);
            }
            else
            {
                if (_PreviousParent == null)
                {
                    Application.AddMessageFilter(this);
                }
            }
            _PreviousParent = _Control.Parent;
        }

        void control_MouseEnter(object sender, EventArgs e)
        {
            _IsMouseOverControl = true;
        }

        void control_MouseLeave(object sender, EventArgs e)
        {
            _IsMouseOverControl = false;
        }

        void control_Leave(object sender, EventArgs e)
        {
            _IsMouseOverControl = false;
        }

        public static void setRedirect(System.Windows.Forms.Control target, int message = MSG_WHEEL_SCROLL)
        {
            foreach (System.Windows.Forms.Control control in CommonUtility.GetAllControls(target))
            {
                new MessageRedirector(control, message);
            }
        }

    }
}

 

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace hoge
{
    public class CommonUtility
    {
        /// <summary>
        /// 配下すべてのコントロールを列挙する
        /// </summary>
        /// <param name="top"></param>
        /// <returns></returns>
        public static System.Windows.Forms.Control[] GetAllControls(System.Windows.Forms.Control top)
        {
            ArrayList buf = new ArrayList();
            foreach (System.Windows.Forms.Control c in top.Controls)
            {
                buf.Add(c);
                buf.AddRange(GetAllControls(c));
            }
            return (System.Windows.Forms.Control[])buf.ToArray(typeof(System.Windows.Forms.Control));
        }
    }
}

使う時にはこんな感じで使えると思います。

// tabControl1配下のコントロールにWheel操作をリダイレクト
MessageRedirector.setRedirect(tabControl1);

 

以上でコントロールにフォーカスがなくてもスクロールできるようになります。

これはスマートですね。

 


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です