以前、WPF でコントロールのドラッグコードを書いたのですが、業務的に少し書き直してみます。WPFでコントロールをドラッグ(1) では、マウスの down/up/move のイベントを直接つけていますが、コントロールが増えたときには面倒ですね…というか、動的にイベントを追加すればよいのですが。ふと、[WPF]枠なしでリサイズ&ドラッグ移動可能なウィンドウを作る に行き当たると、WindowChrome クラス を使うと枠なしのウィンドウが作れて、MouseLeftButtonDown イベント内に DragMove イベントを呼び出せばよいようです。この方式だと簡単ですね。
というわけで、マウスダウンのイベントだけあらかじめ付けておいて、マウスの移動とアップイベントは動的に追加します。また、クラスの継承ではなくて拡張を使って実装します。
public static class ControlDragExtenstions
{
/// <summary>
/// コントロールのドラッグを有効にする
/// 親コントロールが Canvas であること
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public static void DragMove(this Control t, object sender, MouseButtonEventArgs e)
{
var el = sender as Control;
var canvas = el.Parent as Canvas;
var dragOffset = e.GetPosition(el);
el.CaptureMouse();
MouseEventHandler mouseMove = null;
MouseButtonEventHandler mouseUp = null;
mouseMove = new MouseEventHandler((_, __) => {
Point pt = Mouse.GetPosition(canvas);
Canvas.SetLeft(el, pt.X - dragOffset.X);
Canvas.SetTop(el, pt.Y - dragOffset.Y);
});
mouseUp = new MouseButtonEventHandler((_, __) => {
el.ReleaseMouseCapture();
el.MouseMove -= mouseMove;
el.MouseUp -= mouseUp;
});
el.MouseMove += mouseMove;
el.MouseLeftButtonUp += mouseUp;
}
}
利用するときは、次のように sender と MouseButtonEventArgs 引数をそのまま渡します。MouseButtonEventArgs のほうは、マウスの相対位置を調べるのに使います。
// マウスダウンのイベント処理
card.MouseLeftButtonDown += (sender, e) =>
{
this.DragMove(sender, e);
};
これを動かすと、こんな感じにドラッグができるようになります。
