Agosto 2015

Volume 30 numero 8

Il presente articolo è stato tradotto automaticamente.

Windows 10 - moderno Drag and Drop per applicazioni universali di Windows

Da Alain Zanchetta

Questo articolo si basa sull'anteprima pubblica di Windows 10 e Visual Studio 2015.

Trascinamento della selezione è un modo intuitivo per trasferire i dati all'interno di un'applicazione o tra applicazioni sul desktop di Windows. Fece il suo debutto in Windows 3.1 con il File Manager ed è stato poi esteso a tutte le applicazioni che supportano OLE 2, ad esempio Microsoft Office. Quando è stato rilasciato Windows 8, Microsoft ha introdotto un nuovo tipo di applicazione di Windows, chiamato un app di Windows Store, che è stato progettato per i tablet e sempre visualizzata in modalità a schermo intero. Perché solo un'applicazione era visibile in un dato momento, tra le applicazioni drag and drop non fanno senso e altri modi di condividere dati, ad esempio l'accesso alla condivisione, sono stati sviluppati. In Windows 10, tuttavia, applicazioni su un desktop PC sono ancora una volta in esecuzione in modalità finestra, che significa più finestre vengono visualizzati sullo schermo, e di conseguenza drag and drop rende un ritorno come un app universale Windows API, con l'aggiunta di nuove funzionalità che migliorano l'UX.

Concetti di drag-and-Drop

Trascinamento della selezione consente all'utente di trasferire dati tra applicazioni o all'interno di un'applicazione utilizzando un gesto standard (stampa-attesa-e-pan con il dito) o pan e premere con un mouse o uno stilo.

L'origine di trascinamento, che è l'applicazione o la zona dove l'azione di trascinamento viene attivato, fornisce i dati per essere trasferiti tramite la compilazione di un oggetto di pacchetto dati che può contenere formati di dati standard, tra cui testo, RTF, HTML, immagini bitmap, archiviazione di articoli o formati di dati personalizzati. La fonte indica anche il tipo di operazioni supportate: copiare, spostare o sul collegamento. Quando il puntatore del mouse viene rilasciato, si verifica la goccia. La destinazione di rilascio, che è l'applicazione o l'area sotto il puntatore, elabora il pacchetto di dati e restituisce il tipo di operazione eseguita.

Durante il trascinamento della selezione, il trascinamento dell'interfaccia utente fornisce un'indicazione visiva del tipo di operazione di drag-and-drop che sta avvenendo. Questo feedback visivo è inizialmente fornito dall'origine ma può essere cambiato dalle destinazioni come il puntatore passa sopra di loro.

Moderno drag and drop è disponibile su desktop, tablet e telefono. Permette il trasferimento di dati tra o all'interno di qualsiasi tipo di applicazione, incluse le applicazioni di Windows classico, anche se questo articolo è incentrato sull'API XAML per moderno drag and drop.

Implementazione di trascinamento della selezione

L'origine di trascinamento di trascinamento destinazione giocare ruoli diversi. Un'applicazione può avere componenti dell'interfaccia utente che sono solo origini di trascinamento, rilasciare solo obiettivi o entrambi, come ad esempio l'applicazione Photo Booth di esempio illustrato nella Figura 1.

origini di trascinamento e destinazioni di rilascio
Figura 1 origini di trascinamento e destinazioni di rilascio

Un'operazione di drag-and-drop è guidata interamente da input dell'utente, così la sua attuazione è quasi esclusivamente basato su eventi, come mostrato Figura 2.

Drag e Drop eventi
Figura 2 Drag e Drop eventi

Implementazione di un'origine trascinare In Windows 8.1, un controllo ListView può essere l'origine di un'operazione di drag-and-drop in-app se la relativa proprietà CanDragItems è impostata su true:

<ListView CanDragItems="True"
          DragItemsStarting="ListView_DragItemsStarting"
          ItemsSource="{Binding Pictures}"
          ItemTemplate="{StaticResource PictureTemplate}"
          />

L'applicazione può gestire l'evento DragItemsStarting sull'origine. Questo è ancora supportato in Windows 10 con l'aggiunta di un evento DragItemsCompleted, che non era necessario in applicazioni Windows 8.1 dove origine e destinazione devono appartenere allo stesso processo.

