デベロッパー

デベロッパー

Windowsフォームアプリケーションにドラッグ&ドロップ機能を実装する

Wei-Meng Lee
2008年8月5日 / 10:00
 
 

はじめに

 一般的に、Windowsアプリケーション上に外部アプリケーションからデータをドラッグ&ドロップする際は、渡されるデータの構造や、データの使用に適した仕組みを見極める必要があります。

 ドラッグ&ドロップ機能の実装には手間がかかるため敬遠する開発者もいますが、ドラッグ&ドロップをサポートするとアプリケーションの有用性は大きく高まります。本稿では、Windowsフォームアプリケーションにドラッグ&ドロップ機能を実装する方法を紹介します。

ドラッグ&ドロップに関するイベントハンドラ

 あるコントロールから別のコントロールにオブジェクトをドラッグ&ドロップする方法を理解するには、いくつかのイベントハンドラについて理解しておく必要があります。図1の例を見てください。これは、PictureBoxコントロールに表示された画像を別のPictureBoxコントロールにドラッグするところを示しています。

図1 PictureBoxコントロールから別のPictureBoxコントロールに画像をドラッグする
図1 PictureBoxコントロールから別のPictureBoxコントロールに画像をドラッグする
 ドラッグ&ドロップ機能を実装するには、両方のコントロールに対するコードを記述します。

ドラッグするコントロールのコード

 ドラッグしようとするデータのロード処理の起点は、通常はMouseDownまたはMouseMoveイベントになります。図1の例では、このどちらかのイベントで、左側のPictureBoxコントロールに格納されている画像をクリップボードにコピーします。

 ドラッグ操作の結果、つまり、ユーザーが最終的にアイテムをドロップしたかどうかは、QueryContinueDragイベントで知ることができます。移動を目的とするドラッグ操作をユーザーが正しくやり遂げた場合は、左側のPictureBoxコントロールにある画像を削除する必要があるでしょう。

 ドラッグ元のコントロールは、ドラッグ操作の間はGiveFeedBackイベントを送出し続けます。マウスポインタの外観を変更したい場合は、このイベントで処理できます。

ドロップを受け入れるコントロールのコード

 ドロップを受け入れるコントロールの領域にマウスが入ると、そのコントロールはDragEnterイベントを送出します。通常は、このイベントのイベントハンドラに、実行中の処理(コピーや移動など)を反映するようにマウスポインタの形状を変化させるコードを記述します。さらに、そのコントロールの外観を変化させて、ドロップ先であることがすぐに分かるようにすることもできます。

 ドロップを受け入れるコントロールの上にマウスがとどまっている間、そのコントロールはDragOverイベントを送出します。このイベントは、ターゲットのコントロール上にマウスがある間はずっと発生し続けます。このイベントまたはDragEnterイベントを使用して、マウスポインタの外観を変更できます。

 ドロップを受け入れるコントロールからマウスが離れると、そのコントロールはDragLeaveイベントを送出します。DragEnterイベントでコントロールの外観を変更していた場合は、通常はこのイベントのイベントハンドラで元に戻します。

 ドロップを受け入れるコントロールの上でオブジェクトをドロップすると、DragDropイベントが発生するので、このイベントを適切に処理します。図1の例では、左側のコントロールからドラッグした画像を、右側のPictureBoxコントロールにロードすることになります。

 ここで説明した一連のイベントが、すべてのコントロールでサポートされているわけではないことに注目してください。例えば、RichTextBoxコントロールはDragOverイベントをサポートしません。従って、ドラッグ&ドロップを検知するには、DragEnterイベントなど、サポートされている別のイベントを使用する必要があります。

 また、ほとんどのコントロールでは、デザイン時にプロパティウィンドウでAllowDropプロパティを設定できます。しかし、いくつかのコントロール(PictureBoxコントロールなど)では、プロパティウィンドウにAllowDropプロパティが表示されません。従って、コードの中で動的に設定する必要があります。さらに、Visual Studioの入力支援機能(インテリセンス)でAllowDropプロパティが表示されないことにも注意してください。

編者注
 この記事の初出はCoDe Magazineの2008年3月/4月号で、本稿では許可を得て再掲しています。

