連載
続・無償環境でSilverlight 2アプリを開発しよう!

第1回 動きのあるSilverlightアプリを作ろう

シグマコンサルティング 菅原 英治
2009/02/10
Page1 Page2 Page3 Page4

文字列をドラッグ&ドロップするサンプルを開発しよう

 VWD 2008を起動し、新しいSilverlight 2アプリのプロジェクトを作成してください(VWD 2008のインストール方法と、Silverlight 2アプリのプロジェクトの作成方法については、「Silverlight 2アプリを開発しよう!後編」をご参照ください)。

 プロジェクトが作成できたら「Page.xaml」を編集し、アプリケーション画面を作成します。次の太字のコードを入力してください。

<UserControl ……略……>
  <Canvas x:Name="LayoutRoot" Background="Azure">
   <TextBlock Text="Hello" FontSize="30"
       MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"
       MouseMove="TextBlock_MouseMove"
       MouseLeftButtonUp="TextBlock_MouseLeftButtonUp" />
  </Canvas>
</UserControl>
ドラッグ&ドロップのサンプルのXAMLコード(Page.xaml)

 ここでまず、レイアウト用のコントロールとしてCanvasコントロール(=<Canvas>要素。以下、単に「Canvas」と表記)を定義しています。ここでCanvasを使っているのは、ドラッグ&ドロップ後の子要素の位置を絶対座標で指定できるようにするためです。Canvasの利用方法の詳細については、前回の記事の「Canvasコントロールを利用してみよう」をご参照ください。

 Canvasの子要素として、TextBlockコントロール(=<TextBlock>要素)を定義しています。これについては、ドラッグ&ドロップを実現するために、次の3つのイベントについてイベント・ハンドラを定義しています。

