この記事の英語版を表示するには、[英語] のチェック ボックスをオンにしてください。また、テキストにマウス ポインターを合わせると、ポップアップ ウィンドウに英語のテキストを表示することもできます。
翻訳
英語

ドラッグ アンド ドロップの概要

 

公開日: 2016年6月

このトピックでは、Windows Presentation Foundation (WPF) アプリケーションでのドラッグ アンド ドロップのサポートの概要について説明します。 一般的に、ドラッグ アンド ドロップとは、マウス (または何らかのポインティング デバイス) を使用して 1 つ以上のオブジェクトを選択し、これらのオブジェクトを ユーザー インターフェイス (UI) の目的のドロップ先までドラッグしてからドロップするデータ転送方式をいいます。

ドラッグ アンド ドロップ操作には、一般に、ドラッグするオブジェクトがドラッグを始めるドラッグ元と、ドロップするオブジェクトを受け取るドロップ先という 2 者があります。 ドラッグ元とドロップ先は、同じアプリケーションまたは異なるアプリケーションの UI 要素になることがあります。

ドラッグ アンド ドロップで操作できるオブジェクトの種類と数は、まったく任意です。 たとえば、ファイル、フォルダー、およびコンテンツの選択項目は、ドラッグ アンド ドロップ操作を介して操作する、より一般的なオブジェクトの一部です。

ドラッグ アンド ドロップ操作中に実行される特定の操作はアプリケーション固有で、多くの場合コンテキストによって決定されます。 たとえば、同じストレージ デバイスで選択したファイルをあるフォルダーから別のフォルダーにドラッグすると、既定ではファイルが移動します。一方、汎用名前付け規則 (UCS) 共有からローカル フォルダーにファイルをドラッグすると、既定ではファイルがコピーされます。

WPF が提供するドラッグ アンド ドロップ機能は、さまざまなドラッグ アンド ドロップのシナリオをサポートするよう、非常に柔軟かつカスタマイズできるように設計されています。 ドラッグ アンド ドロップでは、1 つのアプリケーション内で、または異なるアプリケーションの間でのオブジェクトの操作をサポートします。 WPF アプリケーションと他の Windows アプリケーションの間でのドラッグ アンド ドロップも完全にサポートされています。

WPF では、任意の UIElement または ContentElement がドラッグ アンド ドロップに参加できます。 ドラッグ アンド ドロップ操作に必要なイベントとメソッドは、DragDrop クラスで定義されています。 UIElementContentElement クラスには、DragDrop のアタッチ済みのイベントのエイリアスが含まれています。これにより、UIElementContentElement が基本要素として継承されるときに、イベントがクラスのメンバーとして表示されます。 これらのイベントにアタッチされたイベント ハンドラーは、基になる DragDrop のアタッチ済みのイベントにアタッチされ、同じイベント データのインスタンスを受信します。 詳細については、UIElement.Drop イベントを参照してください。

System_CAPS_security セキュリティ メモ

OLE のドラッグ アンド ドロップは、インターネット ゾーンにある間は機能しません。

ドラッグ アンド ドロップは、より一般的な領域のデータ転送の一部です。 データ転送には、ドラッグ アンド ドロップ操作およびコピーと貼り付けの操作があります。 ドラッグ アンド ドロップ操作は、システムのクリップボードを使用して、あるオブジェクトまたはアプリケーションから別のオブジェクトまたはアプリケーションへのデータ転送に使用する、コピーと貼り付け操作または切り取りと貼り付け操作に似ています。 いずれの種類の操作でも、次のものが必要です。

  • データを提供するソース オブジェクト。

  • 転送されたデータを一時的に格納する方法。

  • データを受け取るターゲット オブジェクト。

コピーと貼り付け操作では、システムのクリップボードを使用して、転送されたデータを一時的に保存します。ドラッグ アンド ドロップ操作では、DataObject を使用してデータを格納します。 データ オブジェクトは、概念的に、実際のデータと対応するデータ形式の識別子を格納する 1 組以上の Object で構成されています。

ドラッグ元では、静的な DragDrop.DoDragDrop メソッドを呼び出して、転送するデータをそのメソッドに渡すことでドラッグ アンド ドロップ操作を開始します。 必要な場合、DoDragDrop メソッドは DataObject にデータを自動的にラップします。 データ形式の制御を拡大するには、データを DoDragDrop メソッドに渡す前に DataObject にラップします。 ドロップ先は、DataObject からデータを抽出する役割を務めます。 データ オブジェクトの操作の詳細については、「データとデータ オブジェクト」を参照してください。

ドラッグ アンド ドロップ操作のソースとターゲットは UI 要素ですが、一般に、実際に転送されているデータには視覚的表現はありません。 Windows エクスプローラーでファイルをドラッグするときに起こるような視覚的表現を、ドラッグするデータで実行するように、コードを記述することができます。 既定では、データを移動するのかコピーするのかなど、ドラッグ アンド ドロップ操作によりデータに起こる効果を表すようにカーソルを変更して、ユーザーにフィードバックします。

ドラッグ アンド ドロップ操作には、転送するデータにさまざまな効果を持たせることができます。 たとえば、データをコピーしたり、データを移動したりできるなどです。 WPF では、ドラッグ アンド ドロップ操作の効果を指定するために使用できる DragDropEffects 列挙体を定義します。 ドラッグ元では、ソースが DoDragDrop メソッドで許可する効果を指定できます。 ドロップ先では、DragEventArgs クラスの Effects プロパティでターゲットの目的の効果を指定できます。 DragOver イベントでドロップ先の目的の効果を指定した場合、その情報が GiveFeedback イベントのドラッグ元に渡されます。 ドラッグ元では、この情報を使用して、ドロップ先がデータにどのような効果を起こそうとしているかをユーザーに伝えます。 データがドロップされると、ドロップ先では Drop イベントでの実際の効果を指定します。 この情報は、DoDragDrop メソッドの戻り値としてドラッグ元に渡されます。 ドラッグ元の allowedEffects の一覧にない効果をドロップ先が返す場合、ドラッグ アンド ドロップ操作は取り消され、データ転送は発生しません。

WPF では、ドラッグ アンド ドロップ操作の効果に関しては、DragDropEffects 値はドラッグ元とドロップ先間の通信にのみ使用されるということを覚えておくのは重要です。 ドラッグ アンド ドロップ操作の実際の効果は、アプリケーションで適切なコードを記述することに依存します。

たとえば、ドロップ先では、ドロップ先にデータをドロップすることはデータが移動することと指定される可能性があります。 ただし、データを移動するには、データがターゲット要素に追加されるとともに、ソース要素から削除される必要があります。 ソース要素は、データの移動を許可していますが、ソース要素からデータを削除するコードを指定しない場合、最終的にデータは移動ではなく、コピーされるという結果になります。

ドラッグ アンド ドロップの操作は、イベント ドリブン モデルをサポートしています。 ドラッグ元とドロップ先の両方でイベントの標準セットを使用して、ドラッグ アンド ドロップの操作を処理します。 次の表は、標準のドラッグ アンド ドロップのイベントをまとめたものです。 これらは、DragDrop クラスでアタッチされるイベントです。 アタッチされるイベントの詳細については、「添付イベントの概要」を参照してください。

イベント

概要

GiveFeedback

このイベントは、ドラッグ アンド ドロップ操作中に継続的に発生し、ドロップ ソースがユーザーに情報をフィードバックできるようにします。 このフィードバックは、通常、マウス ポインターの外観を変えて、ドロップ先が許可する効果を示すことで実行されます。 これは、 バブリング イベントです。

QueryContinueDrag

このイベントは、ドラッグ アンド ドロップ操作時にキーボードやマウス ボタンの状態が変化し、ドロップ ソースがキーやボタンの状態によってドラッグ アンド ドロップ操作の取り消しができるようになったときに発生します。 これは、 バブリング イベントです。

PreviewGiveFeedback

トンネリング バージョンの GiveFeedback です。

PreviewQueryContinueDrag

トンネリング バージョンの QueryContinueDrag です。

イベント

概要

DragEnter

このイベントは、オブジェクトがドロップ先の境界の中にドラッグされるときに発生します。 これは、 バブリング イベントです。

DragLeave

このイベントは、オブジェクトがドロップ先の境界の外にドラッグされるときに発生します。 これは、 バブリング イベントです。

DragOver

このイベントは、オブジェクトがドロップ先の境界内でドラッグ (移動) する間、継続的に発生します。 これは、 バブリング イベントです。

Drop

このイベントは、オブジェクトがドロップ先にドロップするときに発生します。 これは、バブリング イベントです。

PreviewDragEnter

トンネリング バージョンの DragEnter です。

PreviewDragLeave

トンネリング バージョンの DragLeave です。

PreviewDragOver

トンネリング バージョンの DragOver です。

PreviewDrop

トンネリング バージョンの Drop です。