テキストのドラッグ&ドロップ

 以降では、ドラッグ&ドロップを実装するサンプルアプリケーションを実際に作成してみます。Visual Studio 2005でWindowsフォームアプリケーションを新規作成し、「DragAndDrop」という名前を付けます。ドラッグ&ドロップ処理のコーディングは、使用するコントロールやデータタイプによって若干異なります。この節では、テキストをTextBoxコントロールにドラッグ&ドロップする方法を紹介します。

 デフォルトのForm1にTextBoxコントロールを配置し(図2を参照)、TextBoxコントロールの次の2つのプロパティを設定します。

cap
プロパティ名設定値
MultilineTrue
BorderStyleFixed3D
図2 Form1のTextBoxコントロール
図2 Form1のTextBoxコントロール
 Form1のコードビューに切り替えて、次の定数を宣言します。

Public Class Form1
  Const CtrlMask As Byte = 8
 Form1_Loadイベントで、TextBoxAllowDropプロパティをTrueに設定します。

Private Sub Form1_Load( _
  ByVal sender As System.Object, _
  ByVal e As System.EventArgs) _
  Handles MyBase.Load

  '---set the control to allow drop---
  TextBox1.AllowDrop = True
End Sub
 次に、DragEnterイベントのコードを記述します。前述したように、コントロールに何かをドラッグすると、このイベントが発生します。ここで、このドラッグ操作がコピーなのか移動なのかをCtrlキーの押下状態に基づいて判断し、その結果に応じてマウスポインタを設定します。この特殊なキーストロークをチェックするには、KeyStateプロパティとCtrlMask(1バイトのマスク定数、値は8)をAND演算します。さらに、ユーザーのための視覚的なヒントとなるように、TextBoxコントロールの境界線のスタイルをFixedSingleに変更します。コードは次のとおりです。

Private Sub TextBox1_DragEnter( _
  ByVal sender As Object, _
  ByVal e As _
     System.Windows.Forms.DragEventArgs) _
     Handles TextBox1.DragEnter
  '---if the data to be dropped is a text format---
  If (e.Data.GetDataPresent(DataFormats.Text)) Then
     '---determine if this is a copy or move---
     If (e.KeyState And CtrlMask) = CtrlMask Then
        e.Effect = DragDropEffects.Copy
     Else
        e.Effect = DragDropEffects.Move
     End If
     '---change the border style of the control---
     TextBox1.BorderStyle = BorderStyle.FixedSingle
  End If
End Sub
 ドラッグしたテキストがドロップされたときの処理は、DragDropイベントに記述します。コードは次のとおりです。

Private Sub TextBox1_DragDrop( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms.DragEventArgs) _
  Handles TextBox1.DragDrop

  '---if the data to be dropped is a text format---
  If (e.Data.GetDataPresent(DataFormats.Text)) Then
     '---set the control to display
     ' the text being dropped---
     TextBox1.Text = e.Data.GetData( _
        DataFormats.Text)
  End If
  '---set the borderstyle back to its original---
  TextBox1.BorderStyle = BorderStyle.Fixed3D
End Sub
 この時点で、F5キーを押してアプリケーションをテストできます。図3は、ユーザーがTextBoxコントロール上で移動またはコピーの操作を行う際のマウスポインタを示しています。コピー操作を行うには、マウスをドラッグする際にCtrlキーを押したままにするだけです。図4は、ドロップを受け入れない領域にオブジェクトをドラッグした場合のポインタを示しています(図の下側)。

図3 移動時(上)とコピー時(下)のマウスポインタ
図3 移動時(上)とコピー時(下)のマウスポインタ
図4 コントロールの外にドラッグ
図4 コントロールの外にドラッグ
 テキストをドラッグ&ドロップする方法を覚えたところで、次はPictureBoxコントロール間で画像をドラッグ&ドロップする方法を見ていきましょう。

画像のドラッグ&ドロップ(1)

 同じプロジェクトを使用して、デフォルトのForm1にPictureBoxコントロールをドラッグ&ドロップします(図5を参照)。

図5 Form1に^^PictureBox^^コントロールを追加
図5 Form1に^^PictureBox^^コントロールを追加
 Form1_Loadイベントで、PictureBoxコントロールのプロパティを次のように設定します。

