[C# .NET 4.0]
I'm learning C# and I'm trying to build a Windows Form using C# that has FormBorderStyle = FormBorderStyle.None
and can be moved/resized using the Windows API. As an example, I'm using the rounded corner or custom (moveable/resizable) border designs used for Google Chrome and Norton 360 as the basis for my form.
I've made a lot of progress so far and gotten everything to work, except that when I resize the form, there is a black/white flicker along the length of the right and bottom borders when you resize the form quickly.
I've tried adding this.DoubleBuffer = true
in the constructor and have also tried this.SetStyles(ControlStyles.AllPaintInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
.
Because I'm a sucker for the graphics side of things, I like having control over the full design of the form, so I can see this being something that would forever bother me...so if someone can help me resolve this so the flicker doesn't occur anymore, it would be incredibly useful toward my learning process.
I should also mention that I'm using Windows XP, so I'm not sure that this post will help me since it seems to be focused on Vista/7 (with DWM)...not that I'm advanced enough yet to understand everything in that post.
The two portions of the code that work with the API are below. I have a public enumeration for the WM_NCHITTEST for the Windows API...you can see the values in this link.
OnPaint Override Method:
protected override void OnPaint(PaintEventArgs e)
{
System.IntPtr ptrBorder = CreateRoundRectRgn(0, 0,
this.ClientSize.Width, this.ClientSize.Height, 15, 15);
SetWindowRgn(this.Handle, ptrBorder, true);
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip,
this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, 32);
e.Graphics.FillRectangle(Brushes.SlateGray, rc);
}
WndProc Override Method:
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)HitTest.WM_NCHITTEST)
{
// Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.Y < cCaption)
{
m.Result = (IntPtr)HitTest.HTCAPTION;
return;
}
if (pos.X <= cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMLEFT;
return;
}
if (pos.X >= this.ClientSize.Width - cGrip &&
pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMRIGHT;
return;
}
if (pos.X >= this.ClientSize.Width - cBorder)
{
m.Result = (IntPtr)HitTest.HTRIGHT;
return;
}
if (pos.Y >= this.ClientSize.Height - cBorder)
{
m.Result = (IntPtr)HitTest.HTBOTTOM;
return;
}
if (pos.X <= cBorder)
{
m.Result = (IntPtr)HitTest.HTLEFT;
return;
}
}
base.WndProc(ref m);
}
And here's the full code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace PracticeForm
{
public partial class Form2 : Form
{
[DllImport("user32.dll")]
private static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateRoundRectRgn(int x1, int y1, int x2, int y2, int cx, int cy);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
private static extern bool DeleteObject(System.IntPtr hObject);
private const int cGrip = 20;
private const int cCaption = 35;
private const int cBorder = 7;
private Point mouseOffset;
public Form2()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.MaximumSize = new Size(670, 440);
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
System.IntPtr ptrBorder = CreateRoundRectRgn(0, 0,
this.ClientSize.Width, this.ClientSize.Height, 15, 15);
SetWindowRgn(this.Handle, ptrBorder, true);
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)
{
if (m.Msg == (int)HitTest.WM_NCHITTEST)
{
// Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.Y < cCaption)
{
m.Result = (IntPtr)HitTest.HTCAPTION;
return;
}
if (pos.X <= cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMLEFT;
return;
}
if (pos.X >= this.ClientSize.Width - cGrip &&
pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMRIGHT;
return;
}
if (pos.X >= this.ClientSize.Width - cBorder)
{
m.Result = (IntPtr)HitTest.HTRIGHT;
return;
}
if (pos.Y >= this.ClientSize.Height - cBorder)
{
m.Result = (IntPtr)HitTest.HTBOTTOM;
return;
}
if (pos.X <= cBorder)
{
m.Result = (IntPtr)HitTest.HTLEFT;
return;
}
}
base.WndProc(ref m);
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private void button2_MouseClick(object sender, MouseEventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mouseOffset = new Point(-e.X, -e.Y);
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point p = Control.MousePosition;
p.Offset(mouseOffset.X, mouseOffset.Y);
Location = p;
}
}
private void label1_MouseDown(object sender, MouseEventArgs e)
{
mouseOffset = new Point(-e.X, -e.Y);
}
private void label1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point p = Control.MousePosition;
p.Offset(mouseOffset.X, mouseOffset.Y);
Location = p;
}
}
}
}
Thanks for the help.