オブジェクトのインスタンスのドラッグ アンド ドロップ イベントを処理するには、前述の表に一覧表示されたイベントにハンドラーを追加します。 クラス レベルでドラッグ アンド ドロップ イベントを処理するには、対応する仮想 On*Event イベントおよび On*PreviewEvent メソッドをオーバーライドします。 詳細については、「コントロールの基本クラスでのルーティング イベントのクラス処理」を参照してください。

UI 要素は、ドラッグ元、ドロップ先、またはその両方になれます。 基本的なドラッグ アンド ドロップを実装するには、ドラッグ アンド ドロップ操作を開始して、ドロップしたデータを処理するコードを記述します。 オプションのドラッグ アンド ドロップ イベントを処理すると、ドラッグ アンド ドロップの操作性を拡張できます。

基本的なドラッグ アンド ドロップを実装するには、次のタスクを実行します。

  • ドラッグ元となる要素を特定します。 ドラッグ元には UIElement または ContentElement を指定できます。

  • ドラッグ アンド ドロップ操作を開始するドラッグ元のイベント ハンドラーを作成します。 通常、イベントは MouseMove イベントです。

  • ドラッグ アンド ドロップ操作を開始するには、ドラッグ元のイベント ハンドラーで DoDragDrop メソッドを呼び出します。 DoDragDrop の呼び出しで、ドラッグ元、転送するデータ、および許可される効果を指定します。

  • ドロップ先となる要素を特定します。 ドロップ先には、UIElement または ContentElement を指定できます。

  • ドロップ先で、AllowDrop プロパティを true に設定します。

  • ドロップ先で、ドロップしたデータを処理する Drop イベント ハンドラーを作成します。

  • Drop イベント ハンドラーで、GetDataPresent メソッドと GetData メソッドを使用して、DragEventArgs からデータを抽出します。

  • Drop イベント ハンドラーで、データを使用して、目的のドラッグ アンド ドロップ操作を実行します。

次のタスクに示すように、カスタム DataObject を作成し、オプションのドラッグ元とドロップ先のイベントを処理すると、ドラッグ アンド ドロップの実装を拡張できます。

  • カスタム データまたは複数のデータ項目を転送するには、DoDragDrop メソッドに渡す DataObject を作成します。

  • ドラッグ中に他の操作を実行するには、ドロップ先で DragEnterDragOver、および DragLeave イベントを処理します。

  • マウス ポインターの外観を変更するには、ドラッグ元で GiveFeedback イベントを処理します。

  • ドラッグ アンド ドロップ操作の取り消し方法を変更するには、ドラッグ元で QueryContinueDrag イベントを処理します。

このセクションでは、Ellipse 要素のドラッグ アンド ドロップを実装する方法について説明します。 Ellipse はドラッグ元とドロップ先の両方です。 転送されるデータは、楕円の Fill プロパティの文字列表現です。 次の XAML は、Ellipse 要素と、XAML が処理するドラッグ アンド ドロップ関連のイベントを示しています。 ドラッグ アンド ドロップの実装方法の完全な手順については、「チュートリアル: ユーザー コントロールでのドラッグ アンド ドロップの有効化」を参照してください。

<Ellipse Height="50" Width="50" Fill="Green"
     MouseMove="ellipse_MouseMove"
     GiveFeedback="ellipse_GiveFeedback"
     AllowDrop="True"
     DragEnter="ellipse_DragEnter" DragLeave="ellipse_DragLeave"
     DragOver="ellipse_DragOver" Drop="ellipse_Drop" />

ドラッグ元であるオブジェクトは次の役割を務めます。

  • いつドラッグが発生するかを識別する。

  • ドラッグ アンド ドロップ操作を開始する。

  • 転送するデータを特定する。

  • ドラッグ アンド ドロップ操作によってデータ転送時に起こすことができる効果を指定する。

ドラッグ元には、許可される操作 (移動、コピー、なし) に関してユーザーにフィードバックすることもできます。また、ドラッグ中に Esc キーを押すなどのユーザーの追加の入力に基づいて、ドラッグ アンド ドロップ操作を取り消すことができます。

いつドラッグが発生したかを判断してから、DoDragDrop メソッドを呼び出してドラッグ アンド ドロップ操作を開始することは、アプリケーションの役割です。 通常、これはマウス ボタンが押されている間に、要素上で MouseMove イベントが発生してドラッグする場合です。 次の例は、Ellipse 要素の MouseMove イベント ハンドラーからドラッグ アンド ドロップ操作を開始してドラッグ元にする方法を示しています。 転送されるデータは、楕円の Fill プロパティの文字列表現です。