Private Sub Form1_Load( _
  ByVal sender As System.Object, _
  ByVal e As System.EventArgs) _
  Handles MyBase.Load

  '---set the control to allow drop---
  TextBox1.AllowDrop = True
  '---set the control to allow drop---
  With PictureBox1
     .AllowDrop = True
     .BorderStyle = BorderStyle.FixedSingle
     .SizeMode = PictureBoxSizeMode.StretchImage
  End With
  ...

ドロップの実装

 前の例と同じように、マウスがPictureBoxコントロール上にあるときはマウスポインタが適切に変更されるように、DragEnterイベントにコードを記述します。今回の処理で1つだけ異なるのは、PictureBoxコントロールにドロップされるデータのタイプが画像かどうかをチェックする点です。

Private Sub PictureBox1_DragEnter( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms. _
  DragEventArgs) _
  Handles PictureBox1.DragEnter

  '---if the data to be dropped is an image format---
  If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
     '---determine if this is a copy or move---
     If (e.KeyState And CtrlMask) = CtrlMask Then
        e.Effect = DragDropEffects.Copy
     Else
        e.Effect = DragDropEffects.Move
     End If
     '---change the border style of the control---
     PictureBox1.BorderStyle = BorderStyle.Fixed3D
  End If
End Sub
 DragDropイベントでは、まず、ドロップされたオブジェクトのタイプが画像であることを確認します。画像である場合は、ドロップされた画像をPictureBoxコントロールに割り当てます。

Private Sub PictureBox1_DragDrop( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms. _
  DragEventArgs) _
  Handles PictureBox1.DragDrop

  '---if the data to be dropped is a bitmap format---
  If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
     '---set the control to display
     ' the text being dropped---
     PictureBox1.Image = e.Data.GetData( _
        DataFormats.Bitmap)

  End If
  '---set the border style back to its original---
  PictureBox1.BorderStyle = BorderStyle.FixedSingle
End Sub
 最後にDragLeaveイベントで、PictureBoxの境界線のスタイルを元のスタイルに変更します。

Private Sub PictureBox1_DragLeave( _
  ByVal sender As Object, _
  ByVal e As System.EventArgs) _
  Handles PictureBox1.DragLeave
  '---set the borderstyle back to
  ' its original---
  PictureBox1.BorderStyle = _
     BorderStyle.FixedSingle
End Sub
 F5キーを押してアプリケーションをテストします。Microsoft Wordから画像をドラッグしてPictureBoxコントロールにドロップすると、その画像が表示されます。面白いことに、ワードパッドから画像をドラッグ&ドロップしてもPictureBoxに画像は表示されません。これについては後ほど説明します。

ドラッグの実装

 PictureBoxコントロールに表示された画像を別の場所、例えば別のコントロールやMicrosoft Word(またはワードパッド)にドラッグできるようにするには、もう少しコードを追加する必要があります。

 まず、MouseDownイベントハンドラに次のコードを記述します。PictureBoxコントロールの画像をクリックすると、このイベントが発生します。

Private Sub PictureBox1_MouseDown( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms. _
  MouseEventArgs) _
  Handles PictureBox1.MouseDown
  If PictureBox1.Image IsNot _
     Nothing Then
     PictureBox1.DoDragDrop( _
        PictureBox1.Image, _
        DragDropEffects.Move Or _
        DragDropEffects.Copy)
  End If
End Sub
 このコードでは、PictureBoxコントロールに表示された画像をコピーするために、PictureBoxコントロールのDoDragDrop()メソッドを使用します。このメソッドの2番目のパラメータには、生じる可能性のあるドラッグ操作のタイプ(ここでは移動またはコピー)を指定します。

 作業はこれで完了です。この時点で、PictureBoxコントロールに表示された画像を別のコントロールにドラッグ&ドロップできるようになります。今度は、画像をワードパッド上にドラッグできることが分かるはずです。ただし、先ほどとは逆に、Microsoft Word上にはドラッグできません。

 ここまでのアプリケーションの動作をまとめてみましょう。

  • Microsoft Wordから画像をドラッグして、PictureBoxコントロールにドロップできます。しかし、ワードパッドからドラッグ&ドロップすることはできません。
  • PictureBoxコントロールからWord上に画像をドラッグしても、Wordは画像を受け入れません。しかし、同じ画像をワードパッド上にドラッグ&ドロップできます。
 なぜWordからは画像をドロップできて、ワードパッドからはできないのでしょうか。その理由を理解するために、アプリケーションに少し手を加えて、ドロップ操作によってPictureBoxコントロールに渡されるデータのタイプを具体的に確認できるようにしましょう。

