2012-06-14 34 views
9

Trong ứng dụng Windows C# 3.5 của tôi, tôi có một vài SplitContainers. Có một điều khiển danh sách bên trong mỗi (dock điền). Khi tiêu điểm nằm trên một trong các điều khiển này và tôi di chuyển con lăn chuột, danh sách hiện đang được lấy nét sẽ được cuộn.Sự kiện bánh xe chuột để hoạt động với điều khiển lơ lửng

Nhiệm vụ của tôi là cuộn danh sách, hiện đang được di chuột bằng chuột, không phải là danh sách được chọn. Có thể trong Windows Forms không? Nếu không, là nó có thể với PInvoke?

+0

Dường như họ đã thực hiện "cuộn bất kỳ con trỏ chuột nào qua" hành vi chuẩn trong Windows 10. Thật khó chịu trong hầu hết các trường hợp. – Nyerguds

Trả lời

9

Có vẻ như bạn có thể sử dụng IMessageFilter và PInvoke để xử lý việc này. Một ví dụ trong VB có thể được tìm thấy tại Redirect Mouse Wheel Events to Unfocused Windows Forms Controls. Bạn sẽ có thể dễ dàng chuyển đổi thành C#.

Địa điểm yêu thích

lớp này sử dụng những kỹ thuật sau đây cho nhiệm vụ nhất định:

  • Nghe của kiểm soát MouseEnter và MouseLeave sự kiện để xác định khi nào con trỏ chuột là trong vòng kiểm soát.
  • Triển khai IMessageFilter để nhận WM_MOUSEWHEEL thư trong ứng dụng.
  • PInvoke lệnh gọi API Windows SendMessage chuyển hướng tin nhắn WM_MOUSEWHEEL tới tay cầm của điều khiển.
  • Đối tượng IMessageFilter được triển khai như là một singleton của lớp MouseWheelRedirector và được truy cập bởi các thành viên được chia sẻ Attach, Detach và Active.

Sử dụng a VB.NET to C# converter, đây là những gì bạn kết thúc với:

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Data; 
using System.Diagnostics; 

using System.Windows.Forms; 
using System.Runtime.InteropServices; 

public class MouseWheelRedirector : IMessageFilter 
{ 
    private static MouseWheelRedirector instance = null; 
    private static bool _active = false; 
    public static bool Active 
    { 
     get { return _active; } 
     set 
     { 
      if (_active != value) 
      { 
      _active = value; 
      if (_active) 
      { 
       if (instance == null) 
       { 
        instance = new MouseWheelRedirector(); 
       } 
       Application.AddMessageFilter(instance); 
      } 
      else 
      { 
       if (instance != null) 
       { 
        Application.RemoveMessageFilter(instance); 
       } 
      } 
      } 
     } 
    } 

    public static void Attach(Control control) 
    { 
     if (!_active) 
      Active = true; 
     control.MouseEnter += instance.ControlMouseEnter; 
     control.MouseLeave += instance.ControlMouseLeaveOrDisposed; 
     control.Disposed += instance.ControlMouseLeaveOrDisposed; 
    } 

    public static void Detach(Control control) 
    { 
     if (instance == null) 
      return; 
     control.MouseEnter -= instance.ControlMouseEnter; 
     control.MouseLeave -= instance.ControlMouseLeaveOrDisposed; 
     control.Disposed -= instance.ControlMouseLeaveOrDisposed; 
     if (object.ReferenceEquals(instance.currentControl, control)) 
      instance.currentControl = null; 
    } 

    private MouseWheelRedirector() 
    { 
    } 


    private Control currentControl; 
    private void ControlMouseEnter(object sender, System.EventArgs e) 
    { 
     var control = (Control)sender; 
     if (!control.Focused) 
     { 
      currentControl = control; 
     } 
     else 
     { 
      currentControl = null; 
     } 
    } 

    private void ControlMouseLeaveOrDisposed(object sender, System.EventArgs e) 
    { 
     if (object.ReferenceEquals(currentControl, sender)) 
     { 
      currentControl = null; 
     } 
    } 

