I have a borderless winForm which I needed to resize, and I managed to do it this way:
protected override void WndProc(ref Message m)
{
const int wmNcHitTest = 0x84;
const int htLeft = 10;
const int htRight = 11;
const int htTop = 12;
const int htTopLeft = 13;
const int htTopRight = 14;
const int htBottom = 15;
const int htBottomLeft = 16;
const int htBottomRight = 17;
if (m.Msg == wmNcHitTest)
{
Console.Write(true + "\n");
int x = (int)(m.LParam.ToInt64() & 0xFFFF);
int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);
Point pt = PointToClient(new Point(x, y));
Size clientSize = ClientSize;
///allow resize on the lower right corner
if (pt.X >= clientSize.Width - 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(IsMirrored ? htBottomLeft : htBottomRight);
return;
}
///allow resize on the lower left corner
if (pt.X <= 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(IsMirrored ? htBottomRight : htBottomLeft);
return;
}
///allow resize on the upper right corner
if (pt.X <= 16 && pt.Y <= 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(IsMirrored ? htTopRight : htTopLeft);
return;
}
///allow resize on the upper left corner
if (pt.X >= clientSize.Width - 16 && pt.Y <= 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(IsMirrored ? htTopLeft : htTopRight);
return;
}
///allow resize on the top border
if (pt.Y <= 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(htTop);
return;
}
///allow resize on the bottom border
if (pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(htBottom);
return;
}
///allow resize on the left border
if (pt.X <= 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(htLeft);
return;
}
///allow resize on the right border
if (pt.X >= clientSize.Width - 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(htRight);
return;
}
}
else
{
Console.Write(false + "\n");
}
base.WndProc(ref m);
}
The problem is that there are controls on the left and right borders of my form, so the resize override used on the code above doesn't work on those areas in which there are controls of any kind.
Here is an example:
On the image above you can see that the label inside the marked area is on the left border of my form and it won't let me resize it.
Is there a way to solve this issue?
The problem here is that it is the Label control that gets the mouse notifications, not your borderless form. By far the best way to solve this problem is making the label transparent to the mouse. You already know how to do that, WM_NCHITTEST also permits returning HTTRANSPARENT. Windows keeps looking for the next candidate for the notification, it will be the label's Parent.
Especially easy to do for a label since you don't normally have any use for its mouse events at all:
using System;
using System.Windows.Forms;
public class LabelEx : Label {
protected override void WndProc(ref Message m) {
const int wmNcHitTest = 0x84;
const int htTransparent = -1;
if (!DesignMode && m.Msg == wmNcHitTest) m.Result = new IntPtr(htTransparent);
else base.WndProc(ref m);
}
}
Works for any Control class, you'd want to be more selective if it were a button. Might be all you need, still pretty awkward however if you have a lot of different kind of controls close to the edge. Another technique you can use is called "sub-classing" in native Windows programming. Universally used in Winforms to create wrapper .NET classes for native Windows controls. It works well here too, you can have a peek at the messages of any control and intercept WM_NCHITTEST that way:
const int edge = 16;
class MouseFilter : NativeWindow {
private Form form;
public MouseFilter(Form form, Control child) {
this.form = form;
this.AssignHandle(child.Handle);
}
protected override void WndProc(ref Message m) {
const int wmNcHitTest = 0x84;
const int htTransparent = -1;
if (m.Msg == wmNcHitTest) {
var pos = new Point(m.LParam.ToInt32());
if (pos.X < this.form.Left + edge ||
pos.Y < this.form.Top + edge||
pos.X > this.form.Right - edge ||
pos.Y > this.form.Bottom - edge) {
m.Result = new IntPtr(htTransparent);
return;
}
}
base.WndProc(ref m);
}
}
And just create a MouseFilter instance for every control that gets close to the window edge:
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
subClassChildren(this.Controls);
}
private void subClassChildren(Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
var rc = this.RectangleToClient(this.RectangleToScreen(ctl.DisplayRectangle));
if (rc.Left < edge || rc.Right > this.ClientSize.Width - edge ||
rc.Top < edge || rc.Bottom > this.ClientSize.Height - edge) {
new MouseFilter(this, ctl);
}
subClassChildren(ctl.Controls);
}
}
User contributions licensed under CC BY-SA 3.0