I have been messing around with borderless forms for a few hours and I have been able to get all the functionality that I need from it. The only thing that has been bothering me is when resizing from the top, top-left, or left the form will flicker on the opposite side. The components will as well but I figured out how to deal with that problem. Right now I'm focused on trying to get the flickering to stop while keeping the borderless form completely borderless. I know that the issue stems from the form drawing the moved distance and then redrawing the size (or vice versa) but I cannot get it to stop.
I have tried several different methods of resizing the form from using the PInvoke WndProc method, to just setting the location and size of the form, to trying to lock the form while I am changing the location and size. Nothing seems to get rid of that flickering unless I am using a sizable form. I can hide most of the sizable form but there is still a few pixels of the title bar left. Every method that I have found while searching has yielded the same results.
Here is what I am currently using to inherit from on my Main form:
using System.Drawing;
using System.Windows.Forms;
namespace TestBorderlessModernGUI
{
/// <summary>
/// Inherit from EdgeDrag in the main form
/// </summary>
public class EdgeDrag : Form
{
protected bool isDragging = false;
protected bool canDrag = false;
protected Rectangle lastRectangle = new Rectangle();
public EdgeDrag()
{
}
/// <summary>
/// Call after component Initialization in the Main Form
/// </summary>
protected void InitialiseFormEdge()
{
int resizeWidth = 2;
this.MouseDown = new MouseEventHandler(form_MouseDown);
this.MouseMove = new MouseEventHandler(form_MouseMove);
this.MouseUp = new MouseEventHandler(form_MouseUp);
// bottom
UserControl uc1 = new UserControl()
{
Anchor = (AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right),
Height = resizeWidth,
Width = this.DisplayRectangle.Width - (resizeWidth * 2),
Left = resizeWidth,
Top = this.DisplayRectangle.Height - resizeWidth,
BackColor = Color.Transparent,
Cursor = Cursors.SizeNS
};
uc1.MouseDown = form_MouseDown;
uc1.MouseUp = form_MouseUp;
uc1.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
this.Size = new Size(lastRectangle.Width, e.Y - lastRectangle.Y this.Height);
}
};
uc1.BringToFront();
this.Controls.Add(uc1);
this.Controls.SetChildIndex(uc1, 0);
// right
UserControl uc2 = new UserControl()
{
Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom),
Height = this.DisplayRectangle.Height - (resizeWidth * 2),
Width = resizeWidth,
Left = this.DisplayRectangle.Width - resizeWidth,
Top = resizeWidth,
BackColor = Color.Transparent,
Cursor = Cursors.SizeWE
};
uc2.MouseDown = form_MouseDown;
uc2.MouseUp = form_MouseUp;
uc2.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
this.Size = new Size(e.X - lastRectangle.X this.Width, lastRectangle.Height);
}
};
uc2.BringToFront();
this.Controls.Add(uc2);
this.Controls.SetChildIndex(uc2, 0);
// bottom-right
UserControl uc3 = new UserControl()
{
Anchor = (AnchorStyles.Bottom | AnchorStyles.Right),
Height = resizeWidth,
Width = resizeWidth,
Left = this.DisplayRectangle.Width - resizeWidth,
Top = this.DisplayRectangle.Height - resizeWidth,
BackColor = Color.Transparent,
Cursor = Cursors.SizeNWSE
};
uc3.MouseDown = form_MouseDown;
uc3.MouseUp = form_MouseUp;
uc3.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
this.Size = new Size((e.X - lastRectangle.X this.Width), (e.Y - lastRectangle.Y this.Height));
}
};
uc3.BringToFront();
this.Controls.Add(uc3);
this.Controls.SetChildIndex(uc3, 0);
// top-right
UserControl uc4 = new UserControl()
{
Anchor = (AnchorStyles.Top | AnchorStyles.Right),
Height = resizeWidth,
Width = resizeWidth,
Left = this.DisplayRectangle.Width - resizeWidth,
Top = 0,
BackColor = Color.Transparent,
Cursor = Cursors.SizeNESW
};
uc4.MouseDown = form_MouseDown;
uc4.MouseUp = form_MouseUp;
uc4.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
int diff = (e.Location.Y - lastRectangle.Y);
int y = (this.Location.Y diff);
this.Location = new Point(this.Location.X, y);
this.Size = new Size(e.X - lastRectangle.X this.Width, (this.Height (diff * -1)));
}
};
uc4.BringToFront();
//uc4.BackColor = Color.Firebrick;
this.Controls.Add(uc4);
this.Controls.SetChildIndex(uc4, 0);
// top
UserControl uc5 = new UserControl()
{
Anchor = (AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right),
Height = resizeWidth,
Width = this.DisplayRectangle.Width - (resizeWidth * 2),
Left = resizeWidth,
Top = 0,
BackColor = Color.Transparent,
Cursor = Cursors.SizeNS
};
uc5.MouseDown = form_MouseDown;
uc5.MouseUp = form_MouseUp;
uc5.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
int diff = (e.Location.Y - lastRectangle.Y);
int y = (this.Location.Y diff);
this.Location = new Point(this.Location.X, y);
this.Size = new Size(lastRectangle.Width, (this.Height (diff * -1)));
}
};
uc5.BringToFront();
this.Controls.Add(uc5);
this.Controls.SetChildIndex(uc5, 0);
// left
UserControl uc6 = new UserControl()
{
Anchor = (AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Bottom),
Height = this.DisplayRectangle.Height - (resizeWidth * 2),
Width = resizeWidth,
Left = 0,
Top = resizeWidth,
BackColor = Color.Transparent,
Cursor = Cursors.SizeWE
};
uc6.MouseDown = form_MouseDown;
uc6.MouseUp = form_MouseUp;
uc6.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
int diff = (e.Location.X - lastRectangle.X);
int x = (this.Location.X diff);
this.Location = new Point(x, this.Location.Y);
this.Size = new Size((this.Width (diff * -1)), this.Height);
}
};
uc6.BringToFront();
this.Controls.Add(uc6);
this.Controls.SetChildIndex(uc6, 0);
// bottom-left
UserControl uc7 = new UserControl()
{
Anchor = (AnchorStyles.Bottom | AnchorStyles.Left),
Height = resizeWidth,
Width = resizeWidth,
Left = 0,
Top = this.DisplayRectangle.Height - resizeWidth,
BackColor = Color.Transparent,
Cursor = Cursors.SizeNESW
};
uc7.MouseDown = form_MouseDown;
uc7.MouseUp = form_MouseUp;
uc7.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
int diff = (e.Location.X - lastRectangle.X);
int x = (this.Location.X diff);
this.Location = new Point(x, this.Location.Y);
this.Size = new Size((this.Width (diff * -1)), (e.Y - lastRectangle.Y this.Height));
}
};
uc7.BringToFront();
this.Controls.Add(uc7);
this.Controls.SetChildIndex(uc7, 0);
// bottom-left
UserControl uc8 = new UserControl()
{
Anchor = (AnchorStyles.Top | AnchorStyles.Left),
Height = resizeWidth,
Width = resizeWidth,
Left = 0,
Top = 0,
BackColor = Color.Transparent,
Cursor = Cursors.SizeNWSE
};
uc8.MouseDown = form_MouseDown;
uc8.MouseUp = form_MouseUp;
uc8.MouseMove = delegate (object sender, MouseEventArgs e)
{
if (isDragging)
{
int dX = (e.Location.X - lastRectangle.X);
int dY = (e.Location.Y - lastRectangle.Y);
int x = (this.Location.X dX);
int y = (this.Location.Y dY);
this.Location = new Point(x, y);
this.Size = new Size((this.Width (dX * -1)), (this.Height (dY * -1)));
}
};
uc8.BringToFront();
this.Controls.Add(uc8);
this.Controls.SetChildIndex(uc8, 0);
}
private void form_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDragging = true;
lastRectangle = new Rectangle(e.Location.X, e.Location.Y, this.Width, this.Height);
// If the mouse is within the dragging area
if (e.Y <= 30 && e.X <= this.Size.Width - 120)
canDrag = true;
}
}
private void form_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
// If we can drag the form
if (canDrag)
{
int x = (this.Location.X (e.Location.X - lastRectangle.X));
int y = (this.Location.Y (e.Location.Y - lastRectangle.Y));
this.Location = new Point(x, y);
}
}
}
private void form_MouseUp(object sender, MouseEventArgs e)
{
if (isDragging)
isDragging = false;
if (canDrag)
canDrag = false;
}
}
}
Does anybody know of a way to get rid of the flickering in the borderless form edges so it resembles the sizable form?
Edit: I've modified the code to use WndProc for resizing like Jimi stated and it still flickers in the same manner as the other code. I'm beginning to think the only way to stop the flickering is to use a sizable form. Does anybody have any ideas?
Form Constructor:
public MainForm()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
Edge Resize Code:
private const int HTLEFT = 10,
HTRIGHT = 11,
HTTOP = 12,
HTTOPLEFT = 13,
HTTOPRIGHT = 14,
HTBOTTOM = 15,
HTBOTTOMLEFT = 16,
HTBOTTOMRIGHT = 17,
HTCAPTION = 2;
const int edgeSize = 3; // you can rename this variable if you like
Rectangle Top { get { return new Rectangle(0, 0, this.ClientSize.Width, edgeSize); } }
Rectangle Left { get { return new Rectangle(0, 0, edgeSize, this.ClientSize.Height); } }
Rectangle Bottom { get { return new Rectangle(0, this.ClientSize.Height - edgeSize, this.ClientSize.Width, edgeSize); } }
Rectangle Right { get { return new Rectangle(this.ClientSize.Width - edgeSize, 0, edgeSize, this.ClientSize.Height); } }
Rectangle TopLeft { get { return new Rectangle(0, 0, edgeSize, edgeSize); } }
Rectangle TopRight { get { return new Rectangle(this.ClientSize.Width - edgeSize, 0, edgeSize, edgeSize); } }
Rectangle BottomLeft { get { return new Rectangle(0, this.ClientSize.Height - edgeSize, edgeSize, edgeSize); } }
Rectangle BottomRight { get { return new Rectangle(this.ClientSize.Width - edgeSize, this.ClientSize.Height - edgeSize, edgeSize, edgeSize); } }
protected override CreateParams CreateParams { get { var cp = base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } }
protected override void OnPaint(PaintEventArgs e)
{
if (this.WindowState == FormWindowState.Normal)
{
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x84)
{ // Trap WM_NCHITTEST
var cursor = this.PointToClient(Cursor.Position);
if (TopLeft.Contains(cursor)) m.Result = (IntPtr)HTTOPLEFT;
else if (TopRight.Contains(cursor)) m.Result = (IntPtr)HTTOPRIGHT;
else if (BottomLeft.Contains(cursor)) m.Result = (IntPtr)HTBOTTOMLEFT;
else if (BottomRight.Contains(cursor)) m.Result = (IntPtr)HTBOTTOMRIGHT;
else if (Top.Contains(cursor)) m.Result = (IntPtr)HTTOP;
else if (Left.Contains(cursor)) m.Result = (IntPtr)HTLEFT;
else if (Right.Contains(cursor)) m.Result = (IntPtr)HTRIGHT;
else if (Bottom.Contains(cursor)) m.Result = (IntPtr)HTBOTTOM;
else if (cursor.Y < cCaption) m.Result = (IntPtr)HTCAPTION;
}
}
CodePudding user response:
Duh, I feel stupid.
I was able to get the flickering to stop in the following way...
I switched over to WndProc for resizing and dragging as in my edit above
I am using FixedSingle instead of None for the form border style. Technically, It's not a borderless window but when setting the Text to empty and ControlBox to false, it has the behavior I'm looking for.
Apart from the modified code above, this is what my constructor looks like now:
public MainForm()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.Text = string.Empty;
this.ControlBox = false;
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
As you can see in this image, the window behaves just like the sizable window with no jumping or flickering on the opposite edge.
Edit:
Another issue I ran into was giving the window a name in the Taskbar and Task Manager. I was able to do that with a modified CreateParams getter. The modified parts are both cp.Style values and the cp.Caption. the cp.Style &= ~0xC00000
line hides the titlebar, cp.Style |= 0x00800000
shows a thin line border that is necessary to prevent flickering when using this method, cp.Caption = "TEST"
then sets the title in the taskbar and task manager.
protected override CreateParams CreateParams
{
get
{
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
// Extend the CreateParams property of the Button class.
var cp = base.CreateParams;
// Update the button Style.
cp.Style &= ~0xC00000; //WS_CAPTION;
cp.Style |= 0x00800000;
cp.ExStyle |= 0x02000000;
cp.Caption = "TEST";
return cp;
}
}