    private const int WM_MOUSEWHEEL = 0x20a; 
    public bool PreFilterMessage(ref System.Windows.Forms.Message m) 
    { 
     if (currentControl != null && m.Msg == WM_MOUSEWHEEL) 
     { 
      SendMessage(currentControl.Handle, m.Msg, m.WParam, m.LParam); 
      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 

    [DllImport("user32.dll", SetLastError = false)] 
    private static extern IntPtr SendMessage(
     IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 
} 
+0

Điều này dường như không hoạt động với hầu hết các tấm cảm ứng thông thường bằng các phương pháp như cuộn cạnh phải hoặc cuộn hai ngón tay. Nó xuất hiện trình điều khiển của họ làm một số ma thuật đen để gửi các tin nhắn di chuyển thẳng đến thanh cuộn của điều khiển thay vì gửi 'WM_MOUSEWHEEL' để kiểm soát như họ cần. Bất kỳ ý tưởng về cách để có được xung quanh đó? – Nyerguds

+0

Hmm. Có vẻ như NumericUpDown không muốn nghe điều này. – Nyerguds

3

Sử dụng Control.MouseEnter Event để đặt trọng tâm cho điều khiển. Ví dụ. sử dụng ActiveControl Property

+4

Đôi khi bạn có thể di chuyển một điều khiển ** mà không cần tập trung vào nó, ví dụ nếu nó lấy nét từ một trường văn bản. – Nyerguds

5

Tôi có câu hỏi tương tự và tìm thấy chủ đề này ... nên đăng câu trả lời muộn của tôi cho những người khác có thể tìm thấy chủ đề này. Trong trường hợp của tôi, tôi chỉ muốn các sự kiện bánh xe chuột đi đến bất kỳ điều khiển nào dưới con trỏ ... giống như nhấp chuột phải (nó sẽ gây hoang mang nếu nhấp chuột phải vào điều khiển tiêu điểm thay vì điều khiển bên dưới con trỏ ... Tôi cho rằng điều này cũng đúng với bánh xe chuột, trừ khi chúng ta quen với nó).

Dù sao, câu trả lời rất dễ dàng. Chỉ cần thêm một PreFilterMessage để ứng dụng của bạn và có nó chuyển hướng sự kiện bánh xe chuột để điều khiển dưới chuột:

public bool PreFilterMessage(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_MOUSEWHEEL: // 0x020A 
      case WM_MOUSEHWHEEL: // 0x020E 
       IntPtr hControlUnderMouse = WindowFromPoint(new Point((int)m.LParam)); 
       if (hControlUnderMouse == m.HWnd) 
        return false; // already headed for the right control 
       else 
       { 
        // redirect the message to the control under the mouse 
        SendMessage(hControlUnderMouse, m.Msg, m.WParam, m.LParam); 
        return true; 
       } 
      default: 
       return false; 
      } 
} 
+0

Có một chút thiếu sót từ điều này. Bạn cần phải DllImport WindowFromPoint() và SendMessage: '[DllImport (" user32.dll ")] static extern IntPtr WindowFromPoint (Điểm p); [DllImport (" user32.dll ", CharSet = CharSet.Auto)] tĩnh extern IntPtr SendMessage (IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); ' Ngoài ra, PreFilterMessage() đến từ IMessageFilter, và việc thực hiện đó cần được chuyển đến' ApplicationAddMessageFilter() '. Khi đã xong, tất cả các bảng trong ứng dụng của tôi đều có thể cuộn được dưới chuột. Tuy nhiên, việc nhấp đúp không còn làm nổi bật văn bản. Odd. –

2

Đây là Brian Kennedy 's câu trả lời hoàn thành với Hank Schultz bình luận:

Đầu tiên bạn nên tạo một lớp thực hiện IMessageFilter:

public class MessageFilter : IMessageFilter 
{ 
    private const int WM_MOUSEWHEEL = 0x020A; 
    private const int WM_MOUSEHWHEEL = 0x020E; 

    [DllImport("user32.dll")] 
    static extern IntPtr WindowFromPoint(Point p); 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 

    public bool PreFilterMessage(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_MOUSEWHEEL: 
      case WM_MOUSEHWHEEL: 
       IntPtr hControlUnderMouse = WindowFromPoint(new Point((int)m.LParam)); 
       if (hControlUnderMouse == m.HWnd) 
       { 
        //Do nothing because it's already headed for the right control 
        return false; 
       } 
       else 
       { 
        //Send the scroll message to the control under the mouse 
        uint u = Convert.ToUInt32(m.Msg); 
        SendMessage(hControlUnderMouse, u, m.WParam, m.LParam); 
        return true; 
       } 
      default: 
       return false; 
     } 
    } 
} 

Ví dụ sử dụng:

public partial class MyForm : Form 
{ 
    MessageFilter mf = null; 

    private void MyForm_Load(object sender, EventArgs e) 
    { 
     mf= new MessageFilter(); 
     Application.AddMessageFilter(mf); 
    } 

    private void MyForm_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     Application.RemoveMessageFilter(mf); 
    } 
} 
Các vấn đề liên quan