Thumbコントロールでドラッグ
http://www.moonmile.net/blog/archives/698
で、スクロールバーで使われる Thumb コントロールを使ってドラッグを試してみましたが、このままでは単純な四角(決められたスタイル)しかドラッグできません。
Thum コントロールを少し工夫して、色々な形のコントロールも移動ができるようにする、ことは可能だとは思うのですが、いささか面倒です。つーか、もともとやりたいことは、普通のコントロールのドラッグ、あとはコントロールを配置してマウスで移動、なんてのを想定しているので、Thumb コントロールでは都合が悪いのです。コードの見通は悪くないんだけどね、XAMLが奇妙な感じになりそう。
そんな訳で、普通のコントロール(Ellipseコントロール)を移動させてみます。
■Window1.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | < Window x:Class = "SampleDrag.Window1" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "Window1" Height = "300" Width = "400" > < Canvas Name = "board" > < TextBlock Canvas.Left = "0" Canvas.Top = "0" Height = "21" Name = "textPos" Width = "119" Text = "x:0 y:0" /> < Ellipse Name = "mark0" Canvas.Left = "28" Canvas.Top = "43" Height = "30" Stroke = "Black" Width = "30" Fill = "Pink" MouseLeftButtonDown = "mark0_MouseLeftButtonDown" MouseLeftButtonUp = "mark0_MouseLeftButtonUp" MouseMove = "mark0_MouseMove" /> </ Canvas > </ Window > |
■Windows1.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | /// <summary> /// Window1.xaml の相互作用ロジック /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void printPos( UIElement el) { int x = ( int )Canvas.GetLeft( el ); int y = ( int )Canvas.GetTop( el ); textPos.Text = string .Format( "x:{0} y:{1}" , x, y); } private bool _isDrag = false ; private Point _dragOffset; /// <summary> /// ドラッグ開始 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void mark0_MouseLeftButtonDown( object sender, MouseButtonEventArgs e) { UIElement el = sender as UIElement; if (el != null ) { _isDrag = true ; _dragOffset = e.GetPosition(el); el.CaptureMouse(); } } /// <summary> /// ドラッグ終了 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void mark0_MouseLeftButtonUp( object sender, MouseButtonEventArgs e) { if (_isDrag == true ) { UIElement el = sender as UIElement; el.ReleaseMouseCapture(); _isDrag = false ; } } /// <summary> /// ドラック中 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void mark0_MouseMove( object sender, MouseEventArgs e) { if (_isDrag == true ) { Point pt = Mouse.GetPosition(board); UIElement el = sender as UIElement; Canvas.SetLeft(el, pt.X - _dragOffset.X); Canvas.SetTop(el, pt.Y - _dragOffset.Y); printPos(el); } } } |
ざっと説明すると、
1.移動したい XAML のコントロールに3つのイベントを付けます。
1 2 3 | MouseLeftButtonDown= "mark0_MouseLeftButtonDown" MouseLeftButtonUp= "mark0_MouseLeftButtonUp" MouseMove= "mark0_MouseMove" |
マウスの左ボタンを押した時と離した時、そして移動しているときです。
このそれぞれのイベントに、ドラッグの処理を入れていきます。
1 2 3 4 5 6 7 8 9 10 | private void mark0_MouseLeftButtonDown( object sender, MouseButtonEventArgs e) { UIElement el = sender as UIElement; if (el != null ) { _isDrag = true ; _dragOffset = e.GetPosition(el); el.CaptureMouse(); } } |
左ボタンを押した時にドラッグを開始させます。
このとき、ドラッグ中のフラグ(_isDrag)を設定することと、マウスの相対位置(ドラッグするコントロールの左上からの相対位置)を e.GetPosition で取得して _dragOffset に保存しておきます。
これらはドラッグ中の時の、コントロールの移動に使います。
el.CaptureMouse() は、マウスコントロールをキャプチャするためのメソッドです。これがないと、マウスを素早く動かしたときに追随できません。
1 2 3 4 5 6 7 8 9 10 11 | private void mark0_MouseMove( object sender, MouseEventArgs e) { if (_isDrag == true ) { Point pt = Mouse.GetPosition(board); UIElement el = sender as UIElement; Canvas.SetLeft(el, pt.X - _dragOffset.X); Canvas.SetTop(el, pt.Y - _dragOffset.Y); printPos(el); } } |
マウスを動かしているときのイベントでは、ドラック中かどうかを調べます。これは、コントロール上でマウスを動かしたときでも、このイベントが発生するためです。
移動するコントロールの位置は、Mouse.GetPosition でボタンの位置を取得して、先ほど保存しておいた _dragOffset だけシフトさせます。board は、ドラッグするコントロールが乗っている canvas コントロールの名前です。
canvas に対する位置の設定は、Canvas.SetLeft と Canvas.SetTop を使います。
このあたり、本来は拡大率を計算する必要があるのですが、通常ドラッグは等倍で行われるので、簡単のためそのまま計算します。
1 2 3 4 5 6 7 8 9 | private void mark0_MouseLeftButtonUp( object sender, MouseButtonEventArgs e) { if (_isDrag == true ) { UIElement el = sender as UIElement; el.ReleaseMouseCapture(); _isDrag = false ; } } |
そして、マウスを離したときは、ドラッグ中のフラグ _isDrag を false にして、マウスのキャプチャを ReleaseMouseCapture メソッドで解放します。
これを実行すると
から
のようにマウスでドラッグできます。
Silverlight版は
http://moonmile.net/sl/SampleDrag/
で実行できます。
さて、コントロールを移動することができました。
しかし、このままでは xaml にいちいちイベントを追加しないと駄目ですよね。複数のコントロールを動かしたい場合は、大変なことになりそうだし、新しいコントロールを動的に追加したときなんか、どうやるんだろう? ってこといなりそうですね。
というわけで、今回はイベントを xaml にイベントを直に書きましたが、次回はこれを動的に追加できるようにします。
エントリで否定されたThumbを使った場合のサンプルを書いてみました。自由度とのトレードオフでしょうが、Templateである程度カスタマイズできるのと、イベント処理も簡単になるので私はけっこうThumbも使い回しが効きそうに思いました。
http://d.hatena.ne.jp/CoMo/20110316/
そうそう、この記事を書いた後に Thumb を使ってテンプレートを使えば十分じゃん、ということに気づきました。で、追加しようと思って、そのままになっているのであります。。。申し訳ない。
ただ、この時に調査している目的が、ドラッグ可能なコントロールを動的に追加」だったので、Thumb コントロールを使って、「動的に追加できるか?」が問題なんですよね。
というところで止まっていたりします。
Whats Going down i’m new to this, I stumbled upon this I have found It absolutely helpful and it has helped me out loads. I hope to give a contribution & assist other users like its aided me. Great job.