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 メソッドで解放します。
これを実行すると
<001>

から
<002>

のようにマウスでドラッグできます。
Silverlight版は
http://moonmile.net/sl/SampleDrag/
で実行できます。
さて、コントロールを移動することができました。
しかし、このままでは xaml にいちいちイベントを追加しないと駄目ですよね。複数のコントロールを動かしたい場合は、大変なことになりそうだし、新しいコントロールを動的に追加したときなんか、どうやるんだろう? ってこといなりそうですね。
というわけで、今回はイベントを xaml にイベントを直に書きましたが、次回はこれを動的に追加できるようにします。