名前 説明
MouseLeftButtonDown マウス・ポインタがこの要素上にあるときに、マウスの左ボタンが押されると発生します
MouseMove マウス・ポインタがこの要素上にあるときに、マウスが移動すると発生します
MouseLeftButtonUp マウス・ポインタがこの要素上にあるときに、マウスの左ボタンが離されると発生します
ドラッグ&ドロップを実現するために制御する3つのイベント

 続いて「Page.xaml」のコード・ビハインド(VB:Page.xaml.vb、C#:Page.xaml.cs)を開き、次の太字のコードを入力してください。

Partial Public Class Page
  Inherits UserControl

  Public Sub New()
    InitializeComponent()
  End Sub

  ' ドラッグ中かどうか
  Private isDragging As Boolean = False
  ' クリック始点
  Private startPoint As Point

  ' 左クリックを押したときのイベント・ハンドラ
  Private Sub TextBlock_MouseLeftButtonDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
    ' ドラッグ中とする
    isDragging = True

    ' クリックされたポイントを始点として設定する
    startPoint = e.GetPosition(Nothing)

    ' テキストブロックを半透明にする
    CType(sender, TextBlock).Opacity = 0.75

    ' マウスをテキストブロックにキャプチャする
    CType(sender, TextBlock).CaptureMouse()
  End Sub

  ' マウス移動時のイベント・ハンドラ
  Private Sub TextBlock_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseEventArgs)
    ' ドラッグ中以外は処理しない
    If isDragging = False Then
      Exit Sub
    End If

    ' テキストブロック型として変換する
    Dim text As TextBlock = CType(sender, TextBlock)

    ' ドラッグ先の終点を取得する
    Dim endPoint As Point = e.GetPosition(Nothing)

    ' テキストブロックの座標を計算し設定する
    text.SetValue(Canvas.LeftProperty, _
      CDbl(text.GetValue(Canvas.LeftProperty)) + endPoint.X - startPoint.X)
    text.SetValue(Canvas.TopProperty, _
      CDbl(text.GetValue(Canvas.TopProperty)) + endPoint.Y - startPoint.Y)

    ' 終点を始点として設定する
    startPoint = endPoint

  End Sub

  ' 左クリック後、離したときのイベント・ハンドラ
  Private Sub TextBlock_MouseLeftButtonUp(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
    ' ドラッグ中ではないとする
    isDragging = False

    ' 半透明から戻す
    CType(sender, TextBlock).Opacity = 1.0

    ' マウスのキャプチャを解放する
    CType(sender, TextBlock).ReleaseMouseCapture()
  End Sub
End Class
public partial class Page : UserControl
{
  public Page()
  {
    InitializeComponent();
  }

  // ドラッグ中かどうか
  private bool isDragging = false;
  // クリック始点
  private Point startPoint;

  // 左クリックを押したときのイベント・ハンドラ
  private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  {
    // ドラッグ中とする
    isDragging = true;

    // クリックされたポイントを始点として設定する
    startPoint = e.GetPosition(null);

    // テキストブロックを半透明にする
    (sender as TextBlock).Opacity = 0.75;

    // マウスをテキストブロックにキャプチャする
    (sender as TextBlock).CaptureMouse();

  }

  // マウス移動時のイベント・ハンドラ
  private void TextBlock_MouseMove(object sender, MouseEventArgs e)
  {
    // ドラッグ中以外は処理しない
    if (!isDragging)
      return;
   
    // テキストブロック型として変換する
    TextBlock text = sender as TextBlock;

    // ドラッグ先の終点を取得する
    Point endPoint = e.GetPosition(null);

    // テキストブロックの座標を計算し設定する
    text.SetValue(Canvas.LeftProperty,
      (double)text.GetValue(Canvas.LeftProperty) + endPoint.X - startPoint.X);
    text.SetValue(Canvas.TopProperty,
      (double)text.GetValue(Canvas.TopProperty) + endPoint.Y - startPoint.Y);

    // 終点を始点として設定する
    startPoint = endPoint;
  }

  // 左クリック後、離したときのイベント・ハンドラ
  private void TextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  {
    // ドラッグ中ではないとする
    isDragging = false;
   
    // 半透明から戻す
    (sender as TextBlock).Opacity = 1.0;

    // マウスのキャプチャを解放する
    (sender as TextBlock).ReleaseMouseCapture();
  }
}
ドラッグ&ドロップを実現するために制御する3つのイベントのイベント・ハンドラ(上:Page.xaml.vb、下:Page.xaml.cs)
なお、Page.xamlファイル上で、MouseLeftButtonDown属性、MouseMove属性、MouseLeftButtonUp属性を記述した際に、TextBlock_MouseLeftButtonDownメソッド、TextBlock_MouseMoveメソッド、TextBlock_MouseLeftButtonUpメソッドのひな型が自動的に作成されるはずだ。(コードをコピー&ペーストしたなどの理由で)作成されていない場合には、Page.xamlファイル上でこれらの属性記述部分を右クリックして、表示されるコンテキスト・メニューから[イベント ハンドラへ移動]を選択すればよい(C#、VB、どちらも可能)。

 では、このコード・ビハインド(VB:Page.xaml.vb、C#:Page.xaml.cs)について解説します。

ドラッグ&ドロップでコントロールを移動する場合のポイント

 まずドラッグ&ドロップでコントロールを移動する場合のポイントとなる座標についてです。次の図をご覧ください。

ポイントとなる座標について
  TextBlockコントロールの初期の左上の座標(「初期位置」とする)。
  TextBlockコントロール上でマウスをクリックした座標(「始点」とする)。
  ドラッグしながらマウスを移動した先の座標(「終点」とする)。

 コントロールをドラッグ&ドロップで移動する際には、移動する先の左上の座標(図の★の位置)を求め、コントロールに設定する必要があります。その座標は、の初期位置、の始点、の終点から求めることができ、その計算式は下記となります。

 移動先のX(Y)座標 = 初期位置のX(Y)座標
                 終点のX(Y)座標
                 始点のX(Y)座標

 先ほどの図を例に計算すると、次の表のようになり、正しいことが分かります。

X座標 Y座標
初期位置 2 2
始点 4 3
終点 8 7
★移動先 6(=2+8−4) 6(=2+7−3)

ドラッグ&ドロップを実現するコードの解説

 上述の移動先の左上の座標を求めるというポイントを理解できれば、このコードは簡単です。

 まず、ドラッグ中かどうかを判定するための「isDragging」メンバ変数と、クリックを開始した始点を保持するための「startPoint」メンバ変数を定義します。これらは、TextBlock_MouseLeftButtonDown、TextBlock_MouseMove、TextBlock_MouseLeftButtonUpの3つのメソッド(=イベント・ハンドラ)から利用されるメンバ変数です。

 これら3つのメソッドについて、簡単に解説します。

 TextBlock_MouseLeftButtonDownメソッドでは、ドラッグ状態をドラッグ中とし、クリックした点を始点として保存します。また、TextBlockコントロールのOpacityプロパティを設定し、ドラッグ中を表現するために半透明にしています。続いて、TextBlockコントロールにマウスをキャプチャさせ、ドラッグした状態を維持させます。

 TextBlock_MouseMoveメソッドではまず、ドラッグ状態がドラッグ中でなければ何も処理を行いません。ドラッグ中の場合は、ドラッグ先の終点を取得しています。続いて初期位置、始点、終点を利用し、移動先の座標を求め、TextBlockコントロールに設定します。最後に終点を最新の始点として設定します。

 TextBlock_MouseLeftButtonUpメソッドでは、ドラッグ状態をドラッグ中ではないとし、TextBlockコントロールを半透明から戻します。また、TextBlockコントロールにマウスをキャプチャさせたので、それを解放します。

 Silverlight 2でのドラッグ&ドロップの実現方法についての解説は以上です。簡単なコードで、実現できることが分かったのではないでしょうか。Silverlight 2アプリのUI開発では、今回解説したようなイベントの制御が重要となります。これまでASP.NETでのWebアプリ開発の経験しかない方は、もしかするとこのようなイベント制御にまだ慣れないかもしれません。しかし、UIの開発は、動きがすぐ目に見え、楽しいものなので、すぐに習得できるでしょう。

 また、今回は解説を簡単にするため、ドラッグ&ドロップというよりもドラッグ(=移動)についての解説となりました。(次のコラムで紹介する例のように)ドロップ(=落とす)を実現するのは、さらに応用が必要となり若干難しくなりますが、ぜひご自身で挑戦してみてください。

【コラム】ドラッグ&ドロップの利用例

 Silverlight 2でのドラッグ&ドロップを利用したものとして、わたしは次のアプリを開発しました。

 このアプリでは、国後島と択捉島がドラッグで移動できるようになっており、背景として設定した白地図の都道府県と両島の大きさを比較できます。

 このアプリは、本稿で紹介した技術を少し応用するだけで簡単に作れます。皆さんも、何かアイデアがあれば、ぜひアプリを開発してみてください。

 続いて、Silverlight 2アプリでのアニメーションの利用方法について解説します。


 INDEX
  連載:続・無償環境でSilverlight 2アプリを開発しよう!
  第1回 動きのあるSilverlightアプリを作ろう
    1.文字列をドラッグ&ドロップするサンプルを動かそう
  2.ドラッグ&ドロップを開発しよう
    3.アニメーションを利用しよう
    4.動画を利用しよう

インデックス・ページヘ  「続・無償環境でSilverlight 2アプリを開発しよう!」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH