繼承 ToolStrip,內部維護四個 ToolStripPanel(上/下/左/右)作為停靠目標。拖動釋放時判斷位置:在浮動區域則創建 ToolStripFloatWindow,移回邊緣則重新停靠到對應 Panel。
public partial class MyToolStrip : ToolStrip {
public MyToolStrip() {
InitializeComponent();
EndDrag += MyToolStrip_EndDrag;
SizeChanged += MyToolStrip_SizeChanged;
}
#region 浮動狀態
public ToolStripFloatWindow FloatWindow { get; set; }
private bool IsFloating => FloatWindow != null;
public ToolStripPanel TopToolStripPanel { get; set; }
public ToolStripPanel BottomToolStripPanel { get; set; }
public ToolStripPanel LeftToolStripPanel { get; set; }
public ToolStripPanel RightToolStripPanel { get; set; }
#endregion
#region 浮動實現
private void FloatWindow_LocationChanged(object sender, EventArgs e) {
if (FloatWindow == null || !FloatWindow.HasCreated) return;
var frmLoc = TopToolStripPanel.Parent.Location;
var toolBarLoc = FloatWindow.Location;
// 判斷是否移回四邊停靠區
if (toolBarLoc.Y - frmLoc.Y <= 0) DockTo(TopToolStripPanel, toolBarLoc);
else if (toolBarLoc.X - frmLoc.X <= 0) DockTo(LeftToolStripPanel, toolBarLoc);
else if (toolBarLoc.X + FloatWindow.Width >= TopToolStripPanel.Parent.Width) DockTo(RightToolStripPanel, toolBarLoc);
else if (toolBarLoc.Y + FloatWindow.Height >= TopToolStripPanel.Parent.Height) DockTo(BottomToolStripPanel, toolBarLoc);
}
private void DockTo(ToolStripPanel panel, Point screenLoc) {
FloatWindow.Controls.Remove(this);
panel.SuspendLayout();
panel.Controls.Add(this);
Location = panel.PointToClient(screenLoc);
panel.ResumeLayout();
FloatWindow.Dispose();
FloatWindow = null;
}
private void MyToolStrip_EndDrag(object sender, EventArgs e) {
var screenPt = Cursor.Position;
var clientPt = TopToolStripPanel.Parent.PointToClient(screenPt);
// 浮動有效區域(排除四邊停靠區)
var floatArea = new Rectangle(32, 32,
TopToolStripPanel.Parent.Width - 64,
TopToolStripPanel.Parent.Height - 64);
if (floatArea.Contains(clientPt)) {
var fw = new ToolStripFloatWindow();
fw.Controls.Add(this);
Left = 0; Top = 0;
FloatWindow = fw;
FloatWindow.LocationChanged += FloatWindow_LocationChanged;
fw.SetBounds(screenPt.X, screenPt.Y, ClientSize.Width, ClientSize.Height + 22); // +22 標題欄
fw.Show();
}
}
private void MyToolStrip_SizeChanged(object sender, EventArgs e) {
if (IsFloating) FloatWindow.Width = ClientSize.Width;
}
#endregion
}
// 主窗體構造函數中
var toolStrip = new MyToolStrip {
TopToolStripPanel = topPanel,
BottomToolStripPanel = bottomPanel,
LeftToolStripPanel = leftPanel,
RightToolStripPanel = rightPanel
};
// 向 toolStrip 添加按鈕等項目
EndDrag 事件在拖動結束觸發,決定浮動或停靠ToolStripFloatWindow 是無邊框浮動容器LocationChanged 監聽浮動窗口移動,實現磁性吸附停靠floatArea 排除四邊 32px,防止誤觸發浮動