La fonte principale per moderno drag and drop è UIElement, che dà accesso a tutte le moderne funzionalità di drag-and-drop ed è l'obiettivo principale di questo articolo.

Un modo per rendere trascinabile UIElement è quello di impostare la relativa proprietà CanDrag su true. Questo può essere fatto nel markup o nel codebehind. Il framework XAML gestisce il riconoscimento dei gesti e genera l'evento DragStarting per indicare l'inizio di un'operazione di trascinamento. L'applicazione deve configurare DataPackage riempiendo il suo contenuto e che indica quali operazioni sono supportate. L'applicazione di origine può mettere diversi formati in DataPackage, che renderà compatibile con altre destinazioni, come mostrato Figura 3. Le operazioni supportate sono definite nel tipo DataPackageOperation e possono essere copia, spostamento, Link o qualsiasi combinazione di questi.

Figura 3 Gestione DragStarting e riempimento DataPackage

private void DropGrid_DragStarting(UIElement sender,
  DragStartingEventArgs args)
{
  if (Picture == null)
  {
    args.Cancel = true;
  }
  else if (_fileSource != null)
  {
    args.Data.RequestedOperation =
      DataPackageOperation.Copy | DataPackageOperation.Move;
    args.Data.SetStorageItems(new IStorageItem[] { _fileSource });
  ...
}

È possibile annullare l'operazione di trascinamento nel gestore eventi impostando la proprietà Cancel del parametro DragStartingEventArgs; ad esempio, nella nostra applicazione di esempio, un segnaposto immagine verrà avviato un'operazione di trascinamento solo se ha ricevuto un'immagine o un file.

Il gestore di DragStartingEvent è anche il luogo in cui l'applicazione di origine può personalizzare il trascinamento dell'interfaccia utente, che è spiegato più avanti in questo articolo.

In alcuni casi, l'applicazione potrebbe utilizzare un gesto speciale per avviare un'operazione di drag-and-drop, o per consentire il trascinamento di un controllo cui normali interazioni interferiscano con il gesto di drag-and-drop, ad esempio, il controllo TextBox, che già reagisce agli eventi del puntatore verso il basso modificando la selezione. In questi casi, l'applicazione può implementare il proprio rilevamento di gesto e quindi avviare un'operazione di drag-and-drop chiamando il metodo StartDragAsync. Si noti che questo metodo prevede che un identificatore di puntatore e, pertanto, non è possibile avviare un'operazione di drag-and-drop con dispositivi non standard, ad esempio un sensore Kinect. Una volta che viene chiamato StartDragAsync, il resto dell'operazione di trascinamento della selezione segue lo stesso modello come se CanDrag = True era stato usato, compreso l'evento DragStarting.

Una volta che l'utente ha rilasciato il puntatore, l'operazione di drag-and-drop e la fonte è una notifica tramite l'evento DropCompleted, che contiene il DataPackageOperation restituito dalla destinazione su cui l'utente ha rilasciato il puntatore, o DataPackageOperation.None se il puntatore del mouse è stato rilasciato su un bersaglio che non accettano i dati o se è stato premuto Annulla:

private void DropGrid_DropCompleted(UIElement sender, DropCompletedEventArgs args)
{
  if (args.DropResult == DataPackageOperation.Move)
  {
    // Move means that we should clear our own image
    Picture = null;
    _bitmapSource = null;
    _fileSource = null;
  }
}

StartDragAsync restituisce un IAsyncOperation < DataPackageOperation >; l'applicazione di origine è in grado di gestire in attesa della IAsyncOperation oppure gestendo l'evento di DropCompleted alla fine dell'operazione. A livello di codice l'annullamento dopo il DragStarting evento è possibile tramite l'interfaccia IAsyncOperation, ma potrebbe essere fastidioso per l'utente.

Notare che, sebbene sia il trascinamento di ListView e goccia e il UIElement drag and drop vengono implementate sugli stessi servizi di sistema e sono pienamente compatibili, essi non generano gli stessi eventi sul lato di origine. Cioè, se un controllo ListView è impostata proprietà CanDragItems su true, vengono generati solo DragItemsStarting e DragItemsCompleted. DragStarting e DropCompleted sono gli eventi correlati alla proprietà CanDrag di UIElement.

Implementare una destinazione di rilascio qualsiasi UIElement può essere una destinazione di trascinamento, purché la relativa proprietà AllowDrop è impostata su true. Durante un'operazione di drag-and-drop, i seguenti eventi possono essere generati su un bersaglio: DragEnter, DragOver, DragLeave e Drop. Questi eventi esistono già in Windows 8.1, ma la classe DragEventArgs è stato esteso in Windows 10 per dare alle applicazioni di accedere a tutte le funzionalità di moderno drag and drop. Quando si gestisce un evento drag-and-drop, l'applicazione di destinazione prima deve controllare il contenuto di DataPackage tramite la proprietà DataView dell'argomento dell'evento; nella maggior parte dei casi, verificare la presenza di un dato tipo è sufficiente e può essere fatto in modo sincrono. In alcuni casi, come con i file, l'applicazione potrebbe essere necessario verificare il tipo di file disponibili prima di accettare o ignorare DataPackage. Questa è un'operazione asincrona e richiede l'applicazione di destinazione per prendere un rinvio e poi completarlo (questo modello è dettagliato più avanti in questo articolo).

Una volta che la destinazione ha determinato se può elaborare i dati, è necessario impostare la proprietà AcceptedOperation dell'istanza DragEventArgs per consentire al sistema di fornire il giusto feedback all'utente.

Si noti che se l'applicazione restituisce DataTransferOperation.None—or un'operazione non accettata dall'origine — da un gestore di eventi, la goccia non avrà luogo anche se l'utente rilascia il puntatore sopra l'obiettivo; verrà invece generato l'evento DragLeave.

L'applicazione può gestire DragEnter o DragOver; il AcceptedOperation restituito da DragEnter viene mantenuta se DragOver non viene gestita. Come DragEnter viene chiamato solo una volta, dovrebbe essere preferito a DragOver per motivi di prestazioni. Tuttavia, nel caso di obiettivi nidificati, è necessario restituire il valore corretto da DragOver nel caso in cui un obiettivo padre potrebbe ignorarlo (impostazione di Handled su true impedisce l'evento di bubbling al padre). Nell'applicazione di esempio, ogni segnaposto foto controlla per immagini in DataPackage e indirizza l'evento alla griglia padre solo se nessuna immagine è disponibile, che permette la griglia accettare il testo anche se fisicamente è caduto su un segnaposto (vedere Figura 4).

Figura 4 Gestione DragEnter e ispezione DataPackage

private async void DropGrid_DragEnter(object sender, DragEventArgs e)
{
  if (!App.IsSource(e.DataView))
  {
    bool forceMove = ((e.Modifiers & DragDropModifiers.Shift) ==
      DragDropModifiers.Shift);
    if (e.DataView.Contains(StandardDataFormats.Bitmap))
    {
      _acceptData = true;
      e.AcceptedOperation = (forceMove ? DataPackageOperation.Move :
        DataPackageOperation.Copy);
      e.DragUIOverride.Caption = "Drop the image to show it in this area";
      e.Handled = true;
    }
    else if (e.DataView.Contains(StandardDataFormats.StorageItems))
    {
      // Notify XAML that the end of DropGrid_Enter does
      // not mean that we have finished to handle the event
      var def = e.GetDeferral();
      _acceptData = false;
      e.AcceptedOperation = DataPackageOperation.None;
      var items = await e.DataView.GetStorageItemsAsync();
      foreach (var item in items)
      {
        try
        {
          StorageFile file = item as StorageFile;
          if ((file != null) && file.ContentType.StartsWith("image/"))
          {
            _acceptData = true;
            e.AcceptedOperation = (forceMove ? DataPackageOperation.Move :
              DataPackageOperation.Copy);
            e.DragUIOverride.Caption = "Drop the image to show it in this area";
            break;
          }
        }
        catch (Exception ex)
        {
          Debug.WriteLine(ex.Message);
        }
      }
      e.Handled = true;
      // Notify XAML that now we are done
      def.Complete();
    }
  }
  // Else we let the event bubble on a possible parent target
}

