Thumbコントロールでドラッグ
http://www.moonmile.net/blog/archives/698
で、スクロールバーで使われる Thumb コントロールを使ってドラッグを試してみましたが、このままでは単純な四角(決められたスタイル)しかドラッグできません。
Thum コントロールを少し工夫して、色々な形のコントロールも移動ができるようにする、ことは可能だとは思うのですが、いささか面倒です。つーか、もともとやりたいことは、普通のコントロールのドラッグ、あとはコントロールを配置してマウスで移動、なんてのを想定しているので、Thumb コントロールでは都合が悪いのです。コードの見通は悪くないんだけどね、XAMLが奇妙な感じになりそう。
そんな訳で、普通のコントロール(Ellipseコントロール)を移動させてみます。
■Window1.xaml
<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
/// <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つのイベントを付けます。
MouseLeftButtonDown="mark0_MouseLeftButtonDown" MouseLeftButtonUp="mark0_MouseLeftButtonUp" MouseMove="mark0_MouseMove"
マウスの左ボタンを押した時と離した時、そして移動しているときです。
このそれぞれのイベントに、ドラッグの処理を入れていきます。
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() は、マウスコントロールをキャプチャするためのメソッドです。これがないと、マウスを素早く動かしたときに追随できません。
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 を使います。
このあたり、本来は拡大率を計算する必要があるのですが、通常ドラッグは等倍で行われるので、簡単のためそのまま計算します。
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.