private Point LastMousePosition = new Point(-1, -1); // -1 代表無效
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown(e);
// 客戶區 → 視圖座標(折射修正)
Point p = new Point(e.X, e.Y);
p.Offset(-AutoScrollPosition.X, -AutoScrollPosition.Y);
LastMousePosition = p;
// 單點選取:檢查每個單元格邊界是否包含點
foreach (var cell in myDocument.Cells) {
bool select = cell.Bounds.Contains(p);
if (cell.Selected != select) {
InvalidateCell(cell);
cell.Selected = select;
}
}
}
protected override void OnMouseMove(MouseEventArgs e) {
base.OnMouseMove(e);
if (LastMousePosition.X < 0) return; // 未按下
// 目前點也轉視圖座標
Point p = new Point(e.X, e.Y);
p.Offset(-AutoScrollPosition.X, -AutoScrollPosition.Y);
// 兩點構成選取矩形
Rectangle selRect = Rectangle.Empty;
selRect.X = Math.Min(p.X, LastMousePosition.X);
selRect.Width = Math.Abs(p.X - LastMousePosition.X);
selRect.Y = Math.Min(p.Y, LastMousePosition.Y);
selRect.Height = Math.Abs(p.Y - LastMousePosition.Y);
// 矩形與單元格相交即選取
foreach (var cell in myDocument.Cells) {
bool flag = selRect.IntersectsWith(cell.Bounds);
if (cell.Selected != flag) {
cell.Selected = flag;
InvalidateCell(cell);
}
}
}
protected override void OnMouseUp(MouseEventArgs e) {
base.OnMouseUp(e);
LastMousePosition = new Point(-1, -1); // 重置
}
同 DataObject.SetData 可疊加格式,Clipboard.SetDataObject(data, true) 第二參數 true 確保應用程式關閉後剪貼簿資料仍保留。
Offset(-AutoScrollPosition),消除折射干擾。if (cell.Selected != flag) 避免重複 InvalidateCell,極大降低重繪開銷。Rectangle.IntersectsWith 以 O(1) 完成範圍選取判定。