WPFでドラッグ対応のアプリを作る

WPFでドラッグしてボタンやオブジェクトを移動させて配置を操作するアプリを作りたい場面は多々あると思いますが、Visual Studioの標準機能では簡単に実現できる手段は用意されていません。いくつか自力で実現する方法はあるのですが、WPFの開発を始めたときになかなか情報が得られなかったのでメモがわりにまとめておきます。

それじゃないドラッグ&ドロップがしたいの

Visual StuidoのヘルプやGoogleで安易に検索してみると見つかるドラッグ&ドロップは、上記の操作(そしてあなたのやりたいと思っていること)とは異なっていると思います。Visual Studioが用意しているのは、例えばエクスプローラからファイルを自作アプリにドロップして開くような操作です。もしこれがビンゴなら下の方法で実現できます。
ドラッグ アンド ドロップの概要 | Microsoft Docs

もしハズレだと思うのだったら、これに関連するそれっぽいイベントDragEnter、DraLeave、DragOver、Dropは期待はずれです。目的が違うので役に立ちません。

方法1:MouseDownやMouseMoveイベントを駆使する

期待しているようなドラッグに対応したイベントはControlやFrameworkElementには用意されていませんのでより低レベルのイベントMouseDownやMouseMoveを組み合わて自力で実現する必要があります。

具体的には下のリンクを見てもらうとして、MouseDownイベントでドラッグ中のフラグを立て、MouseMoveイベントでポインタの移動量に合わせて対象オブジェクトを移動し、MouseUpイベントでフラグを下ろします。
WPFでコントロールをドラッグ(1) | Moonmile Solutions Blog
ただドラッグ中のEscキーでのキャンセルとか、最小移動量(System.Windows.Forms.SystemInformation.DragSize.Widthなどで取得可能)に満たない場合もキャンセル扱いにするなどの処理があったほうが良いように思います。

比較的分かりやすいのですが、実にWPFっぽくない実装で、ドラッグさせたいオブジェクトの種類が増えるとコードビハインドのソースコードが汚れるのが難点です。また、コピペする以外に処理を汎用化して再利用するのが難しくなります。

なお、オブジェクトの位置を数値指定するために、Canvasレイアウトの中に対象オブジェクトを配置することが前提になります。これは他の方法でも共通することです。

方法2:Thumbコントロールを使う方法

上記の方法はその場しのぎ感が強くて本格的に採用したくないかもしれません。ドラッグに特化したコントロールとしてはThumbコントロールがあります。これはドラッグ処理に便利な高レベルのイベントDragStart、DragDelta、DragCompletedが用意されています。今回の目的だけであればDragDeltaに2行ほど書けば十分です。先の例のようにフラグを管理する必要もありません。
【WPF】【XAML】ThumbとCanvasで掴んで移動! | 創造的プログラミングと粘土細工

Thumbコントロールは元々スクロールバーのつまみの用途に用意されているのでデフォルトでは味気のない四角いボタンです。ただしWPFの特徴のテンプレートを使えば自由なオブジェクトに差し替えることができますのでなかなかお手軽な方法だと思います。

方法3:ExpressionBlendを使う

Blendを使えるリッチマンはもっと簡単に瞬殺でドラッグ対応を実現できます。具体的には次のMovie6を見て頂ければ分かるようにBlend上の操作で30秒弱で完了しています。すばらしい。
第10回 WPFの「入力イベントとアニメーション」を学ぼう (2/2):連載:WPF入門 - @IT

この方法が優れているのは簡単なだけでなく、ビヘイビアと呼ばれるMouseDragElementBehaviorの属性をXAMLで付けるだけで、コードビハインドにイベントハンドラが不要です。完全に再利用可能なWPFらしいアプローチです。

方法4:Expression Blend SDKを使う

この方法は実質的に方法3と同じです。Blendを使わずに同じXAMLコードを書けば良いだけです。ただし実行するにはMouseDragElementBehaviorを含むアセンブリ(DLLファイル)が必要です。
つい最近までBlendを買わないとダメなのだと思い込んでいましたが、実はBlend SDKというのがフリーでダウンロードできて、この中にアセンブリが含まれています。もちろん再配布可能なのでライセンスの問題もありません。


以上サンプルコードもなく完全に他人のふんどしエントリですが、WPFのドラッグに関して複数の手段をまとめて説明しているところが少ないようなのでまとめて見ました。