Subclassing panel == no mousewheel?

G

Glenn Nilsson

Hi,

I've subclassed a Panel and trying to catch the MouseWheel event, non
successful I tried to override OnMouseWheel, but none of the above will
trigger the event.

The code is this:

namespace Wailqill.Windows.Forms
{
public class FlowPanel : System.Windows.Forms.Panel
{
public FlowPanel()
{
this.MouseWheel += new MouseEventHandler(FlowPanel_MouseWheel);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
MessageBox.Show("ugh1!");
base.OnMouseWheel(e);
}
private void FlowPanel_MouseWheel(object sender, MouseEventArgs e)
{
MessageBox.Show("ugh2!");
}
}
}

None of the messageboxes will show. After this I tried the code directly
on an inherited form, and that works just great.

What have I missed?

/Glenn
 
R

Rhett Gong

Hi Glenn,
I have tried your code and added a textbox in it. If I click the panel
(except the textbox), and then I rotate mousewheel, the Messagebox was not
shown. However, if I click the textbox which is in the panel, and then
rotate mousewheel, the messagebox is shown "ugh2". After the 2nd step, no
matter wherever I click in the panel and rotate mousewheel, the messagebox
is shown as expected.
"The WM_MOUSEWHEEL message is sent to the focus window when the mouse
wheel is rotated." But the panel can't receive focus nor be selectable. So
you can't catch the MouseWheel event in your subclassed panel. When you put
your code in an inherited form and the form can be selected to get focus, I
think that is why you can catch MouseWheel there.


Rhett Gong [MS]
Microsoft Online Partner Support

This posting is provided "AS IS" with no warranties, and confers no rights.
Please reply to newsgroups only. Thanks.
 
H

Herfried K. Wagner [MVP]

* Glenn Nilsson said:
I've subclassed a Panel and trying to catch the MouseWheel event, non
successful I tried to override OnMouseWheel, but none of the above
will trigger the event.

This behavior is "by design". The control will only scroll if it or one
of its child controls have the focus. You will have to click on a
control contained in the panel before being able to use the wheel.
 
G

Glenn Nilsson

Thanks for notifying me about this. Both of you.

Knowing this arises a second problem, the thing is that I inherit Panel,
instead of UserControl, just for the lazyness for not having to add and
draw the BorderStyle. But the rest of the content is manually drawn. So,
there are no other controls in my control, and there won't be any either.

My first thought is to solve it by the means of manually setting the
focus with Control.Focus() on the MouseEnter-event, is this bad? Are
there any other methods for achieving this? Or shoud I simply inherit
from another base class to get the functionality need?

at 2003-12-02 09:01, Rhett Gong mumbled something like:
 
J

Jason Dorie

Subclass from UserControl, then add the attached code. It uses interop to
affect the style if it changes after window creation (IE @ design time). If
you don't care about being able to change it, just leave it in the
CreateParams block and toss the other stuff away.

Jason Dorie


private const int WS_BORDER = 0x00800000;
private const int WS_EX_CLIENTEDGE = 0x00000200;

private void BorderStyleToWindowStyle(ref int style, ref int exStyle)
{
style &= ~WS_BORDER;
exStyle &= ~WS_EX_CLIENTEDGE;

switch(borderStyle)
{
case BorderStyle.Fixed3D:
exStyle |= WS_EX_CLIENTEDGE;
break;

case BorderStyle.FixedSingle:
style |= WS_BORDER;
break;

case BorderStyle.None:
break;
}
}


protected override CreateParams CreateParams
{
get {
CreateParams p = base.CreateParams;
int style = p.Style;
int exStyle = p.ExStyle;
BorderStyleToWindowStyle(ref style, ref exStyle);
p.Style = style;
p.ExStyle = exStyle;
return p;
}
}

/// <summary>
/// Gets or sets the border style of the tree view control.
/// </summary>
[Category("Appearance")]
[DescriptionAttribute("Border style of the control")]
[DefaultValue(typeof(System.Windows.Forms.BorderStyle), "Fixed3D")]
public BorderStyle BorderStyle
{
get {return borderStyle;}
set
{
borderStyle = value;

// Get Styles
int style = GetWindowLong(Handle, GWL_STYLE);
int exStyle = GetWindowLong(Handle, GWL_EXSTYLE);

// Modify Styles
BorderStyleToWindowStyle(ref style, ref exStyle);

// Set Styles
SetWindowLong(Handle, GWL_STYLE, style);
SetWindowLong(Handle, GWL_EXSTYLE, exStyle);

// Update window property cache
SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}

const int GWL_STYLE = -16;
const int GWL_EXSTYLE = -20;

[DllImport("User32", CharSet=CharSet.Auto)]
private static extern int GetWindowLong(IntPtr hWnd, int Index);

[DllImport("User32", CharSet=CharSet.Auto)]
private static extern int SetWindowLong(IntPtr hWnd, int Index, int Value);


const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOMOVE = 0x0002;
const uint SWP_NOZORDER = 0x0004;
const uint SWP_NOREDRAW = 0x0008;
const uint SWP_NOACTIVATE = 0x0010;
const uint SWP_FRAMECHANGED = 0x0020;
const uint SWP_SHOWWINDOW = 0x0040;
const uint SWP_HIDEWINDOW = 0x0080;
const uint SWP_NOCOPYBITS = 0x0100;
const uint SWP_NOOWNERZORDER = 0x0200;
const uint SWP_NOSENDCHANGING = 0x0400;

[DllImport("User32", ExactSpelling=true, CharSet=CharSet.Auto)]
private static extern int SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int x, int y, int cx, int cy, uint uFlags);
 
G

Glenn Nilsson

I thank you Jason for this code, it was very welcome :)

But I think you missed my point. My intentions wasn't to inherit the
UserControl instead of Panel and get thr borders; it was to be able to
catch the MouseWheel event.

Anyone who might know how to solve it?
 
R

Rhett Gong

Hi Glenn,
As I said before, the panel can't be focused. You can test
Control.CanFocus Property for that.
The Windows Forms controls in the following list are not selectable and
will return a value of false for the CanSelect property. Controls derived
from these controls are also not selectable.
|Panel
|GroupBox
|PictureBox
|ProgressBar
|Splitter
|Label
|LinkLabel (when there is no link present in the control)
For the workaround, I think you need to write your own control inherited
from other base classes to get the functionality which you need.

Rhett Gong [MS]
Microsoft Online Partner Support

This posting is provided "AS IS" with no warranties, and confers no rights.
Please reply to newsgroups only. Thanks.
 
J

Jason Dorie

I think in your constructor if you call...

SetStyle( ControlStyles.Selectable, true );

....it might work. This is the cue that the system uses to decide whether or
not your control can receieve focus. However, you may be unwise to do this
because it might confuse the existing panel code, since it expects that
style to be disabled.

Jason Dorie
 
G

Glenn Nilsson

That with a little help of a this.Focus() in OnMouseDown did the trick.
Thank you!!

PS. I haven't noticed any side effects as of yet with this solution.

at 2003-12-04 08:32, Jason Dorie mumbled something like:
 
G

Glenn Nilsson

doh, actually, all that was needed was

this.Focus();

in OnMouseDown...

at 2003-12-04 19:24, Glenn Nilsson mumbled something like:
 
J

Jason Dorie

It may be that the base constructor sets the style before you get a chance
to monkey with it. The "Selectable" property probably just does the
OnMouseDown focus thing anyway. :)

Jason
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top