Concetti avanzati

Personalizzare il feedback visivo il feedback negativo che OLE 2 trascinare e discesa fornito era quello di cambiare il cursore del mouse secondo la risposta del bersaglio per l'evento DragOver. Moderno drag and drop consente scenari più avanzati come il feedback visivo fornito all'utente è più ricco. Il trascinamento dell'interfaccia utente è costituito da tre parti: contenuto visivo, glifo e didascalia.

Il contenuto visivo rappresenta i dati trascinati. Potrebbe essere trascinato UIElement (se l'origine è un'applicazione XAML); un'icona standard scelta dal sistema in base al contenuto di DataPackage; o un'immagine personalizzata impostate dall'applicazione.

Il glifo riflette il tipo di operazione accettato dalla destinazione. Si possono prendere quattro diverse forme corrispondenti ai valori del tipo DataPackageOperation. Esso non può essere personalizzato di applicazioni, ma può essere nascosta.

La didascalia è la descrizione fatta dalla destinazione. A seconda dell'applicazione di destinazione, un'operazione di copia potrebbe, ad esempio, essere l'aggiunta di un brano a una playlist, il caricamento di un file da SkyDrive o una copia di file semplice. La didascalia consente una risposta più precisa rispetto il glifo e svolge un ruolo molto simile ad un tooltip.

La tabella in Figura 5 dimostra come l'origine e la destinazione possibile personalizzare queste parti diverse. Quando il puntatore non è sopra una destinazione di trascinamento, il trascinamento dell'interfaccia utente è esattamente ciò che ha configurato l'origine. Quando il puntatore si trova su una destinazione di trascinamento, alcune parti dell'oggetto visual potrebbero essere sottoposto a override dalla destinazione; tutte le sostituzioni vengono cancellate quando il puntatore esce il bersaglio.

Figura 5 personalizzazioni disponibili per l'origine e la destinazione

  Alimentazione Destinazione
Contenuto visivo

Default = elemento trascinato

Consente di utilizzare contenuti generati dal sistema basato su DataPackage

Possibile utilizzare qualsiasi immagine bitmap

Predefinito = che cosa è stato impostato dall'origine

Non è possibile utilizzare il contenuto generato dal sistema

Possibile utilizzare qualsiasi immagine bitmap

Per visualizzare o nascondere

Glifo Nessun accesso

Aspetto basato su AcceptedOperation

Per visualizzare o nascondere

Didascalia Nessun accesso

Possibile utilizzare qualsiasi stringa

Per visualizzare o nascondere

Quando inizia un'operazione di drag-and-drop, se l'applicazione di origine non tenta di personalizzare l'interfaccia utente trascinamento nel gestore eventi DragStarting, uno snapshot dell'oggetto UIElement trascinato è assunto da XAML e usato come il contenuto dell'interfaccia utente di trascinamento. L'oggetto UIElement iniziale è ancora visualizzato nella sua posizione originale, che è un comportamento diverso da ListView, dove sono nascosti i ListViewItems trascinato dalla loro posizione iniziale. Poiché lo snapshot di UIElement trascinato viene presa dopo che è stato generato l'evento DragStarting, è possibile innescare un cambiamento dello stato di visualizzazione durante questo evento per modificare lo snapshot. (Si noti che stato di UIElement è anche alterato e, anche se viene ripristinato, un leggero sfarfallio potrebbe accadere).

Quando si gestisce un evento di DragStarting, all'origine del trascinamento può personalizzare il feedback visivo tramite la proprietà DragUI della classe DragStartingEventArgs. Ad esempio, chiedendo al sistema di utilizzare il contenuto di DataPackage per generare il contenuto visivo avviene attraverso SetContentFromDataPackage, come mostrato Figura 6.

Figura 6 utilizzo di SetContentFromDataPackage per generare contenuto visivo

