Thumbコントロールでドラッグ

WPFやSilverlightの表示は、XAMLで作成されているので、うまくやれば Windows アプリケーションの図形移動よりも楽に移動ができる…ハズです。

Windows コントロールの場合は、ボタンなどのような標準コントロールの場合はドラッグ&ドロップのイベントが用意されているのですが、四角や文字などを移動しようと思うと途端に難しくなります。
# マウスイベントを拾って移動すればいいだけなのですが、まあ、
# 面倒と言えば面倒。図形のサイズを変えようとすると、ひと苦労だし。

WPFやSilverlightのビューは、XAMLで書かれているので、ここの値を直接書き変えてやれば、移動や回転などができます。ボタン以外も、矩形や円なども同様に移動などができるわけです。

で、実際にやってみたのですが、結果を言えば、やっぱり「ひと苦労」ですね。
矩形のハンドル(四隅にある四角)を使って大きさなどを変えようと思うと、ハンドル自身のマウスダウンイベントや、移動のイベントなどを拾う必要があります。
さて、具体的な例は、もう少しソースを整理してから紹介することにして。

実は WPF と Silverlight には、あらかじめドラッグできるコントロールが用意されています。これが、「Thumbコントロール」なのです。リストボックスなどのスクロールバーに使われています。

Thumb クラス
http://msdn.microsoft.com/ja-jp/library/system.windows.controls.primitives.thumb.aspx
で、結論を先に言うと、これを使って汎用的なドラッグできるコントロールができるかというと、「できません!」。あくまで、スクロールバーなどに使うコントロールで、一般的な形になっていません。なので、色やら枠線やらが固定になっています。

ま、ひとつ、参考までにソースを晒しておきます。

■WPFの場合

<001>
20100310_001

<Window x:Class=&quot;SampleThumb.Window1&quot;
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    Title=&quot;Window1&quot; Height=&quot;300&quot; Width=&quot;400&quot;>
    <Canvas>
        <TextBlock Canvas.Left=&quot;0&quot; Canvas.Top=&quot;0&quot; Height=&quot;22&quot; Name=&quot;textPos&quot; Width=&quot;75&quot; Text=&quot;x:0 y:0&quot; />
        <Rectangle Canvas.Left=&quot;46&quot; Canvas.Top=&quot;48&quot; Height=&quot;70&quot; Name=&quot;rectangle1&quot; Stroke=&quot;Black&quot; Width=&quot;109&quot; Fill=&quot;pink&quot;/>
        <Thumb Canvas.Left=&quot;141&quot; Canvas.Top=&quot;103&quot; Height=&quot;30&quot; Name=&quot;mark&quot;  Width=&quot;30&quot; Background=&quot;LightBlue&quot;
               DragCompleted=&quot;mark_DragCompleted&quot;
               DragStarted=&quot;mark_DragStarted&quot;
               DragDelta=&quot;mark_DragDelta&quot;
               />
    </Canvas>
</Window>

 

namespace SampleThumb
{
    /// <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(&quot;x:{0} y:{1}&quot;, x, y);
        }

        /// <summary>
        /// ドラッグ開始
        /// </summary>
        /// <param name=&quot;sender&quot;></param>
        /// <param name=&quot;e&quot;></param>
        private void mark_DragStarted(object sender,
            System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            mark.Background = Brushes.Pink;
            Debug.Print(&quot;start&quot;);
        }
        /// <summary>
        /// ドラッグ終了
        /// </summary>
        /// <param name=&quot;sender&quot;></param>
        /// <param name=&quot;e&quot;></param>
        private void mark_DragCompleted(object sender,
            System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            mark.Background = Brushes.LightBlue;
            Debug.Print(&quot;end&quot;);
        }

        /// <summary>
        /// ドラッグ中
        /// </summary>
        /// <param name=&quot;sender&quot;></param>
        /// <param name=&quot;e&quot;></param>
        private void mark_DragDelta(object sender,
            System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            printPos(mark);
            Canvas.SetLeft(mark, Canvas.GetLeft(mark) + e.HorizontalChange);
            Canvas.SetTop(mark, Canvas.GetTop(mark) + e.VerticalChange);
        }
    }
}

肝は、Thumb コントロールの3つのイベントです。

・DragStartedイベント
・DragCompletedイベント
・DragDeltaイベント

ドラッグ中は、DragDeltaイベント内で、mark(移動するThumbコントロール)の位置を変更します。位置は、canvas を使って簡便に、SetLeft、SetTop メソッドを使っています。

■Silverlightの場合

まったく同じものが Silverlight でも動作します。

<002>
20100310_002

<UserControl x:Class=&quot;SampleThumbSilverlight.MainPage&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:d=&quot;<a href=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;>http://schemas.microsoft.com/expression/blend/2008</a>&quot; xmlns:mc=&quot;<a href=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;>http://schemas.openxmlformats.org/markup-compatibility/2006</a>&quot;
    mc:Ignorable=&quot;d&quot; d:DesignWidth=&quot;400&quot; d:DesignHeight=&quot;300&quot;>
    <Canvas x:Name=&quot;LayoutRoot&quot;>
        <TextBlock Canvas.Left=&quot;0&quot; Canvas.Top=&quot;0&quot; Height=&quot;22&quot; Name=&quot;textPos&quot; Width=&quot;75&quot; Text=&quot;x:0 y:0&quot; />
        <Rectangle Canvas.Left=&quot;46&quot; Canvas.Top=&quot;48&quot; Height=&quot;70&quot; Name=&quot;rectangle1&quot; Stroke=&quot;Black&quot; Width=&quot;109&quot; Fill=&quot;pink&quot;/>
        <Thumb Canvas.Left=&quot;141&quot; Canvas.Top=&quot;103&quot; Height=&quot;30&quot; Name=&quot;mark&quot;  Width=&quot;30&quot; Background=&quot;LightBlue&quot;
               DragCompleted=&quot;mark_DragCompleted&quot;
               DragStarted=&quot;mark_DragStarted&quot;
               DragDelta=&quot;mark_DragDelta&quot;
               />
    </Canvas>
</UserControl>

 

namespace SampleThumbSilverlight
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void printPos(UIElement el)
        {
            int x = (int)Canvas.GetLeft(el);
            int y = (int)Canvas.GetTop(el);
            textPos.Text = string.Format(&quot;x:{0} y:{1}&quot;, x, y);
        }

        /// <summary>
        /// ドラッグ開始
        /// </summary>
        /// <param name=&quot;sender&quot;></param>
        /// <param name=&quot;e&quot;></param>
        private void mark_DragStarted(object sender,
            System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            mark.Background = new SolidColorBrush(Colors.Orange);
        }
        /// <summary>
        /// ドラッグ終了
        /// </summary>
        /// <param name=&quot;sender&quot;></param>
        /// <param name=&quot;e&quot;></param>
        private void mark_DragCompleted(object sender,
            System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            mark.Background = new SolidColorBrush(Colors.Purple);
        }

        /// <summary>
        /// ドラッグ中
        /// </summary>
        /// <param name=&quot;sender&quot;></param>
        /// <param name=&quot;e&quot;></param>
        private void mark_DragDelta(object sender,
            System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            printPos(mark);
            Canvas.SetLeft(mark, Canvas.GetLeft(mark) + e.HorizontalChange);
            Canvas.SetTop(mark, Canvas.GetTop(mark) + e.VerticalChange);
        }
    }
}

Siverlight の動作はこちらで確認できます。

http://www.moonmile.net/sl/SampleThumb/

 

という訳で、Thumbコントロールは汎用的ではないので「使えない」。
仕方がないので、MouseLeftButtonDown イベントなどを地道に取得することになります。

~~ 2010/04/01 追記 ~~

「使えない」と思っていたのですが、Template 化して使うことができました。
となると、自前でドラッグフラグを作らなくていいから、Thumb コントロールは使えるのでは?

カテゴリー: 開発 パーマリンク

Thumbコントロールでドラッグ への2件のフィードバック

  1. elno のコメント:

    すみません、

    >あくまで、スクロールバーなどに使うコントロールで、一般的な形になっていません。なので、色やら枠線やらが固定になっています。

    これってどういう意味ですか?
    他のコントロール同様、TemplateにEllipseなりTextBoxなり適当に詰め込んでみたら
    ちゃんとドラッガブルになりましたが…

    Canvasの外に持っていけないって事をおっしゃってます?

  2. masuda のコメント:

    おお、なるほど!Templateにするといけますね。これはやっていませんでした。
    ありがとうございます。

    実は「できない」と思っていたから、矩形の大きさを変えるハンドル(四隅の小さな四角)を自作していたんですよね。あと、矢印を動的に配置するツール。う~ん、これだと、ハンドル部分を Thumb の Template を変更するほうが、手早いのかも。試してみます。

コメントは停止中です。