private void ellipse_MouseMove(object sender, MouseEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
    {
        DragDrop.DoDragDrop( ellipse,
                             ellipse.Fill.ToString(),
                             DragDropEffects.Copy);
    }
}

MouseMove イベント ハンドラー内で、DoDragDrop メソッドを呼び出して、ドラッグ アンド ドロップ操作を開始します。 DoDragDrop メソッドは 3 つのパラメーターを受け取ります。

  • dragSource – 転送されたデータのソースである依存関係オブジェクトへの参照。通常、これは MouseMove イベントのソースです。

  • data - DataObject にラップされる転送済みデータを含むオブジェクト。

  • allowedEffects - ドラッグ アンド ドロップ操作の許可される効果を指定する DragDropEffects 列挙値の 1 つ。

シリアル化可能なオブジェクトはすべて data パラメーターに渡すことができます。 データがまだ DataObject にラップされていない場合、データは新しい DataObject に自動的にラップされます。 複数のデータ項目を渡すには、自分で DataObject を作成し、DoDragDrop メソッドに渡す必要があります。 詳細については、「データとデータ オブジェクト」を参照してください。

allowedEffects パラメーターを使用すると、ドラッグ元が、ドロップ先に対して、データの転送時に何を行えるかを指定できます。 ドラッグ元の一般的な値は CopyMove、および All です。

System_CAPS_noteメモ

ドロップ先でも、ドロップされたデータに対応してどのような効果を意図するか指定できます。 たとえば、ドロップ先がドロップするデータ型を認識しない場合、許可された効果を None に設定してデータを拒否することができます。 これは通常、 DragOver イベント ハンドラーで実行します。

ドラッグ元は、オプションで GiveFeedback イベントと QueryContinueDrag イベントを処理できます。 これらのイベントには、イベントを処理済みとマークしない限り使用される既定のハンドラーがあります。 既定の動作を変更する特定のニーズがない限り、通常はこれらのイベントを無視します。

ドラッグ元がドラッグされている間、GiveFeedback イベントは継続的に発生します。 このイベントの既定のハンドラーは、ドラッグ元が有効なドロップ先の上にドラッグしているかどうかを確認します。 有効である場合は、このハンドラーは、ドロップ先の許可された効果を確認します。 その後、許可されているドロップ効果に関してエンドユーザーにフィードバックします。 通常は、マウス カーソルを非ドロップ、コピー、または移動のカーソルに変更してこれを実行します。 カスタムのカーソルを使用してユーザーにフィードバックする必要がある場合のみ、このイベントを処理する必要があります。 このイベントを処理する場合は、既定のハンドラーが自作のハンドラーをオーバーライドしないよう、必ずイベントを処理済みとマークしてください。

ドラッグ元がドラッグされている間、QueryContinueDrag イベントは継続的に発生します。 このイベントを処理すると、Esc、Shift、Ctrl、および Alt の各キーの状態に加えて、マウス ボタンの状態に基づいて、どのアクションがドラッグ アンド ドロップ操作を終了させるかを決定することができます。 このイベントの既定のハンドラーは、Esc キーを押した場合はドラッグ アンド ドロップ操作を取り消し、マウス ボタンを放した場合はデータをドロップします。

System_CAPS_caution注意

これらのイベントは、ドラッグ アンド ドロップ操作中に継続的に発生します。 そのため、イベント ハンドラーではリソースを集中的に使用するタスクを避ける必要があります。 たとえば、GiveFeedback イベントが発生するたびに新しいカーソルを作成するのではなく、キャッシュされたカーソルを使用します。

ドロップ先であるオブジェクトは次の役割を務めます。

  • 有効なドロップ先であることを指定する。

  • ドラッグ元に対して、ターゲットの上にドラッグしたときに応答する。

  • 転送されたデータが受信できる形式であることを確認する。

  • ドロップしたデータを処理する。

要素がドロップ先であることを指定するには、AllowDrop プロパティを true に設定します。 ドロップ先のイベントが要素で発生して、処理できるようになります。 ドラッグ アンド ドロップ操作中に、次の一連のイベントがドロップ先で発生します。

  1. DragEnter

  2. DragOver

  3. DragLeave または Drop

DragEnter イベントは、データがドロップ先の境界の中にドラッグされるときに発生します。 通常は、アプリケーションに適していれば、ドラッグ アンド ドロップ操作の効果のプレビューを提供するように、このイベントを処理します。 DragEnter イベントで DragEventArgs.Effects プロパティを設定しないでください。このプロパティは DragOver イベントで上書きされるためです。