画像のドラッグ&ドロップ(2)

さまざまなデータタイプのハンドリング

 作成済みのDragEnterイベントに、次の太字で示した行を追加します。GetFormats()メソッドは、イベントに渡されるデータのタイプを返します。

Private Sub PictureBox1_DragEnter( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms.DragEventArgs) _
  Handles PictureBox1.DragEnter

  Dim formats As String() = e.Data.GetFormats
  '---if the data to be dropped is an image format---
  If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
     ...
 イベントに渡されるデータのタイプを監視するために、ここで追加した行の後にブレークポイントを設定します。F5キーを押してアプリケーションをデバッグ実行し、WordからPictureBoxコントロールに画像をドロップしてみましょう。図6は、Wordからドラッグ&ドロップされた画像のデータタイプを示しています。

図6 Wordからドロップされた画像のデータタイプを調べる
図6 Wordからドロップされた画像のデータタイプを調べる
 この図から、考えられるフォーマットの1つがビットマップであることが分かります。従って、データを無事にビットマップ画像に変換して、PictureBoxコントロールに表示できます。これに対して、ワードパッドから画像をドラッグ&ドロップしたときのデータタイプは図7のように示されます。

図7 ワードパッドからドロップされた画像のデータタイプを調べる
図7 ワードパッドからドロップされた画像のデータタイプを調べる
 今度は、画像データがビットマップ形式で渡されていません。その代わりに、RTF(リッチテキストフォーマット)で渡されています。

 従って、ワードパッドからドラッグ&ドロップされた画像をPictureBoxコントロールで受け取れるようにするには、ビットマップだけでなくRTFも受けつけるようにDragEnterイベントを変更する必要があります。

Private Sub PictureBox1_DragEnter( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms. _
  DragEventArgs) _
  Handles PictureBox1.DragEnter

  Dim formats As String() = e.Data.GetFormats
  '---if the data to be dropped is an image format---
  If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
     '---determine if this is a copy or move---
     If (e.KeyState And CtrlMask) = CtrlMask Then
        e.Effect = DragDropEffects.Copy
     Else
        e.Effect = DragDropEffects.Move
     End If
     '---change the border style of the control---
     PictureBox1.BorderStyle = BorderStyle.Fixed3D
  ElseIf (e.Data.GetDataPresent(DataFormats.Rtf)) Then
     '---determine if this is a copy or move---
     If (e.KeyState And CtrlMask) = CtrlMask Then
        e.Effect = DragDropEffects.Copy
     Else
        e.Effect = DragDropEffects.Move
     End If
     '---change the border style of the control---
     PictureBox1.BorderStyle = BorderStyle.Fixed3D
  End If
End Sub
 さらに、DragDropイベントを修正して、このデータフォーマットを処理するカスタムコードを記述します。

Private Sub PictureBox1_DragDrop( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms. _
  DragEventArgs) _
  Handles PictureBox1.DragDrop

  '---if the data to be dropped is a image format---
  If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
     '---set the control to display
     ' the text being dropped---
     PictureBox1.Image = e.Data.GetData( _
        DataFormats.Bitmap)
  ElseIf (e.Data.GetDataPresent(DataFormats.Rtf)) Then
     '---display the rich text---
     Console.WriteLine( _
        e.Data.GetData(DataFormats.Rtf))
  End If
  '---set the borderstyle back to its original---
  PictureBox1.BorderStyle = BorderStyle.FixedSingle
End Sub
 残念ながら、このコードで行っているのは、画像データを単にRTFとしてコンソールウィンドウに書き出すことだけです(図8を参照)。PictureBoxコントロールに実際の画像を表示するには、画像データを抽出するコードを記述する必要があります。

編集部注
 編集部で稼動テストをしたところ、デバッグモードでワードパッドからのドラッグ&ドロップをするとフリーズしてしまうことがありました。ビルド済みの実行モジュールを利用した方が良いかもしれません。