private void DropGrid_DragStarting(UIElement sender, DragStartingEventArgs args)
{
  ...
  if (_fileSource != null)
  {
    args.Data.RequestedOperation = DataPackageOperation.Copy | DataPackageOperation.Move;
    args.Data.SetStorageItems(new IStorageItem[] { _fileSource });
    args.DragUI.SetContentFromDataPackage();
  }
  else if (_bitmapSource != null)
  {
    args.Data.RequestedOperation = DataPackageOperation.Copy | DataPackageOperation.Move;
    args.Data.SetBitmap(_bitmapSource);
    args.DragUI.SetContentFromDataPackage();
  }
}

È possibile impostare un'immagine bitmap personalizzata come il contenuto del trascinamento dell'interfaccia utente utilizzando due diverse classi: classe BitmapImage XAML ben nota o una nuova classe di Windows 10, SoftwareBitmap. Se la bitmap è una risorsa dell'applicazione, è più facile utilizzare un oggetto BitmapImage e inizializzarla con l'URI della risorsa:

private void SampleBorder_DragStarting(UIElement sender, DragStartingEventArgs args)
{
  args.Data.SetText(SourceTextBox.SelectedText);
  args.DragUI.SetContentFromBitmapImage(new BitmapImage(new Uri(
    "ms-appx:///Assets/cube.png", UriKind.RelativeOrAbsolute)));
}

Se la bitmap deve essere generata al volo quando inizia l'operazione di trascinamento o quando il puntatore del mouse entra in una destinazione di trascinamento, un SoftwareBitmap possono essere creati dal buffer generato dalla classe RenderTargetBitmap XAML, che genera una bitmap che contiene la rappresentazione visiva di un oggetto UIElement, come illustrato nel Figura 7. Questo oggetto UIElement deve essere la struttura ad albero visuale di XAML, ma non ha bisogno di essere sulla parte visibile della pagina. Perché RenderTargetBitmap fa questo rendering in modo asincrono, è necessario prendere un rinvio qui così XAML sa se la bitmap non è pronta quando il gestore eventi è finito e attende per il rinvio deve essere completata per aggiornare il contenuto dell'interfaccia utente Drag. (Ti spiegheremo il meccanismo di rinvio più dettagliatamente nella sezione successiva di questo articolo).

Figura 7 personalizzazione del contenuto dell'interfaccia utente Drag con RenderTargetBitmap e SoftwareBitmap

private async void PhotoStripGrid_DragStarting(UIElement sender, DragStartingEventArgs args)
{
  if ((Picture1.Picture == null) || (Picture2.Picture == null)
    || (Picture3.Picture == null) || (Picture4.Picture == null))
  {
    // Photo Montage is not ready
    args.Cancel = true;
  }
  else
  {
    args.Data.RequestedOperation = DataPackageOperation.Copy;
    args.Data.SetDataProvider(StandardDataFormats.Bitmap, ProvideContentAsBitmap);
    App.SetSource(args.Data);
    var deferral = args.GetDeferral();
    var rtb = new RenderTargetBitmap();
    const int width = 200;
    int height = (int)(.5 + PhotoStripGrid.ActualHeight / PhotoStripGrid.ActualWidth
                         * (double)width);
    await rtb.RenderAsync(PhotoStripGrid, width, height);
    var buffer = await rtb.GetPixelsAsync();
    var bitmap = SoftwareBitmap.CreateCopyFromBuffer(buffer, BitmapPixelFormat.Bgra8, width, height,
                                                                    BitmapAlphaMode.Premultiplied);
    args.DragUI.SetContentFromSoftwareBitmap(bitmap);
    deferral.Complete();
  }
}

Naturalmente, se il SoftwareBitmap è già stato generato — e potrebbe essere memorizzata nella cache per le operazioni di drag-and-drop successive — Nessun differimento è necessaria.

Per SetContentFromBitmapImage e SetContentFromSoftwareBitmap, è possibile specificare un punto di ancoraggio che indica come posizionare il trascinamento dell'interfaccia utente rispetto alla posizione del puntatore. Se si utilizza l'overload senza parametro del punto di ancoraggio, l'angolo superiore sinistro della bitmap personalizzata seguirà il puntatore del mouse. Il metodo DragStartingEventArgs GetPosition restituisce la posizione del puntatore del rispetto qualsiasi oggetto UIElement, che può essere utilizzato per impostare la posizione iniziale del trascinamento UI esattamente dove si trova l'oggetto UIElement trascinato.

