C# 鼠标滚轮滚动工具条菜单项

C# 鼠标滚轮滚动工具条菜单项,c#,winforms,scroll,toolstripitem,toolstripmenu,C#,Winforms,Scroll,Toolstripitem,Toolstripmenu,我有一些包含许多菜单项的菜单。鼠标滚轮不会滚动它们。我必须使用键盘箭头或单击顶部和底部的箭头。 是否可以使用鼠标滚轮滚动toolstrip菜单项? 感谢一个有效的解决方案: 在表单的Load事件中注册表单的mouseweel事件和根目录的DropDownClosed事件MenuStripItem(此处,rootItem) this.MouseWheel += Form3_MouseWheel; rootItem.DropDownOpened += rootItem_DropDow

我有一些包含许多菜单项的菜单。鼠标滚轮不会滚动它们。我必须使用键盘箭头或单击顶部和底部的箭头。 是否可以使用鼠标滚轮滚动toolstrip菜单项? 感谢

一个有效的解决方案:

  • 在表单的
    Load
    事件中注册表单的
    mouseweel
    事件和根目录的
    DropDownClosed
    事件
    MenuStripItem
    (此处,rootItem)

        this.MouseWheel += Form3_MouseWheel;
        rootItem.DropDownOpened += rootItem_DropDownOpened;
        rootItem.DropDownClosed += rootItem_DropDownClosed;
    
  • 为模拟按键的
    键盘
    类添加代码

    public static class Keyboard
    {
        [DllImport("user32.dll")]
        static extern uint keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
    
    
        const byte VK_UP = 0x26; // Arrow Up key
        const byte VK_DOWN = 0x28; // Arrow Down key
    
        const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag, the key is going to be pressed
        const int KEYEVENTF_KEYUP = 0x0002; //Key up flag, the key is going to be released
    
        public static void KeyDown()
        {
            keybd_event(VK_DOWN, 0, KEYEVENTF_EXTENDEDKEY, 0);
            keybd_event(VK_DOWN, 0, KEYEVENTF_KEYUP, 0);
        }
    
        public static void KeyUp()
        {
            keybd_event(VK_UP, 0, KEYEVENTF_EXTENDEDKEY, 0);
            keybd_event(VK_UP, 0, KEYEVENTF_KEYUP, 0);
        }
    }
    
  • 添加
    下拉打开
    下拉关闭
    鼠标滚轮
    事件的代码:

    bool IsMenuStripOpen  = false;
    
    void rootItem_DropDownOpened(object sender, EventArgs e)
    {
        IsMenuStripOpen = true;
    }
    
    
    void rootItem_DropDownClosed(object sender, EventArgs e)
    {
        IsMenuStripOpen = false;
    }
    
    void Form3_MouseWheel(object sender, MouseEventArgs e)
    {
        if (IsMenuStripOpen)
        {
            if (e.Delta > 0)
            {
                Keyboard.KeyUp();
            }
            else
            {
                Keyboard.KeyDown();
            }
        }
    }
    

  • 您可以使用此类在应用程序范围内启用it:

    public class DropDownMenuScrollWheelHandler : System.Windows.Forms.IMessageFilter
    {
        private static DropDownMenuScrollWheelHandler Instance;
        public static void Enable(bool enabled)
        {
            if (enabled)
            {
                if (Instance == null)
                {
                    Instance = new DropDownMenuScrollWheelHandler();
                    Application.AddMessageFilter(Instance);
                }
            }
            else
            {
                if (Instance != null)
                {
                    Application.RemoveMessageFilter(Instance);
                    Instance = null;
                }
            }
        }
        private IntPtr activeHwnd;
        private ToolStripDropDown activeMenu;
    
        public bool PreFilterMessage(ref Message m)
        {
            if (m.Msg == 0x200 && activeHwnd != m.HWnd) // WM_MOUSEMOVE
            {
                activeHwnd = m.HWnd;
                this.activeMenu = Control.FromHandle(m.HWnd) as ToolStripDropDown;
            }
            else if (m.Msg == 0x20A && this.activeMenu != null) // WM_MOUSEWHEEL
            {
                int delta = (short)(ushort)(((uint)(ulong)m.WParam) >> 16);
                handleDelta(this.activeMenu, delta);
                return true;
            }
            return false;
        }
    
        private static readonly Action<ToolStrip, int> ScrollInternal
            = (Action<ToolStrip, int>)Delegate.CreateDelegate(typeof(Action<ToolStrip, int>),
                typeof(ToolStrip).GetMethod("ScrollInternal",
                    System.Reflection.BindingFlags.NonPublic
                    | System.Reflection.BindingFlags.Instance));
    
        private void handleDelta(ToolStripDropDown ts, int delta)
        {
            if (ts.Items.Count == 0)
                return;
            var firstItem = ts.Items[0];
            var lastItem = ts.Items[ts.Items.Count - 1];
            if (lastItem.Bounds.Bottom < ts.Height && firstItem.Bounds.Top > 0)
                return;
            delta = delta / -4;
            if (delta < 0 && firstItem.Bounds.Top - delta > 9)
            {
                delta = firstItem.Bounds.Top - 9;
            }
            else if (delta > 0 && delta > lastItem.Bounds.Bottom - ts.Height + 9)
            {
                delta = lastItem.Bounds.Bottom - owner.Height + 9;
            }
            if (delta != 0)
                ScrollInternal(ts, delta);
        }
    }
    
    公共类DropDownMenusRollWheelHandler:System.Windows.Forms.IMessageFilter
    {
    私有静态DropDownMenuScrollWheelHandler实例;
    公共静态无效启用(bool启用)
    {
    如果(已启用)
    {
    if(实例==null)
    {
    实例=新的DropDownMenuScrollWheelHandler();
    Application.AddMessageFilter(实例);
    }
    }
    其他的
    {
    if(实例!=null)
    {
    Application.RemoveMessageFilter(实例);
    实例=null;
    }
    }
    }
    私有IntPtr-activeHwnd;
    private ToolStripDropDown活动菜单;
    公共bool预过滤器消息(参考消息m)
    {
    如果(m.Msg==0x200&&activeHwnd!=m.HWnd)//WM\u MOUSEMOVE
    {
    activeHwnd=m.HWnd;
    this.activeMenu=Control.FromHandle(m.HWnd)作为ToolStripDropDown;
    }
    如果(m.Msg==0x20A&&this.activeMenu!=null)//WM\u鼠标滚轮
    {
    int delta=(短)(ushort)((uint)(ulong)m.WParam)>>16;
    handleDelta(this.activeMenu,delta);
    返回true;
    }
    返回false;
    }
    私有静态只读操作
    =(操作)委托。CreateDelegate(操作的类型),
    typeof(ToolStrip).GetMethod(“ScrollInternal”,
    System.Reflection.BindingFlags.NonPublic
    |System.Reflection.BindingFlags.Instance));
    专用void handleDelta(ToolStripDropDown ts,int delta)
    {
    如果(ts.Items.Count==0)
    返回;
    var firstItem=ts.Items[0];
    var lastItem=ts.Items[ts.Items.Count-1];
    如果(lastItem.Bounds.Bottom0)
    返回;
    δ=δ/-4;
    if(delta<0&&firstItem.Bounds.Top-delta>9)
    {
    delta=firstItem.Bounds.Top-9;
    }
    else if(delta>0&&delta>lastItem.Bounds.Bottom-ts.Height+9)
    {
    delta=lastItem.Bounds.Bottom-owner.Height+9;
    }
    如果(增量!=0)
    内部(ts,增量);
    }
    }
    
    这非常简单,只需使用上下文菜单的子菜单(
    ToolStripMenuItem
    ):

    假设使用
    form1
    (或
    UserControl
    )和
    contextMenuStrip1

    private void form1_Load( object sender , EventArgs e )
    {
        //this.MouseWheel -= When_MouseWheel;
        this.MouseWheel += When_MouseWheel;
    }
    void When_MouseWheel( object sender , MouseEventArgs e )
    {
        if ( this.contextMenuStrip1.IsDropDown ) {
             //this.Focus();
             if ( e.Delta > 0 ) SendKeys.SendWait( "{UP}" );
             else SendKeys.SendWait( "{DOWN}" );         
        }
    }
    

    我修改了Mohsen Afshin的答案,点击向上/向下箭头,而不是向上/向下按键。我的应用程序有一个名为
    菜单的
    ContextMenuStrip
    。这是密码

    在初始化中:

        menu.VisibleChanged += (s, e) =>
        {
            if (menu.Visible)
            {
                MouseWheel += ScrollMenu;
                menu.MouseWheel += ScrollMenu;
            }
            else
            {
                MouseWheel -= ScrollMenu;
                menu.MouseWheel -= ScrollMenu;
            }
        };
    
    滚动菜单功能:

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
    
    private void ScrollMenu(object sender, MouseEventArgs e)
    {
        Point origin = Cursor.Position;
        int clicks;
    
        if (e.Delta < 0)
        {
            Cursor.Position = menu.PointToScreen(new Point(menu.DisplayRectangle.Left + 5, menu.DisplayRectangle.Bottom + 5));
            clicks = e.Delta / -40;
        }
        else
        {
            Cursor.Position = menu.PointToScreen(new Point(menu.DisplayRectangle.Left + 5, menu.DisplayRectangle.Top - 5));
            clicks = e.Delta / 40;
        }
    
        for (int i = 0; i < clicks; i++)
            mouse_event(0x0006, 0, 0, 0, 0);//Left mouse button up and down on cursor position
        Cursor.Position = origin;
    }
    
    [System.Runtime.InteropServices.DllImport(“user32.dll”)]
    私有静态外部无效鼠标事件(uint-dwFlags、uint-dx、uint-dy、uint-cButtons、uint-dwExtraInfo);
    私有无效滚动菜单(对象发送器,鼠标指针)
    {
    点原点=光标位置;
    int点击;
    如果(e.Delta<0)
    {
    Cursor.Position=menu.PointToScreen(新点(menu.DisplayRectangle.Left+5,menu.DisplayRectangle.Bottom+5));
    点击次数=e.Delta/-40;
    }
    其他的
    {
    Cursor.Position=menu.PointToScreen(新点(menu.DisplayRectangle.Left+5,menu.DisplayRectangle.Top-5));
    点击次数=e.增量/40;
    }
    对于(int i=0;i

    我在让
    mouse\u event
    函数单击特定位置时遇到问题,因此我移动光标,单击,然后将光标移回。它看起来不是最干净的,但它可以工作。

    手动操作是不可能的…………谢谢!是否可以像在Visual Studio 2010中那样,在不模拟上下箭头的情况下滚动视图?您必须实现自己的MenuStrip,否则唯一有效的解决方案是此解决方案此解决方案有效,但由于它在列表中上下移动选择,而不是滚动选择本身,因此相当笨拙。如果发生这种情况时鼠标移动到列表上方,则选择会跳回鼠标下方,这会让用户感到非常混乱和迷失方向。还请注意,您可以使用SendKeys使最后一个事件处理程序更加整洁:
    SendKeys.Send((e.Delta>0)“{UP}”:“{DOWN}”)
    。当单击向上或向下按钮时,鼠标滚轮事件似乎停止触发。应该是
    ts.Height
    而不是
    owner.Height
    ?此外,还可以侦听
    鼠标滚轮
    事件,而不是使用
    AddMessageFilter
    。除此之外,好东西!你会参加谁的鼠标轮活动?AddMessageFilter允许您处理应用程序中所有菜单的所有鼠标滚轮滚动,而无需担心将事件连接到每个菜单。我有一个扩展方法,可以增加滚动按钮的大小,因此它是附加鼠标滚轮事件的自然位置。起初,
    AddMessageFilter
    似乎没有必要,但转念一想,这是一个很好的解决方案。除了上面提到的讨厌之外,我还不得不将“msg==0x20A”改为“m.msg…”和“int delta…”行=