図8 RTFの内容を出力
図8 RTFの内容を出力

画像のドラッグ&ドロップ(3)

コピーと移動の違い

 先ほどの例では、PictureBoxコントロールから画像をコピーしたり移動したりする方法を紹介しました。通常の移動処理では、別のコントロールや別の場所に画像をコピーした後、元の画像を削除する必要があります。では、ドロップ操作が完了したタイミングを知るにはどうしたらいいのでしょうか。それにはQueryContinueDragイベントを使用します。

 図9のように、Form1にPictureBoxコントロールをもう1つ追加します。これを使用して、PictureBox1からPictureBox2に画像をドラッグ&ドロップで移動するサンプルを作成していきます。

図9 Form1の2つのPictureBoxコントロール
図9 Form1の2つのPictureBoxコントロール
 Form1_LoadイベントでPictureBox2を次のように設定します。

Private Sub Form1_Load( _
  ByVal sender As System.Object, _
  ByVal e As System.EventArgs) _
  Handles MyBase.Load
  '---set the control to allow drop---
  TextBox1.AllowDrop = True
  '---set the control to allow drop---
  With PictureBox1
     .AllowDrop = True
     .BorderStyle = BorderStyle.FixedSingle
     .SizeMode = PictureBoxSizeMode.StretchImage
  End With
  '---set the control to allow drop---
  With PictureBox2
     .AllowDrop = True
     .BorderStyle = BorderStyle.FixedSingle
     .SizeMode = PictureBoxSizeMode.StretchImage
  End With
  ...
 ドロップをサポートするため、リスト1のコードをPictureBox2に追加します。

リスト1
Private Sub PictureBox2_DragDrop( _
   ByVal sender As Object, _
   ByVal e As System.Windows.Forms. _
   DragEventArgs) _
   Handles PictureBox2.DragDrop

   '---if the data to be dropped is a bitmap format---
   If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
      '---set the control to display
      ' the bitmap being dropped---
      PictureBox2.Image = e.Data.GetData( _
         DataFormats.Bitmap)
   End If
   '---set the borderstyle back to its original---
   PictureBox2.BorderStyle = BorderStyle.FixedSingle
End Sub

Private Sub PictureBox2_DragEnter( _
   ByVal sender As Object, _
   ByVal e As System.Windows.Forms. _
   DragEventArgs) _
   Handles PictureBox2.DragEnter

   '---if the data to be dropped is an image format---
   If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
      '---determine if this is a copy or move---
      If (e.KeyState And CtrlMask) = CtrlMask Then
         e.Effect = DragDropEffects.Copy
      Else
         e.Effect = DragDropEffects.Move
      End If
      '---change the border style of the control---
      PictureBox2.BorderStyle = BorderStyle.Fixed3D
   End If
End Sub

Private Sub PictureBox2_DragLeave( _
   ByVal sender As Object, _
   ByVal e As System.EventArgs) _
   Handles PictureBox2.DragLeave

   '---set the borderstyle back to its original---
   PictureBox2.BorderStyle = BorderStyle.FixedSingle
End Sub
 移動操作では、ユーザーがPictureBox2に画像を移動させた後、PictureBox1の画像を削除しなければなりません。この処理のために、PictureBox1QueryContinueDragイベントにコードを記述する必要があります。このイベントは、PictureBox1から画像をドラッグ&ドロップした後に発生します。そのイベントコードの中で、行ったドラッグ操作が移動かどうかを判断し、移動である場合はPictureBox1から画像を削除します。

Private Sub PictureBox1_QueryContinueDrag( _
  ByVal sender As Object, _
  ByVal e As _
  System.Windows.Forms.QueryContinueDragEventArgs) _
  Handles PictureBox1.QueryContinueDrag

  If e.Action = DragAction.Drop Then
     If (e.KeyState And CtrlMask) <> CtrlMask Then
        '---a move operation---
        PictureBox1.Image = Nothing
     End If
  End If
