שיחקתי עם זה קצת והוספתי לו תכונות snap פשוטות (לקצוות של הparentform ולקצוות של אחד לשני)
static class MyDictionary
{
public static List<SizeableUserControl> userControlCollection = new List<SizeableUserControl>();
}
class SizeableUserControl : UserControl
{
Form parentForm;
private const int grab = 16;
public SizeableUserControl(Form form)
{
parentForm = form;
MyDictionary.userControlCollection.Add(this);
this.ResizeRedraw = true;
InitializeComponent();
}
private void InitializeComponent()
{
this.SuspendLayout();
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Name = "SizeableUserControl";
this.Size = new System.Drawing.Size(100, 100);
Panel titleBar = new Panel();
titleBar.Dock = DockStyle.Top;
titleBar.BackColor = Color.White;
titleBar.Height = 20;
Controls.Add(titleBar);
titleBar.MouseDown += TitleBar_MouseDown;
titleBar.MouseMove += TitleBar_MouseMove;
titleBar.MouseUp += TitleBar_MouseUp;
// Minimize button
Button minimizeButton = new Button();
minimizeButton.Text = "─";
minimizeButton.TextAlign = ContentAlignment.MiddleCenter;
minimizeButton.Width = 20;
minimizeButton.Height = 20;
minimizeButton.Dock = DockStyle.Right;
minimizeButton.FlatStyle = FlatStyle.Flat;
minimizeButton.FlatAppearance.BorderSize = 0;
titleBar.Controls.Add(minimizeButton);
minimizeButton.Click += (sender, e) =>
{
if (minimizeButton.Text == "─")
{
minimizeButton.Text = "+";
this.Height = 20;
this.Width = 60;
}
else
{
minimizeButton.Text = "─";
this.Height = 100;
this.Width = 100;
}
};
// Maximize button
Button maximizeButton = new Button();
maximizeButton.Text = "⬜"; // Larger square Unicode character
maximizeButton.TextAlign = ContentAlignment.MiddleCenter;
maximizeButton.Width = 20;
maximizeButton.Height = 20;
maximizeButton.Dock = DockStyle.Right;
maximizeButton.FlatStyle = FlatStyle.Flat;
maximizeButton.FlatAppearance.BorderSize = 0;
// Store the original DockStyle
DockStyle originalDockStyle = DockStyle.None;
maximizeButton.Click += (sender, e) =>
{
if (this.Dock == DockStyle.None)
{
// Maximize the form
originalDockStyle = this.Dock;
this.Dock = DockStyle.Fill;
maximizeButton.Text = "❐"; // Change text to indicate restore
}
else
{
// Restore the original DockStyle
this.Dock = originalDockStyle;
maximizeButton.Text = "⬜"; // Change text to indicate maximize
}
};
titleBar.Controls.Add(maximizeButton);
// X button
Button xButton = new Button();
xButton.Text = "X";
xButton.Dock = DockStyle.Right;
xButton.Width = 20;
xButton.Height = 20;
xButton.FlatStyle = FlatStyle.Flat;
xButton.FlatAppearance.BorderSize = 0;
xButton.Click += (sender, e) => this.Dispose();
titleBar.Controls.Add(xButton);
this.ResumeLayout(false);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
const int WM_NCHITTEST = 0x84;
const int HT_LEFT = 10;
const int HT_RIGHT = 11;
const int HT_TOP = 12;
const int HT_TOPLEFT = 13;
const int HT_TOPRIGHT = 14;
const int HT_BOTTOM = 15;
const int HT_BOTTOMLEFT = 16;
const int HT_BOTTOMRIGHT = 17;
if (m.Msg == WM_NCHITTEST)
{
var pos = this.PointToClient(new Point(m.LParam.ToInt32()));
if (pos.X <= grab && pos.Y <= grab)
m.Result = new IntPtr(HT_TOPLEFT);
else if (pos.X >= this.ClientSize.Width - grab && pos.Y <= grab)
m.Result = new IntPtr(HT_TOPRIGHT);
else if (pos.X <= grab && pos.Y >= this.ClientSize.Height - grab)
m.Result = new IntPtr(HT_BOTTOMLEFT);
else if (pos.X >= this.ClientSize.Width - grab && pos.Y >= this.ClientSize.Height - grab)
m.Result = new IntPtr(HT_BOTTOMRIGHT);
else if (pos.X <= grab)
m.Result = new IntPtr(HT_LEFT);
else if (pos.X >= this.ClientSize.Width - grab)
m.Result = new IntPtr(HT_RIGHT);
else if (pos.Y <= grab)
m.Result = new IntPtr(HT_TOP);
else if (pos.Y >= this.ClientSize.Height - grab)
m.Result = new IntPtr(HT_BOTTOM);
}
}
bool isMouseDown = false;
private Point mouseDownLocation;
private void TitleBar_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
}
private void TitleBar_MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown)
{
// Check proximity on all sides (adjust the threshold as needed)
int proximityThreshold = 10;
// Calculate the new position of the control based on the mouse movement
int newX = this.Left - mouseDownLocation.X + e.X;
int newY = this.Top - mouseDownLocation.Y + e.Y;
// Ensure the new position is within the boundaries of the parent form
newX = Math.Max(0, Math.Min(newX, parentForm.ClientSize.Width - this.Width));
newY = Math.Max(0, Math.Min(newY, parentForm.ClientSize.Height - this.Height));
// Iterate through other controls and check if snapping is possible
foreach (var kvp in MyDictionary.userControlCollection)
{
if (kvp != this)
{
// Check top side
if (Math.Abs(newY - kvp.Bottom) < proximityThreshold)
{
newY = kvp.Bottom + 1;
// Align right and left if they are close enough
if (Math.Abs(newX - kvp.Left) < proximityThreshold)
{
newX = kvp.Left;
}
else if (Math.Abs(newX + this.Width - kvp.Right) < proximityThreshold)
{
newX = kvp.Right - this.Width;
}
}
// Check bottom side
else if (Math.Abs(newY + this.Height - kvp.Top) < proximityThreshold)
{
newY = kvp.Top - this.Height - 1;
// Align right and left if they are close enough
if (Math.Abs(newX - kvp.Left) < proximityThreshold)
{
newX = kvp.Left;
}
else if (Math.Abs(newX + this.Width - kvp.Right) < proximityThreshold)
{
newX = kvp.Right - this.Width;
}
}
// Check left side
if (Math.Abs(newX - kvp.Right) < proximityThreshold)
{
newX = kvp.Right + 1;
// Align tops if they are close enough
if (Math.Abs(newY - kvp.Top) < proximityThreshold)
{
newY = kvp.Top;
}
// Align bottoms if they are close enough
else if (Math.Abs(newY + this.Height - kvp.Bottom) < proximityThreshold)
{
newY = kvp.Bottom - this.Height;
}
}
// Check right side
else if (Math.Abs(newX + this.Width - kvp.Left) < proximityThreshold)
{
newX = kvp.Left - this.Width - 1;
// Align tops if they are close enough
if (Math.Abs(newY - kvp.Top) < proximityThreshold)
{
newY = kvp.Top;
}
// Align bottoms if they are close enough
else if (Math.Abs(newY + this.Height - kvp.Bottom) < proximityThreshold)
{
newY = kvp.Bottom - this.Height;
}
}
}
}
// Snap to parent form edges
if (Math.Abs(newX) < proximityThreshold)
{
newX = 0;
}
else if (Math.Abs(newX + this.Width - parentForm.ClientSize.Width) < proximityThreshold)
{
newX = parentForm.ClientSize.Width - this.Width;
}
if (Math.Abs(newY) < proximityThreshold)
{
newY = 0;
}
else if (Math.Abs(newY + this.Height - parentForm.ClientSize.Height) < proximityThreshold)
{
newY = parentForm.ClientSize.Height - this.Height;
}
this.Location = new Point(newX, newY);
// Forces the control to repaint for a smoother visual experience
this.Invalidate();
}
}
private void TitleBar_MouseDown(object sender, MouseEventArgs e)
{
isMouseDown = true;
mouseDownLocation = e.Location;
}
}