Sul lato di destinazione, le diverse parti dell'oggetto trascinato visivo possono essere personalizzato sia nei gestori eventi DragEnter o DragOver. Personalizzazione avviene tramite la proprietà DragUIOverride della classe DragEventArgs che espone quattro metodi di SetContentFrom identici a DragUI sul lato sorgente, così come quattro proprietà che consentono di nascondere diverse parti del DragUI e modificare la didascalia. Infine, DragUIOverride espone anche un metodo chiaro che reimposta tutte le sostituzioni di DragUI fatto dalla destinazione.

Operazioni asincrone The Windows Universal applicazioni API impone un modello asincrono per tutte le operazioni che può richiedere più di pochi millisecondi. Questo è particolarmente critico nel caso di trascinamento della selezione come tali operazioni sono completamente guidate da parte dell'utente. Per la sua ricchezza, trascinamento della selezione utilizza tre diversi modelli asincroni: chiamate asincrone, rinvii e callback.

Chiamate asincrone vengono utilizzate quando l'applicazione chiama un sistema API che potrebbe richiedere del tempo per completare. Questo modello è ormai ben noto dagli sviluppatori di Windows e semplice fatta l'async e attendono Parole chiavi in c# (o create_task e quindi in C++). Tutti i metodi che recuperano dati da DataPackage seguono questo modello, come ad esempio GetBitmapAsync, che la nostra applicazione di esempio utilizza per recuperare un riferimento all'immagine in diretta, come mostrato Figura 8.

Figura 8 utilizzando chiamate asincrone per leggere DataPackage