End Sub
 ここでコードをテストできます。Visual Studio 2005のF5キーを押して、PictureBox1に画像をドラッグ&ドロップします。次に、PictureBox1の中にある画像をドラッグして、PictureBox2にドロップします。ドロップ後、PictureBox1の中の画像がなくなることに注目してください。移動ではなくコピーを行った場合、つまりCtrlキーを押したままPictureBox1からPictureBox2まで画像をドラッグした場合は、QueryContinueDragイベントのコードでは画像をコピーするだけで、削除しません。

 1つ注意してほしいのは、ユーザーが移動させたアイテムをQueryContinueDragイベントで削除するという手法は、フールプルーフな方法ではないという点です。移動操作が失敗した場合(PictureBox2の外に画像をドロップした場合など)でも、画像の削除が実行されてしまいます。QueryContinueDragイベントを使用する方法では、ユーザーがアイテムをどこに移動したか(またはドロップしたか)や、操作が失敗したかどうかは分かりません。

ファイルのドラッグ&ドロップ

 Windowsアプリケーション共通の操作の一つに、アプリケーション上にファイルをドラッグ&ドロップする操作があります。例えば、フォルダ上にファイルをドラッグ&ドロップしたり、Windows Media Player上に音楽ファイルをドラッグして再生したことがあるのではないでしょうか。

 サンプルアプリケーションに手を加えて、ユーザーがWindowsエクスプローラから画像ファイルをドラッグして、PictureBoxコントロールにドロップできるようにしましょう。そのためには次の2つのステップが必要です。

  • まず、DragEnterイベントを修正します(リスト2を参照)。WindowsエクスプローラからドラッグされるファイルのデータタイプはFileDropです。従って、リスト2のコードでは、このデータタイプをDragEnterイベントハンドラでチェックします。
  • 次に、DragDropイベントをリスト3のように変更し、画像ファイルを開いてその内容をPictureBoxコントロールに表示できるようにします。
リスト2
Private Sub PictureBox1_DragEnter( _
   ByVal sender As Object, _
   ByVal e As System.Windows.Forms. _
   DragEventArgs) _
   Handles PictureBox1.DragEnter

   Dim formats As String() = e.Data.GetFormats
   '---if the data to be dropped is an image format---
   If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
      '---determine if this is a copy or move---
      If (e.KeyState And CtrlMask) = CtrlMask Then
         e.Effect = DragDropEffects.Copy
      Else
         e.Effect = DragDropEffects.Move
      End If
      '---change the border style of the control---
      PictureBox1.BorderStyle = BorderStyle.Fixed3D
   ElseIf (e.Data.GetDataPresent( _
      DataFormats.FileDrop)) Then
      '---if this is a file drop---
      e.Effect = DragDropEffects.All
   ElseIf (e.Data.GetDataPresent( _
      DataFormats.Rtf)) Then
      '---determine if this is a copy or move---
      If (e.KeyState And CtrlMask) = CtrlMask Then
         e.Effect = DragDropEffects.Copy
      Else
         e.Effect = DragDropEffects.Move
      End If
      '---change the border style of the control---
      PictureBox1.BorderStyle = BorderStyle.Fixed3D
   End If
End Sub
リスト3
Private Sub PictureBox1_DragDrop( _
   ByVal sender As Object, _
   ByVal e As System.Windows.Forms.DragEventArgs) _
   Handles PictureBox1.DragDrop

   '---if the data to be dropped is a image format---
   If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then
      '---set the control to
      ' display the bitmap being dropped---
      PictureBox1.Image = e.Data.GetData( _
         DataFormats.Bitmap)
   ElseIf (e.Data.GetDataPresent( _
      DataFormats.FileDrop)) Then
      Dim files() As String
      files = e.Data.GetData( _
         DataFormats.FileDrop)
      For Each file As String In files
         file = UCase(file)
         If file.EndsWith(".GIF") Or _
            file.EndsWith(".JPG") Or _
            file.EndsWith(".BMP") Then
            PictureBox1.Image = New Bitmap(file)
         End If
         System.Threading.Thread.Sleep(2000)
            Application.DoEvents()
      Next
   ElseIf (e.Data.GetDataPresent(DataFormats.Rtf)) Then
      '---display the rich text---
      Console.WriteLine(e.Data.GetData( _
         DataFormats.Rtf))
   End If
   '---set the borderstyle back to its original---
   PictureBox1.BorderStyle = BorderStyle.FixedSingle
