blah blah blah is here! blah blah » Close

up0down
link

Couldn't find my old thread, so here goes:

this is the code I used to make the panel sizable.

last answered 2 years ago

2 answers

link

I tried this myself with exactly the same results as yourself.

It seems that the panel's Cursor property never changes from the default and consequently the CursorChanged event never fires. Frankly, I don't understand why this is so as it does fire if you change the Cursor property programatically.

I wondered about handling the Resize event instead but then there was no obvious way to determine the direction in which resizing was taking place.

In the end I managed to do what you wanted by handling the WM_SIZING message in the resizable panel class itself though even that was more difficult than I expected as you can't just cancel the message. Anyway, here's the code:

using System.Runtime.InteropServices;

// add this struct

[StructLayout(LayoutKind.Sequential)]
public class RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

// override WndProc in the resizable panel class

private const int WM_SIZING = 0x214;
private const int WMSZ_LEFT = 1;
private const int WMSZ_RIGHT = 2;
private const int WMSZ_TOP = 3;
private const int WMSZ_TOPLEFT = 4;
private const int WMSZ_TOPRIGHT = 5;
private const int WMSZ_BOTTOM = 6;
private const int WMSZ_BOTTOMLEFT = 7;
private const int WMSZ_BOTTOMRIGHT = 8;

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SIZING)
{
int wmsz = m.WParam.ToInt32();
if(wmsz != WMSZ_TOP && wmsz != WMSZ_BOTTOM)
{
RECT rect = new RECT();
Marshal.PtrToStructure(m.LParam, rect);
switch (wmsz)
{
case WMSZ_BOTTOMLEFT :
rect.Left = rect.Right - this.Width;
rect.Bottom = rect.Top + this.Height;
break;
case WMSZ_BOTTOMRIGHT :
rect.Right = rect.Left + this.Width;
rect.Bottom = rect.Top + this.Height;
break;
case WMSZ_LEFT :
rect.Left = rect.Right - this.Width;
break;
case WMSZ_RIGHT :
rect.Right = rect.Left + this.Width;
break;
case WMSZ_TOPLEFT :
rect.Left = rect.Right - this.Width;
rect.Top = rect.Bottom - this.Height;
break;
case WMSZ_TOPRIGHT :
rect.Right = rect.Left + this.Width;
rect.Top = rect.Bottom - this.Height;
break;
}
Marshal.StructureToPtr(rect, m.LParam, true);
}

}

base.WndProc(ref m);
}

foamy
2499

That looks bloody awesome :D I suspect I will change it a little as I will want to enable or disable the behavior through the properties of the class. I will attempt to make properties called UserCanResizeWidth, UserCanResizeTop and UserCanResizeBottom and post back. If you want, I'd like your input on how to do this aswell :) Once again I thank you, vulpes ;) *bow*

vulpes
17279

You'll need a way to record which 'WMSZ' values are allowed. I'd be inclined to define a bool array field with 8 elements whose indices (plus 1) correspond to the 8 WMSZ values. If UserCanResizeWidth is true, then elements 0 and 1 will need to be set to true and so on for the other properties. You can then switch on the WMSZ value within WndProc and, if the corresponding value in the bool array is true, break without doing anything so that resizing will take place normally or, if it's false, change the panel dimensions back so that resizing is effectively disabled.

up1down
link

Well, this is what I have so far. It works, but it's not the way you described (I think):

public bool UserCanResizeWidth
{
get;
set;
}

public bool UserCanResizeTop
{
get;
set;
}

public bool UserCanResizeBottom
{
get;
set;
}

[StructLayout(LayoutKind.Sequential)]
public class RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

private const int WM_SIZING = 0x214;
private const int WMSZ_LEFT = 1;
private const int WMSZ_RIGHT = 2;
private const int WMSZ_TOP = 3;
private const int WMSZ_TOPLEFT = 4;
private const int WMSZ_TOPRIGHT = 5;
private const int WMSZ_BOTTOM = 6;
private const int WMSZ_BOTTOMLEFT = 7;
private const int WMSZ_BOTTOMRIGHT = 8;

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SIZING)
{
int wmsz = m.WParam.ToInt32();
RECT rect = new RECT();
Marshal.PtrToStructure(m.LParam, rect);
switch (wmsz)
{
case WMSZ_BOTTOMLEFT:
if (!UserCanResizeWidth)
rect.Left = rect.Right - this.Width;
if (!UserCanResizeBottom)
rect.Bottom = rect.Top + this.Height;
break;
case WMSZ_BOTTOMRIGHT:
if (!UserCanResizeWidth)
rect.Right = rect.Left + this.Width;
if (!UserCanResizeBottom)
rect.Bottom = rect.Top + this.Height;
break;
case WMSZ_LEFT:
if (!UserCanResizeWidth)
rect.Left = rect.Right - this.Width;
break;
case WMSZ_RIGHT:
if (!UserCanResizeWidth)
rect.Right = rect.Left + this.Width;
break;
case WMSZ_TOPLEFT:
if (!UserCanResizeWidth)
rect.Left = rect.Right - this.Width;
if (!UserCanResizeTop)
rect.Top = rect.Bottom - this.Height;
break;
case WMSZ_TOPRIGHT:
if (!UserCanResizeWidth)
rect.Right = rect.Left + this.Width;
if (!UserCanResizeTop)
rect.Top = rect.Bottom - this.Height;
break;
case WMSZ_BOTTOM:
if (!UserCanResizeBottom)
rect.Bottom = rect.Top + this.Height;
break;
case WMSZ_TOP:
if (!UserCanResizeTop)
rect.Top = rect.Bottom - this.Height;
break;
}
if (this.Height < min_Height)
this.Height = min_Height;
Marshal.StructureToPtr(rect, m.LParam, true);
}
base.WndProc(ref m);
}

vulpes
17279

I think I was making it more complicated than it needed to be so you'd only need to have one 'if' statement in each switch case but the way you've done it looks fine, foamy :)

Feedback