private async void DropGrid_Drop(object sender, DragEventArgs e)
{
  if (!App.IsSource(e.DataView))
  {
    bool forceMove = ((e.Modifiers & DragDropModifiers.Shift) ==
      DragDropModifiers.Shift);
    if (e.DataView.Contains(StandardDataFormats.Bitmap))
    {
      // We need to take a deferral as reading the data is asynchronous
      var def = e.GetDeferral();
      // Get the data
      _bitmapSource = await e.DataView.GetBitmapAsync();
      var imageStream = await _bitmapSource.OpenReadAsync();
      var bitmapImage = new BitmapImage();
      await bitmapImage.SetSourceAsync(imageStream);
      // Display it
      Picture = bitmapImage;
      // Notify the source
      e.AcceptedOperation = forceMove ? DataPackageOperation.Move :
        DataPackageOperation.Copy;
      e.Handled = true;
      def.Complete();
    }
...
}

Risconti sono utilizzati quando il framework XAML richiama in codice di un'applicazione che si potrebbe emettere una chiamata asincrona prima di restituire un valore atteso dal framework. Questo modello non è stato ampiamente utilizzato nelle versioni precedenti di XAML, quindi cerchiamo di prendere il tempo di analizzarlo. Quando un pulsante genera un evento Click, è una chiamata unidirezionale, nel senso che nessun valore deve essere restituito dall'applicazione. Se una chiamata asincrona viene effettuata dall'applicazione, il risultato sarà disponibile dopo il completamento del gestore dell'evento Click, ma questo è perfettamente bene perché questo gestore non restituisce un valore.

D'altra parte, quando XAML genera un DragEnter o un evento DragOver, prevede l'applicazione per impostare la proprietà AcceptedOperation degli argomenti dell'evento per indicare se il contenuto di DataPackage può essere gestito. Se l'applicazione si preoccupa solo per il tipo di dati disponibili all'interno di DataPackage, questo può ancora essere fatto in modo sincrono, ad esempio:

private void DropTextBox_DragOver(object sender, DragEventArgs e)
{
  bool hasText = e.DataView.Contains(StandardDataFormats.Text);
  e.AcceptedOperation = hasText ? DataPackageOperation.Copy :
    DataPackageOperation.None;
}

Tuttavia, se, ad esempio, l'applicazione può accettare solo alcuni tipi di file, esso non deve solo controllare i tipi di dati all'interno di DataPackage, esso deve accedere ai dati, pure, che possono essere fatto solo in modo asincrono. Ciò significa che l'esecuzione del codice viene sospesa fino a quando i dati sono stati letti e che il gestore eventi DragEnter (o DragOver) sarà completato prima che l'applicazione sappia se può accettare i dati. Questo scenario è esattamente lo scopo del rinvio: ottenendo un rinvio dall'oggetto DragEventArg, l'applicazione dice XAML che rinvierà alcune delle elaborazioni, e completando il differimento, l'applicazione notifica XAML che questo trattamento viene fatto e sono state impostate le proprietà di output dell'istanza DragEventArgs. Fare riferimento a Figura 4 per vedere come la nostra applicazione di esempio controlla per StorageItems dopo aver ottenuto un rinvio.

Il differimento può essere utilizzato anche quando la personalizzazione del contenuto dell'interfaccia utente drag sul lato di destinazione richiede le operazioni asincrone come metodo RenderAsync di RenderTargetBitmap.

Sul lato di origine di un'operazione di drag-and-drop, DragStartingEvent­Args espone un rinvio, troppo, cui scopo è consentire l'operazione iniziare non appena il gestore eventi termina (anche se non è stato completato il differimento) al fine di fornire il più rapido feedback per l'utente, anche se la creazione di una bitmap per personalizzare l'interfaccia utente Drag richiede un certo tempo.

Callback vengono utilizzati in DataPackage rinviare fornendo i dati fino a quando è realmente necessario. Con questo meccanismo, l'applicazione di origine può pubblicizzare diversi formati in DataPackage, ma solo i dati effettivamente leggi da una destinazione dovrà essere preparato e trasferito. In molti casi, non verrà mai chiamato il callback — ad esempio, se la destinazione non può capire il corrispondente formato di dati — che è un'ottimizzazione delle prestazioni di Nizza.

Si noti che, in molti casi, fornendo i dati reali richiederà una chiamata asincrona e, pertanto, la DataProviderRequest parametro di questo callback espone un rinvio applicazioni di avvisare che hanno bisogno di più tempo fornire i dati e quindi che i dati sono disponibili, come mostrato Figura 9.

Figura 9 rinviando i dati finché viene effettivamente letto

private void DeferredData_DragStarting(UIElement sender,
  DragStartingEventArgs args)
{
  args.Data.SetDataProvider(StandardDataFormats.Text, ProvideDeferredText);
}
async void ProvideDeferredText(DataProviderRequest request)
{
  var deferral = request.GetDeferral();
  var file = await KnownFolders.DocumentsLibrary.GetFileAsync(fileName);
  var content = await FileIO.ReadTextAsync(file);
  request.SetData(content);
  deferral.Complete();
}

Conclusioni

Quando si scrive un'applicazione che modifica formati di dati standard quali file, immagini o testo, dovresti considerare l'implementazione di trascinamento e cadere come si tratta di un'operazione sia naturale che ben nota agli utenti. Le basi di trascinamento della selezione sono già familiare a coloro che hanno programmato con Windows Form e Windows Presentation Foundation, che riduce la curva di apprendimento di questa caratteristica ricca, con i suoi concetti specifici come ad esempio la personalizzazione dell'interfaccia utente drag e i modelli relativamente inutilizzati come il modello di differimento. Se si desidera solo per supportare scenari di drag-and-drop di base, si può fare affidamento sulla vostra esperienza precedente e dispone di un'implementazione semplice o, se si preferisce, si può sfruttare le nuove funzionalità per fornire un'esperienza su misura per l'utente.


Anna Pai è un software engineer del team di Xbox. Precedentemente ha lavorato in Silverlight, Silverlight per Windows Phone e quindi XAML per Windows e Windows Phone.

Alain Zanchetta è un software engineer del team di XAML di Windows. In precedenza è stato un architetto nella divisione consulenza di Microsoft Francia.

Grazie all'esperto tecnico Microsoft seguente per la revisione di questo articolo: Clément Fauchère
Clemente Fauchere è software engineer nel Team di Shell di Windows presso Microsoft.