使用DevExpressWinform实现窗体对齐到网格和边缘吸附效果
本帖最后由 cosky 于 2026-3-1 18:02 编辑先看效果:
核心代码:
在窗体构造函数中初始化:
void InitSnapOption()
{
SnapOptions snapOptions1 = new SnapOptions
{
//当窗体移动时是否触发吸附效果
SnapOnMoving = DefaultBoolean.True,
//当窗体改变大小时是否触发吸附效果
SnapOnResizing = DefaultBoolean.True,
//当窗体移动时是否有网格吸附效果
SnapToGrid = DefaultBoolean.False,
//当窗体拖放到屏幕边缘时是否启用吸附效果
SnapToScreen = DefaultBoolean.True,
//当两个窗体靠近时是否启用吸附效果(需要两个窗体都有BehaviorManager,并且设置了SnapToSnapForms=True)
SnapToSnapForms = DefaultBoolean.True,
//当窗体移动时吸附的网格大小
GridCellSize = new Size(20, 20),
//吸附效果触发的距离(注意:如果启用了多个窗体之间吸附效果,请保持该属性一致,否则会出现不可描述的效果)
SnapThreshold = 20
};
this.behaviorManager.SetBehaviors(this, new DevExpress.Utils.Behaviors.Behavior[] {
DevExpress.Utils.Behaviors.Common.SnapWindowBehavior.Create(typeof(DevExpress.Utils.BehaviorSource.SnapWindowBehaviorSourceForForm), snapOptions1)
});
}
鼠标悬停在窗体区域上的效果:
void InitLabelEvents(LabelControl labelControl)
{
labelControl.MouseEnter += LabelControl_MouseEnter;
labelControl.MouseLeave += LabelControl_MouseLeave;
labelControl.MouseClick += LabelControl_MouseClick;
}
private void LabelControl_MouseClick(object sender, MouseEventArgs e)
{
var label = (sender as LabelControl);
this.ShowChildForm<SnapForm2>(label.Size, PointToScreen(label.Location));
}
private void LabelControl_MouseLeave(object sender, EventArgs e)
{
(sender as LabelControl).Appearance.BackColor = Color.LightCyan;
}
private void LabelControl_MouseEnter(object sender, EventArgs e)
{
(sender as LabelControl).Appearance.BackColor = Color.Silver;
}
绘制窗口停靠矩形区域:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen customPen = new Pen(Color.Silver)
{
DashStyle = System.Drawing.Drawing2D.DashStyle.Dash,
DashCap = System.Drawing.Drawing2D.DashCap.Flat,
DashPattern = new float[] { 3, 1 },
Width = 2
};
using (DevExpress.Utils.Drawing.GraphicsCache cache = new DevExpress.Utils.Drawing.GraphicsCache(e.Graphics))
{
cache.DrawRectangle(customPen, GetLabelRect(labelControl1));
cache.DrawRectangle(customPen, GetLabelRect(labelControl2));
cache.DrawRectangle(customPen, GetLabelRect(labelControl3));
cache.DrawRectangle(customPen, GetLabelRect(labelControl4));
}
}
点击Label生成子窗体:
private void LabelControl_MouseClick(object sender, MouseEventArgs e)
{
var label = (sender as LabelControl);
this.ShowChildForm<SnapForm2>(label.Size, PointToScreen(label.Location));
}
ShowChildForm方法扩展:
public static (T Form, bool InstanceCreated) ShowChildForm<T>(this FormBase parentForm, Size formSize, Point formPoint) where T : FormBase
{
var childType = typeof(T);
var childForm = CreateInstance<T>(childType, parentForm);
childForm.Owner = parentForm;
childForm.StartPosition = FormStartPosition.Manual;
childForm.Size = formSize;
childForm.Location = formPoint;
if (parentForm.FormTag == null)
{
parentForm.FormTag = new FormTags { BeforeBound = parentForm.Bounds };
parentForm.SizeMoving += (sender) => FixedChildForm(parentForm);
parentForm.ExitSizeMove += (sender) =>
{
parentForm.FormTag.BeforeBound = parentForm.Bounds;
UpdateChildForm(parentForm);
};
}
childForm.Shown += (sender, e) =>
{
childForm.FormTag = new FormTags()
{
BoundLeft = childForm.Left - parentForm.Left,
BoundTop = childForm.Top - parentForm.Top,
BoundRight = parentForm.Right - childForm.Right,
BoundBottom = parentForm.Bottom - childForm.Bottom,
ParentBound = parentForm.Bounds,
BeforeBound = childForm.Bounds
};
};
childForm.ExitSizeMove += (sender) =>
{
UpdateChildForm(parentForm, childForm);
};
childForm.Show(parentForm);
return (childForm, true);
}
2026-1-6 更新:
可设置拖动主窗体时,子窗体跟随主窗体移动
完整方案下载:
(环境.NetFramework4.8 + DevExpress24.2)
感谢楼主的热心分享
页:
[1]