次の例は、Ellipse 要素の DragEnter イベント ハンドラーを示しています。 このコードでは、現在の Fill ブラシを保存して、ドラッグ アンド ドロップ操作の効果をプレビューします。 続いて、GetDataPresent メソッドを使用して、楕円の上にドラッグした DataObject に、Brush に変換できる文字列データが含まれているかどうかを確認します。 含まれている場合、データは GetData メソッドによって抽出されます。 その後、データは Brush に変換されて、楕円に適用されます。 変更は DragLeave イベント ハンドラーで元に戻ります。 データが Brush に変換できない場合、アクションは実行されません。

private Brush _previousFill = null;
private void ellipse_DragEnter(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        // Save the current Fill brush so that you can revert back to this value in DragLeave.
        _previousFill = ellipse.Fill;

        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

            // If the string can be converted into a Brush, convert it.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString);
                ellipse.Fill = newFill;
            }
        }
    }
}

DragOver イベントは、データがドロップ先の上にドラッグされる間、継続的に発生します。 このイベントはドラッグ元の GiveFeedback イベントとペアになります。 DragOver イベント ハンドラーでは、通常は GetDataPresent メソッドと GetData メソッドを使用して、転送されたデータがドロップ先で処理できる形式であるかどうかを確認します。 また、いずれかの修飾キーが押されたかどうかも確認できます。修飾キーは、通常、ユーザーが移動またはコピー操作を意図しているかどうかを示します。 これらの確認を行った後、DragEventArgs.Effects プロパティを、データをドロップするとどのような効果が起こるかをドラッグ元に通知するように設定します。 ドラッグ元は、GiveFeedback のイベント引数でこの情報を受信し、適切なカーソルを設定してユーザーにフィードバックします。

次の例は、Ellipse 要素の DragOver イベント ハンドラーを示しています。 このコードは、楕円の上にドラッグされている DataObject に、Brush に変換できる文字列データが含まれているかどうかを確認します。 含まれている場合、DragEventArgs.Effects プロパティを Copy に設定します。 これにより、ドラッグ元に対して、データが楕円にコピーできることを示します。 データが Brush に変換できない場合、DragEventArgs.Effects プロパティは None に設定されます。 これにより、ドラッグ元に対して、楕円はデータの有効なドロップ先ではないことを示します。

private void ellipse_DragOver(object sender, DragEventArgs e)
{
    e.Effects = DragDropEffects.None;

    // If the DataObject contains string data, extract it.
    if (e.Data.GetDataPresent(DataFormats.StringFormat))
    {
        string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

        // If the string can be converted into a Brush, allow copying.
        BrushConverter converter = new BrushConverter();
        if (converter.IsValid(dataString))
        {
            e.Effects = DragDropEffects.Copy | DragDropEffects.Move;
        }
    }
}

DragLeave イベントは、データがドロップされることなくターゲットの境界の外にドラッグされるときに発生します。 このイベントを処理すると、DragEnter イベント ハンドラーで行ったことをすべて元に戻すことができます。

次の例は、Ellipse 要素の DragLeave イベント ハンドラーを示しています。 このコードは、保存された Brush を楕円に適用することで、DragEnter イベント ハンドラーで行ったプレビュー内容を元に戻します。

private void ellipse_DragLeave(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        ellipse.Fill = _previousFill;
    }
}

Drop イベントは、データがドロップ先にドロップされると発生します。既定では、これはマウス ボタンが放されたときに発生します。 Drop イベント ハンドラーでは、GetData メソッドを使用して DataObject から転送されたデータを抽出し、アプリケーションが必要とするデータ処理を実行します。 Drop イベントは、ドラッグ アンド ドロップ操作を終了します。

次の例は、Ellipse 要素の Drop イベント ハンドラーを示しています。 このコードは、ドラッグ アンド ドロップ操作の効果を適用します。DragEnter イベント ハンドラーのコードと似ています。 このコードは、楕円の上にドラッグされている DataObject に、Brush に変換できる文字列データが含まれているかどうかを確認します。 含まれている場合は、 Brush は楕円に適用されます。 データが Brush に変換できない場合、アクションは実行されません。

private void ellipse_Drop(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

            // If the string can be converted into a Brush, 
            // convert it and apply it to the ellipse.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString);
                ellipse.Fill = newFill;
            }
        }
    }
}
表示: