Schnellstart: Ziehen von Inhalten

Applies to Windows only

Benutzer können Text, Bilder oder andere Daten ziehen, um sie in einem GridView- oder ListView-Steuerelement neu anzuordnen, oder Elemente auf andere Arten von Steuerelementen ziehen.

In einer Windows Store-App können Sie Elemente mithilfe der Maus, mit Touchbewegungen oder sprachgesteuert ziehen, um sie in einer GridView oder ListView neu anzuordnen, oder ein Element von einer GridView oder ListView auf ein anderes XAML-Steuerelement ziehen. Um Elemente aus einer GridView oder ListView ziehen zu können, legen Sie das CanDragItems-Attribut auf True fest. Damit ein Steuerelement gezogene Elemente akzeptiert, legen Sie das AllowDrop-Attribut auf True fest.

Sie können Animationen auf Ziehvorgänge anwenden. Folgen Sie dazu den allgemeinen Richtlinien unter Richtlinien für Ziehanimationen. Diese Richtlinien wurden zwar für JavaScript geschrieben, gelten aber auch hier. Im Artikel Animieren der Benutzeroberfläche finden Sie Informationen zum Anwenden von Ziehanimationen in XAML.

Das Ziehen zwischen verschiedenen Apps wird nicht unterstützt, Sie können in diesen Fällen aber mithilfe der Freigabe-APIs oder der Zwischenablage Daten übertragen. Alle Datenübertragungs-APIs haben einige Typen miteinander gemein. Dazu zählen die Windows::ApplicationModel::DataTransfer ::DataPackage-Klasse und die Windows::ApplicationModel::DataTransfer ::StandardDataFormats-Enumeration. Bei einem Ziehvorgang werden die übertragenen Daten mithilfe der DataPackage-Klasse umschlossen, und die StandardDataFormats-Enumeration definiert Formate, für die DataPackage spezielle Set*-Methoden bereitstellt. Zu diesen Formaten zählen Text, Bitmap, HTML, RTF, URI und StorageItem-Objektauflistungen. Die DataPackageView-Klasse stellt die asynchronen Get*-Methoden bereit, die Sie im Drop-Ereignishandler zum Abrufen der Daten verwenden. Mit der DataPackage::SetData-Methode und den DataPackageView::GetDataAsync-Methoden können Sie auch benutzerdefinierte Objekte ziehen.

So lassen Sie das Ziehen von Elementen in einem GridView- oder ListView-Steuerelement zu

Das Ziehen von Elementen in einer GridView oder ListView zuzulassen, ist ausgesprochen simpel. Legen Sie im XAML-Code einfach die folgenden Attribute für das Steuerelement fest: AllowDrop="True" CanDragItems="True" CanReorderItems="True"

Grundlegende Schritte beim Ziehen

Ein Ziehvorgang zwischen zwei Steuerelementen umfasst immer zwei grundlegende Schritte – unabhängig davon, welche Art von Daten Sie übertragen:

  1. Behandeln Sie das Windows::UI::Xaml::Controls::DragItemsStarting-Ereignis in der Quelle, in dem die Ziehbewegung beginnt. Dabei kann es sich um eine Windows::UI::Xaml::Controls::GridView oder eine Windows::UI::Xaml::Controls::ListView handeln. Der DragItemsStartingEventArgs-Parameter enthält einen Verweis auf das bzw. die gezogenen Elemente. Außerdem enthält der Parameter eine Data-Eigenschaft. Dies ist das DataPackage, das an das Dropziel übergeben wird. Rufen Sie im Ereignishandler die zu übergebenden Daten aus der DragItemsStartingEventArgs::Items-Auflistung ab, und füllen Sie anschließend – in der für Ihre Zwecke am besten geeigneten Weise – mit diesen Daten die Data-Eigenschaft auf.

  2. Behandeln Sie das Windows::UI::Xaml::Controls::Drop-Ereignis im Dropziel. Rufen Sie das übergebene DataPackage-Objekt ab, rufen Sie GetView auf, um seine DataPackageView-Eigenschaft abzurufen, und greifen Sie mit den Get*-Methoden des Objekts auf die Daten zu, die Sie zuvor im DragItemsStarting-Ereignis gespeichert haben. Bei einem Dropziel kann es sich um jedes beliebige XAML-Steuerelement handeln, das das Drop-Ereignis unterstützt.

Zusätzliche Ereignisse – DragEnter, DragLeave und DragOver – eignen sich in erster Linie zum Erstellen von Animationen oder anderen visuellen Effekten, sind für die Datenübertragung an sich aber nicht notwendig.

So ziehen Sie Text

Im folgenden Beispiel gehen wir davon aus, dass die Dropquelle eine GridView ist, die String-Elemente enthält, und "DragItemsStarting_1" der Ereignishandler für das von der GridView ausgelöste DragItemsStarting-Ereignis ist. Wenn die GridView:: SelectionMode-Eigenschaft auf "Multiple" festgelegt ist, kann die Elementauflistung mehrere Elemente enthalten. In diesem Beispiel unterstellen wir, dass "SelectionMode" auf "Single" festgelegt ist, sodass wir mit Sicherheit davon ausgehen können, dass sich das gezogene Element an Position 0 befindet.

Drag:

void DragDrop::DragText::DragTextGridView_DragItemsStarting_1(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e)
{    
    auto mytxt = safe_cast<String^>(e->Items->GetAt(0));
    e->Data->SetText(mytxt);
}
private void DragTextGridView_DragItemsStarting_1(object sender, DragItemsStartingEventArgs e)
{
    var mytxt = e.Items[0] as String;
    if (mytxt != null)
    {
        e.Data.SetText(mytxt);
    }
}

Drop:

Das folgende Beispiel zeigt, wie das Drop-Ereignis behandelt wird. In diesem Fall gehen wir davon aus, dass das Dropziel ein XAML-TextBlock-Element ist.

void DragDrop::DragText::DropTextHere_Drop_1(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e)
{
    using namespace concurrency;
    using namespace Windows::ApplicationModel::DataTransfer;

    DataPackageView^ dataView = e->Data->GetView();
    create_task(dataView->GetTextAsync())
    .then([this, sender](String^ txt)
    {
        TextBlock^ tb = safe_cast<TextBlock^>(sender);
        tb->Text = txt;
    });
}
private async void DropTextHere_Drop_1(object sender, DragEventArgs e)
{
    var dataView = e.Data.GetView();
    var tb = sender as TextBlock;
    if (sender != null)
    {
        tb.Text = await dataView.GetTextAsync();
    }
}

So ziehen Sie Bitmaps

Wenn ein BitmapImage aus einer Datei abgerufen wird, verwenden Sie die DataPackage::SetStorageItems- und die DataPackageView::GetStorageItemsAsync-Methode, um es als IStorageItem zu ziehen. Falls Sie eine GridView oder ListView von ziehbaren dateibasierten BitmapImage-Objekten erstellen müssen, empfiehlt es sich, ein bindbares Wrapperobjekt zu erstellen, das als öffentliche Eigenschaften das BitmapImage und die ursprüngliche StorageFile sowie ggf. andere Informationen wie den Dateinamen oder Attribute enthält. Da ein IStorageItem-Objekt selbst nicht gebunden werden kann, kann es nicht ohne Weiteres in einer GridView angezeigt werden.

Wichtig  Virtualisierte Dateiobjekte können zwar mithilfe der FileInformation-Klasse an ein XAML-Steuerelement gebunden, aber nicht problemlos gezogen werden.

Im folgenden Beispiel gehen wir davon aus, dass die Dragquelle eine ListView ist, die an eine Liste benutzerdefinierter PhotoWrapper-Objekte gebunden ist. Jedes PhotoWrapper-Objekt enthält ein BitmapImage und das StorageFile-Objekt, das beim Öffnen der Datei abgerufen wurde. Die DataTemplate der ListView ist an die ImageFile-Eigenschaft gebunden.

    [Windows::UI::Xaml::Data::Bindable]
    public ref class PhotoWrapper sealed
    {
    public:
        property Windows::UI::Xaml::Media::Imaging::BitmapImage^ Thumbnail;
        property Windows::Storage::StorageFile^ ImageFile;
    };
    public sealed class PhotoWrapper
    {
        public BitmapImage Thumbnail { get; set; }
        public StorageFile ImageFile { get; set; }
    }

Drag:

Der folgende DragItemsStarting-Ereignishandler zeigt, wie beim Ziehen eine Liste mit einem oder mehreren IStorageItem-Objekten erstellt und in das DataPackage eingefügt wird.

void DragDrop::DragImage::ListView_DragItemsStarting_1(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e)
{
    IVector<IStorageItem^>^ selectedFiles = ref new Vector<IStorageItem^>();
    for (unsigned int i = 0; i < e->Items->Size; i++)
    {
        PhotoWrapper^ wrapper = safe_cast<PhotoWrapper^>(e->Items->GetAt(i));
        selectedFiles->Append(wrapper->ImageFile);
    }

    e->Data->SetStorageItems(selectedFiles);
}
        void ListView_DragItemsStarting_1(object sender, DragItemsStartingEventArgs e)
        {
            IList<IStorageItem> selectedFiles = new List<IStorageItem>();
            foreach (var item in e.Items)
            {
                var wrapper = item as PhotoWrapper;
                selectedFiles.Add(wrapper.ImageFile);
            }

            e.Data.SetStorageItems(selectedFiles);
        }

Drop:

Rufen Sie im Drop-Ereignis die schreibgeschützte DataPackageView-Eigenschaft ab, und rufen Sie die OpenReadAsync-Methode auf, um den Datenstrom abzurufen und anschließend ein BitmapImage daraus zu erstellen. Danach legen Sie die Source-Eigenschaft des Image-Steuerelements fest und entfernen das entsprechende PhotoWrapper-Objekt aus der Quellliste.

void DragDrop::DragImage::ListView_Drop_1(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e)
{
    DataPackageView^ dpView = e->Data->GetView();

    create_task(dpView->GetStorageItemsAsync())
    .then([this](IVectorView<IStorageItem^>^ images)
    {
        for (unsigned int i = 0; i < images->Size; i++)
        {
            create_task([images, i, this]()
            {
                // Get a stream from the file object.
                IStorageFile^ file = safe_cast<IStorageFile^>(images->GetAt(i));
                return file->OpenReadAsync();
            }).then([this](IRandomAccessStreamWithContentType^ s)
            {
                // Set the stream as the bitmap source
                BitmapImage^ bi = ref new BitmapImage();
                bi->SetSourceAsync(s);
                return bi;
            }).then([this](BitmapImage^ bi)
            {
                // Add the BitmapImage to the source list.
                // The update will be reflected in the ListView.
                m_targetImages->Append(bi);
            });
        }        
    });
}
        private async void ListView_Drop_1(object sender, DragEventArgs e)
        {
            var dpView = e.Data.GetView();
            var images = await dpView.GetStorageItemsAsync();

            foreach (var image in images)
            {
                // Get a stream from the file object.
                IStorageFile file = image as StorageFile;
                var randomStream = await file.OpenReadAsync();

                // Set the stream as the bitmap source
                BitmapImage bi = new BitmapImage();
                await bi.SetSourceAsync(randomStream);

                // Add the BitmapImage to the source list.
                // The update will be reflected in the ListView.
                m_targetImages.Add(bi);
            }
        }
  

So ziehen Sie benutzerdefinierte Objekte

Sie können benutzerdefinierte Objekte ziehen, indem Sie sie in den assoziativen DataPackage::Properties-Container einfügen. Da die Daten dem DataPackage in diesem Fall nicht bekannt sind, müssen Sie einen Zeichenfolgenschlüssel angeben, der das Datenformat beschreibt. Bei einem Ziehvorgang wird die Formatzeichenfolge nur App-intern verwendet. Sie müssen daher keinen allgemein verständlichen Namen auswählen. Geben Sie einfach beim Abrufen der Daten dieselbe Zeichenfolge an. In diesem Beispiel wird für alle Elemente der gleiche Schlüssel angegeben, Sie könnten aber auch für jedes Element einen eigenen Schlüssel verwenden.

Im folgenden Beispiel gehen wir davon aus, dass wir eine bindbare Klasse mit dem Namen "City" haben und mindestens ein City-Objekt von einer GridView in eine ListView ziehen möchten.

    [Windows::UI::Xaml::Data::Bindable]
    public ref class City sealed
    {
    public:
        City(Platform::String^ name, int pop)
        {
            this->Name = name;
            this->Population = pop;
        }
        property Platform::String^ Name;
        property int Population;
    };
    public sealed class City
    {
        public City(String name, int pop)
        {
            this.Name = name;
            this.Population = pop;
        }
        public String Name { get; set; }
        public int Population { get; set; }
    }

Drag:

void DragDrop::MainPage::GridView_DragItemsStarting_1(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e)
{
    for (auto item : e->Items)
    {    
        // If you want to drop only a subset of the dragged items,
        // then make each key unique.    
        e->Data->Properties->Insert("MyApp.MyCity", item);
    }
}
void GridView_DragItemsStarting_1(Object sender, DragItemsStartingEventArgs e)
{
    foreach(var item in e.Items)
    {
        // If you want to drop only a subset of the dragged items,
        // then make each key unique. 
        e.Data.Properties.Add("MyApp.MyCity", item);
     }
}

Drop:

In C++ werden die Elemente beim Ablegen aus dem "DataPackage" abgerufen, wieder in den ursprünglichen Typ "City" umgewandelt und in die Datenquelle für das Dropziel kopiert.

void DragDrop::MainPage::ListViewDropTarget_Drop_1(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e)
{    
    DataPackageView^ dpView = e->Data->GetView();
    for (auto prop : dpView->Properties)
    {
        auto city = safe_cast<City^>(prop->Value);
        m_dropTargetItems->Append(city);
    }  
}
void ListViewDropTarget_Drop_1(Object sender, DragEventArgs e)
{
    DataPackageView dpView = e.Data.GetView();
    foreach (var prop in dpView.Properties)
    {
        var city = prop.Value as City;
        m_dropTargetItems.Add(city);
    }
}