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="SampleThumb.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>
        <TextBlock Canvas.Left="0" Canvas.Top="0" Height="22" Name="textPos" Width="75" Text="x:0 y:0" />
        <Rectangle Canvas.Left="46" Canvas.Top="48" Height="70" Name="rectangle1" Stroke="Black" Width="109" Fill="pink"/>
        <Thumb Canvas.Left="141" Canvas.Top="103" Height="30" Name="mark"  Width="30" Background="LightBlue"
               DragCompleted="mark_DragCompleted"
               DragStarted="mark_DragStarted"
               DragDelta="mark_DragDelta"
               />
    </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("x:{0} y:{1}", x, y);
        }

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

        /// <summary>
        /// ドラッグ中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></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="SampleThumbSilverlight.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:d="<a href="http://schemas.microsoft.com/expression/blend/2008">http://schemas.microsoft.com/expression/blend/2008</a>" xmlns:mc="<a href="http://schemas.openxmlformats.org/markup-compatibility/2006">http://schemas.openxmlformats.org/markup-compatibility/2006</a>"
    mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="300">
    <Canvas x:Name="LayoutRoot">
        <TextBlock Canvas.Left="0" Canvas.Top="0" Height="22" Name="textPos" Width="75" Text="x:0 y:0" />
        <Rectangle Canvas.Left="46" Canvas.Top="48" Height="70" Name="rectangle1" Stroke="Black" Width="109" Fill="pink"/>
        <Thumb Canvas.Left="141" Canvas.Top="103" Height="30" Name="mark"  Width="30" Background="LightBlue"
               DragCompleted="mark_DragCompleted"
               DragStarted="mark_DragStarted"
               DragDelta="mark_DragDelta"
               />
    </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("x:{0} y:{1}", x, y);
        }

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

        /// <summary>
        /// ドラッグ中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></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 を変更するほうが、手早いのかも。試してみます。

コメントは停止中です。