【C#】 FlowLayoutPanel内コントロールのドラッグ&ドロップ

FlowLayoutPanel内に追加したコントロールをドラッグ&ドロップで移動したかったので,その方法のメモ。

概要

元々,Controlクラスにはドラッグ&ドロップ用のプロパティとイベントが用意されているが,今回は同一のFlowLayoutPanel内でコントロールの順番を変更したいだけなので,それらは使用せず単純に下記のようにした。

  1. FlowLayoutPanel内のコントロールのMouseUpイベントでドラッグ終了時のカーソル位置を取得
  2. カーソル位置に応じて,ドラッグされたコントロールのFlowLayoutPanel内インデックスを変更する

実装例

Form上にFlowLayoutPanelを1つ配置し,その中にButtonを3つ配置する。この3つのButtonのFlowLayoutPanel内での順番をドラッグ&ドロップで変更できるようにする。

f:id:nbps:20160430120456j:plain

コードは下記の通り。


FlowLayoutPanelの領域判定用範囲の設定

23行目にて,FlowLayoutPanelの領域と同じ位置,同じ大きさの領域を作成している。この領域はドロップ操作がFlowLayoutPanel内で行われたかどうかを判定するために使用している。

ButtonのMouseUpイベントを設定

38行目にて,各ButtonコントロールにMouseUpイベント(ドロップ操作イベント)を設定している。

SetChildIndexでインデックスを変更する

43~61行目がButtonコントロールのMouseUpイベントハンドラである。

46行目にて,離されたマウスボタンが左ボタンかどうかを判定している。左ボタンでない場合は何もしないようにしている。

52行目にて,ドロップ操作がFlowLayoutPanel内で行われたかどうかを判定している。e.Xとe.Yにはイベント発生元のButtonコントロール内でのカーソルの相対位置が格納されているため,Form上での相対位置に変換した上で前述の領域内にあるかどうかを判定している。領域外でドロップされた場合は何もしないようにしている。もちろん,実装によっては領域外でのドロップを許可しても良い。

55,58行目にて,FlowLayoutPanel内のインデックスを計算して,ドロップされたButtonのインデックスを設定している。

他のコントロールへのドラッグ&ドロップをする場合

今回の実装では同一のFlowLayoutPanel内でのドラッグ&ドロップなので上記のような単純な実装になっているが,他のFlowLayoutPanelや,その他のコントロールへのドラッグ&ドロップをする場合にはMouseDown(ドラッグ開始)イベントを使用してドラッグされたコントロールやカーソルの情報を保持しておく必要がある。