End Sub
 必要な作業はこれだけです。これで、Windowsエクスプローラから画像ファイルをドラッグしてPictureBoxコントロールにドロップし、その内容を表示できます。今回変更したコードでは、PictureBoxコントロールに1つまたは複数のファイルをドロップできることに注意してください。複数ファイルをドロップした場合、それぞれの画像が2秒間隔で1つずつ表示されます。

特別なコントロールにドラッグ&ドロップを実装

 ほとんどのWindows Formsコントロールは、この記事で説明したドラッグ&ドロップ操作のためのイベント一式(またはその一部)をサポートします。しかし、ドラッグ&ドロップを可能にしたいコントロールが、標準的なイベントをサポートしていない場合はどうすればよいでしょうか。良い例がWindows Media Player ActiveXコントロールです。WindowsアプリケーションにWindows Media Playerコントロールを埋め込めばユーザーがメディアファイルをドラッグ&ドロップしただけで再生できるようになると思うかもしれませんが、残念ながら、Windows Media Player ActiveXコントロールはDragEnterDragDropのようなイベントをサポートしていません。従って、直接ドラッグ&ドロップを実装する簡単な方法はありません。

 この問題に対処するには、ユーザーコントロールを使用してActiveXコントロールをラッピングします。そのためには、現在のプロジェクトにユーザーコントロールを新たに追加します(ソリューションエクスプローラでプロジェクト名を右クリックして[Add]→[New Item]を選択して、[User Control]を選択)。そのファイルに「MediaPlayer.vb」という名前を付けます。

 ツールボックスにWindows Media Playerを追加します。そのためには、ツールボックスを右クリックして、[Choose Items]を選択します。[Choose Toolbox Items]ダイアログボックスで、[COM Components]タブをクリックして、[Windows Media Player]のチェックボックスをオンにします(図10を参照)。[OK]をクリックすると、ツールボックスにWindows Media Playerコントロールが追加されます。

図10 ツールボックスにWindows Media Player ActiveXコントロールを追加
図10 ツールボックスにWindows Media Player ActiveXコントロールを追加
 ツールボックスからWindows Media Playerコントロールをドラッグして、MediaPlayer.vbのデザイン画面上にドロップします(図11を参照)。

図11 ユーザーコントロールにWindows Media Playerコントロールを配置
図11 ユーザーコントロールにWindows Media Playerコントロールを配置
 これで、MediaPlayerユーザーコントロールがツールボックスに表示されるはずです(図12を参照)。

図12 MediaPlayerユーザーコントロール
図12 MediaPlayerユーザーコントロール
 Form1MediaPlayerユーザーコントロールをドラッグ&ドロップします(図13を参照)。

図13 Form1にMediaPlayerコントロールを追加
図13 Form1にMediaPlayerコントロールを追加
 MediaPlayer.vbのコードビューで、次のコードを追加します。

Public Class MediaPlayer
Private _URL As String
  Public Property URL() As String
     Get
        Return _URL
     End Get
     Set(ByVal value As String)
        _URL = value
        AxWindowsMediaPlayer1. _
           URL = _URL
     End Set
  End Property
End Class
 原則的に、再生するメディアファイルのURLはユーザーに設定させるため、URLプロパティを公開します。

 Form1のコードビハインド(分離コード)に移って、MediaPlayerユーザーコントロールのDragEnterイベントに次のようなコードを記述します。

Private Sub MediaPlayer1_DragEnter( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms.DragEventArgs) _
  Handles MediaPlayer1.DragEnter
  '---if the data to be dropped is
  ' an filedrop format---
  If (e.Data.GetDataPresent( _
     DataFormats.FileDrop)) Then
     '---determine if this is a copy or move---
     If (e.KeyState And CtrlMask) = CtrlMask Then
        e.Effect = DragDropEffects.Copy
     Else
        e.Effect = DragDropEffects.Move
     End If
  End If
End Sub
 最後に、ユーザーがドロップしたメディアファイルを再生するためのコードをDragDropイベントに記述します。

