MouseWheel

Has anyone have a problem catching the MouseWheel? Have a custom control and it captures the mouse down, mouse up, and mouse move. But for some darn reason it's not catching my MouseWheel. Like the other mouse events I'm attaching to the event:

this.MouseWheel += OnMouseWheel;

Any advice greatly appreciated.
[337 byte] By [webejamming] at [2007-11-20 10:31:46]
# 1 Re: MouseWheel
I'm surprised you can compile the code you listed because this.MouseWheel has the MouseEventHandler(object sender, MouseEventArgs e) delegate while the OnMouseWheel(MouseEventArgs e) delegate has a different signature. I'm getting a compiler error doing the same thing. However, if you suppy your own callback pointer, as in the code below, everything works fine:
private void UserControl1_Load(object sender, EventArgs e)
{
this.MouseWheel += new MouseEventHandler(UserControl1_MouseWheel);
}
void UserControl1_MouseWheel(object sender, MouseEventArgs e)
{
MessageBox.Show("haha");
}
By the way I'm on 2.0 framework
trenches at 2007-11-9 11:35:31 >
# 2 Re: MouseWheel
Thanks Trenches, but I've tried it already. Funny thing is, as a test, I added a listview to my control and added the code below.

listView1.MouseWheel += new MouseEventHandler(OnMouseWheel);

This was able to catch the event. I was wondering if a usercontrol just doesn't inherently capable of capturing mousewheel event. I turned on the control's AutoScroll property to True and schrunk the window so that I'll have a scroll bar. When I roll my mouse wheel the scroll doesn't move. You think this might have something to do with it?
webejamming at 2007-11-9 11:36:31 >
# 3 Re: MouseWheel
OnMouseWheel is a method on the base control class. it is the method that fires the mouse wheel event.

here's a little info that doesnt really have anything to do with what you're doing, but may be helpful in the future.

most window events (like mouse wheel) are bound to standard win32 notifications. when the window gets a mouse wheel notification, .net bundles up the info from the message into an event args object, then invokes a method to fire the event. that method that fires the event is typically a protected virtual method with the naming convention of OnEventName and has a single parameter which is the event args parameter.

on the other side (subscribing side of your event) you typically do not use OnEventName methods to handle the event. the event dispatching method has only a single event args parameter (unlike the event itself which has a sender object and the event args) to keep someone from inadvertently creating a stack overflow by assigning an event to its event dispatching method ( as you would have been doing by assigning control.WheelMouse += OnWheelMouse; ).

the wheel mouse event is dispatched from the base control object and is implemented in every subsequent control (unless they specifically override that functionality) class such as user control.

the reason you may not have been getting it is that the control needs to be in focus (and capable of being selected) before it can be captured.

there is a way to globally capture the wheel mouse info and subscribe to it in your user control through the use of a global message filter (basically re-implementing what System.Windows.Forms.Control already does).

create a message filter object (singleton so everyone can subscribe to the wheelmouse event):

public class GlobalWheelMouseFilter : IMessageFilter {
static Mutex mutex = new Mutex(true, "GWM");
static GlobalWheelMouseFilter instance;
public static GlobalWheelMouseFilter Instance {
get {
mutex.WaitOne();
if(instance == null) {
instance = new GlobalWheelMouseFilter();
}
mutex.ReleaseMutex();
return instance;
}
}
const int WM_MOUSEWHEEL = 0x20a;
public event MouseEventHandler MouseWheel;

protected virtual void OnMouseWheel(MouseEventArgs e) {
if(MouseWheel != null) MouseWheel(this, e);
}

bool WmMouseWheel(ref Message m) {
Point p = new Point(LowWord(m.LParam), HighWord(m.LParam));
HandledMouseEventArgs e = new HandledMouseEventArgs(MouseButtons.None, 0, p.X, p.Y, HighWord(m.WParam));
this.OnMouseWheel(e);
m.Result = e.Handled ? IntPtr.Zero : ((IntPtr)1);
if(!e.Handled) {
return false;
}
return true;
}

public bool PreFilterMessage(ref Message m) {
if(m.Msg == WM_MOUSEWHEEL) {
return WmMouseWheel(ref m);
}
return false;
}

int LowWord(IntPtr lowword) {
return (short)((int)((long)lowword) & 0xffff);
}
int HighWord(IntPtr highword) {
return (short)(((int)((long)highword) >> 0x10) & 0xffff);

}
}

then in your Main:

[STAThread]
static void Main() {
Application.AddMessageFilter(GlobalWheelMouseFilter.Instance);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Application.RemoveMessageFilter(GlobalWheelMouseFilter.Instance);
}

and where you want to subscribe to the wheel mouse event:
GlobalWheelMouseFilter.Instance.MouseWheel += new MouseEventHandler(Instance_MouseWheel);
// ...

void Instance_MouseWheel(object sender, MouseEventArgs e) {
label3.Text = string.Format("{0}, x={1} y={2}", e.Delta, e.X, e.Y);
}
MadHatter at 2007-11-9 11:37:30 >
# 4 Re: MouseWheel
Awesome MadHatter, this is exactly what I needed. I went to the properties of my control and realized that all the other Mouse events were available but not MouseWheel. That maybe one of the reason it wasn't firing. The global filter will definately work. Thanks again.
webejamming at 2007-11-9 11:38:36 >
# 5 Re: MouseWheel
one thing to note is that the mouse location will be global coordinates (relative to the screen). if you want to know where the pointer is relative to your control, then you'll need to convert the global point (e.Location) to one on whatever control you're using by using the control's PointToClient method.
MadHatter at 2007-11-9 11:39:35 >