WPF でコントロールをドラッグする

以前、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);
};

 

これを動かすと、こんな感じにドラッグができるようになります。

image

カテゴリー: C#, WPF パーマリンク