Private Sub MediaPlayer1_DragDrop( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Forms. _
  DragEventArgs) _
  Handles MediaPlayer1.DragDrop

  If (e.Data.GetDataPresent( _
     DataFormats.FileDrop)) Then
     Dim files() As String
     '---get all the file names---
     files = e.Data.GetData( _
        DataFormats.FileDrop)
     If files.Length > 0 Then
        '---load only the first file---
        files(0) = UCase(files(0))
        If files(0).EndsWith(."WMV") Then
           '---get the media player to play the
           ' first file---
           MediaPlayer1.URL = files(0)
        End If
     End If
  End If
End Sub
編集部注
 Form1のロード時にMediaPlayer1のAllowDropプロパティの値もTrueにしておく必要があります。手順は、TextBox1やPictureBox1、2と同様です。
 このコントロールには複数のファイルをドロップできるので、MediaPlayerコントロールでは最初のファイルだけをロードする点に注意してください。

 図14は、Windowsフォームの中にあるMediaPlayerコントロールが、ドロップされたファイルを再生しているところを示しています。

図14 Form1にメディアファイルをドラッグ&ドロップした結果
図14 Form1にメディアファイルをドラッグ&ドロップした結果

カスタムオブジェクトのドラッグ&ドロップ

 ここまで、DataFormatsクラスで規定されているさまざまなデータタイプのうち、いくつかの使用法を見てきました。DataFormatsクラスで規定されているデータタイプには、BitmapCommaSeparatedValueDibDifEnhancedMetafileFileDropHtmlLocaleMetafilePictOemTextPalettePenDataRiffRtfSerializableStringFormatSymbolicLinkTextTiffUnicodeTextWaveAudioなどがあります。しかし、ここにリストされていないタイプのデータをドラッグ&ドロップしたい場合はどうなるでしょうか。例えば、ListViewコントロールからアイテムをドラッグしたいと思うかもしれません。この場合、DragEnterイベントは次のようになります。

If (e.Data.GetDataPresent _
  ("System.Windows.Forms. _
  ListViewItem()")) Then
  '---determine if this is a copy
  '---or move---
  If (e.KeyState And CtrlMask) =
     CtrlMask Then
     e.Effect =
     DragDropEffects.Copy
  Else
     e.Effect =
     DragDropEffects.Move
  End If
 また、MouseDownイベントハンドラは次のようになります。

Control.DoDragDrop(New _
  DataObject("System.Windows.Forms. _
  ListViewItem()", Items), _
  DragDropEffects.Move Or _
  DragDropEffects.Copy)
 ご覧のように、Windowsアプリケーションにドラッグ&ドロップ機能を実装するのは、それほど難しくありません。必要なのは、サポートしたいデータのタイプを理解し、その特定のデータタイプを処理するのに必要な準備をすることです。

著者紹介

Wei-Meng Lee(Wei-Meng Lee)
Microsoft MVP受賞者。Microsoft社の最新テクノロジー実地研修を専門とするDeveloper Learning Solutions社を創設。.NETとワイヤレステクノロジーの開発者、指導者として知られる。
国際的なカンファレンスでたびたび講演し、.NET、XML、ワイヤレステクノロジーに関する著書、共著書多数。.NETからMac OS Xに至るまで広範な分野について執筆している。著書に『.NET Compact Framework Pocket Guide』 (Oreilly&Associates Inc、2005年5月)、『ASP.NET 2.0: A Developer's Notebook』 (Oreilly&Associates Inc、2005年6月)、『Programming Sudoku』 (Apress刊、2006年3月)など。ブログ「Wei-Meng Lee's Blog」を開設している。
【関連記事】
定期実行する.NETコンソールアプリケーションの作成
MOVIDA など4社、Lotus Notes モバイル化で業務提携
『Windows』マシンで『Solaris』用アプリケーションの実行が可能に
ドラッグ&ドロップで検索や画像保存ができる Sleipnir プラグイン「SuperDrag Extension」
Serena Mashup Composer でマッシュアップをウィジェットとして提供

New Topics

Special Ad

ゆりかごからロケットまで、すべての乗り物をエンジョイ
ゆりかごからロケットまで、すべての乗り物をエンジョイ えん乗り」は、ゆりかごからロケットまで、すべての乗り物をエンジョイする、ニュース、コラム、動画などをお届けします! てんこ盛りをエンジョイするのは こちらから

Hot Topics

IT Job

Interviews / Specials

Popular

Access Ranking

Partner Sites