Agosto de 2015
Número 8 do Volume 30
Windows 10: arrastar e soltar modernos para aplicativos universais do Windows
Por Alain Zanchetta
Este artigo baseia-se na visualização pública do Windows 10 e do Visual Studio de 2015.
Arrastar e soltar é uma maneira intuitiva de transferir dados em um aplicativo ou entre aplicativos na área de trabalho do Windows. Ele fez sua estreia no Windows 3.1 com o Gerenciador de Arquivos e foi estendido para todos os aplicativos com suporte ao OLE 2, como o Microsoft Office. Quando o Windows 8 foi lançado, a Microsoft introduziu um novo tipo de aplicativo do Windows, chamado de um aplicativo da Windows Store, que foi projetado para tablets e sempre exibido no modo de tela inteira. Como apenas um único aplicativo estava visível em um determinado momento, o arrastar e soltar entre os aplicativos não fazia sentido e outras maneiras de compartilhar dados, como o Símbolo de Compartilhamento, foram desenvolvidas. No entanto, no Windows 10, os aplicativos na área de trabalho de um computador são executados novamente no modo de janela, o que significa que várias janelas são exibidas na tela, e, portanto, o arrastar e soltar retorna como uma API de aplicativo Universal do Windows, com a adição de novos recursos que aprimoram a experiência do usuário.
Conceitos de arrastar e soltar
Arrastar e soltar permite ao usuário transferir dados entre aplicativos ou dentro de um aplicativo usando um gesto padrão (pressionar e segurar e visão panorâmica com o dedo ou pressionar e visão panorâmica com um mouse ou uma caneta).
A origem da operação arrastar, que é o aplicativo ou área onde o gesto de arrastar é disparado, fornece os dados a serem transferidos ao preencher um objeto de pacote de dados que pode conter os formatos de dados padrão, incluindo texto, RTF, HTML, bitmaps, itens de armazenamento ou formatos de dados personalizados. A origem também indica os tipos de operações que são aceitas: copiar, mover ou vincular. Quando o ponteiro é liberado, a operação de soltar ocorre. O destino da operação arrastar, que é o aplicativo ou a área sob o ponteiro, processa o pacote de dados e retorna o tipo de operação executada.
Durante a operação arrastar e soltar, a interface do usuário fornece uma indicação visual do tipo de operação arrastar e soltar que está sendo executada. Esse feedback visual inicialmente é fornecido pela origem, mas pode ser alterado pelos destinos conforme o ponteiro passa sobre eles.
A operação arrastar e soltar moderna está disponível em computador desktop, tablet e telefone. Ela permite a transferência de dados entre ou dentro de qualquer tipo de aplicativo, incluindo aplicativos do Windows Clássico, embora este artigo esteja concentrado na API do XAML para a operação arrastar e soltar moderna.
Implementação de arrastar e soltar
A operação de arrastar a origem e soltar no destino desempenham funções diferentes. Um aplicativo pode ter componentes de interface do usuário que são apenas “arrastar” as origens, apenas soltar nos destinos ou ambas, como o aplicativo Photo Booth de exemplo mostrado na Figura 1.
Figura 1 Arrastar origens e Soltar nos Destinos
Uma operação de arrastar e soltar é controlada totalmente pela entrada do usuário, de forma que sua implementação é quase que exclusivamente baseada em evento, conforme mostrado naFigura 2.
Figura 2 Eventos Arrastar e Soltar
Implementação de uma origem de arrastar No Windows 8.1, a ListView pode ser a origem de uma operação de arrastar e soltar no aplicativo se sua propriedade CanDragItems estiver definida como true:
<ListView CanDragItems="True"
DragItemsStarting="ListView_DragItemsStarting"
ItemsSource="{Binding Pictures}"
ItemTemplate="{StaticResource PictureTemplate}"
/>
O aplicativo pode manipular o evento DragItemsStarting na origem. Isso ainda é suportado no Windows 10 com a adição de um evento DragItemsCompleted, que não era necessário em aplicativos do Windows 8.1 onde a origem e o destino devem pertencer ao mesmo processo.
A principal origem da operação arrastar para o arrastar e soltar moderno é o UIElement, que fornece acesso a todos os recursos de arrastar e soltar modernos e é o foco principal deste artigo.
Uma forma de tornar o UIElement arrastável é definir sua propriedade CanDrag como true. Isso pode ser feito na marcação ou no code-behind. A estrutura XAML lida com o reconhecimento de gesto e dispara o evento DragStarting para indicar o início de uma operação de arrastar. O aplicativo deve configurar o DataPackage preenchendo seu conteúdo e indicando quais operações são suportadas. O aplicativo de origem pode colocar formatos diferentes no DataPackage, o que o tornará compatível com mais destinos, conforme mostrado na Figura 3. As operações com suporte são definidas no tipo de DataPackageOperation e podem ser Copiar, Mover, Vincular ou qualquer combinação desses elementos.
Figura 3 Manipulação da DragStarting e Preenchimento do 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 });
...
}
Você pode cancelar a operação Arrastar no manipulador de eventos, definindo a propriedade Cancel do parâmetro DragStartingEventArgs. Por exemplo, no nosso aplicativo de exemplo, um espaço reservado para imagem iniciará uma operação Arrastar somente se ele recebeu uma imagem ou um arquivo.
O manipulador DragStartingEvent também é o local onde o aplicativo de origem pode personalizar a interface do usuário de arrastar, o que é explicado mais tarde neste artigo.
Em alguns casos, o aplicativo pode usar um gesto especial para iniciar uma operação de arrastar e soltar ou precisa permitir arrastar um controle cujas interações normais interferem com o gesto de arrastar e soltar, por exemplo, a TextBox, que já reage aos eventos do ponteiro de busca, alterando sua seleção. Nesses casos, o aplicativo pode implementar sua própria detecção de gesto e, em seguida, iniciar uma operação de arrastar e soltar chamando o método StartDragAsync. Observe que este método espera um identificador de ponteiro e, portanto, você não pode iniciar uma operação de arrastar e soltar com dispositivos não padrão, como um sensor Kinect. Quando StartDragAsync é chamado, o restante da operação de arrastar e soltar segue o mesmo padrão como se CanDrag=True tivesse sido usado, incluindo o evento DragStarting.
Quando o usuário lançou o ponteiro, a operação de arrastar e soltar foi concluída e a origem é notificada por meio do evento DropCompleted, que contém o DataPackageOperation retornado pelo destino em que o usuário lançou o ponteiro ou DataPackageOperation.None se o ponteiro foi lançado em um destino que não aceita os dados ou se Cancelar foi pressionado:
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 retorna um IAsyncOperation <DataPackageOperation>. O aplicativo de origem pode manipular o término da operação, aguardando o IAsyncOperation ou manipulando o evento DropCompleted. O cancelamento de forma programática após o evento DragStarting é possível através da interface IAsyncOperation, mas pode ser perturbador para o usuário.
Observe que, embora tanto o arrastar e soltar da ListView e o arrastar e soltar do UIElement sejam implementados nos mesmos serviços do sistema e são totalmente compatíveis, eles não geram os mesmos eventos no lado da origem. Ou seja, se uma ListView tem sua propriedade CanDragItems definida como true, apenas DragItemsStarting e DragItemsCompleted são gerados. DragStarting e DropCompleted são eventos relacionados à propriedade de CanDrag do UIElement.
Implementando um destino de soltar Qualquer UIElement pode ser um destino de soltar desde que sua propriedade AllowDrop seja definida como true. Durante uma operação de arrastar e soltar, os seguintes eventos podem ser gerados em um destino: DragEnter, DragOver, DragLeave e Drop. Esses eventos já existem no Windows 8.1, mas a classe DragEventArgs foi estendida no Windows 10 para fornecer aos aplicativos acesso a todos os recursos do arrastar e soltar moderno. Ao manipular um evento de arrastar e soltar, o aplicativo de destino deve primeiro inspecionar o conteúdo do DataPackage por meio da propriedade DataView do argumento do evento. Na maioria dos casos, a verificação da presença de um dado tipo é suficiente, e isso pode ser feito de forma síncrona. Em alguns casos, como com arquivos, o aplicativo pode precisar verificar o tipo dos arquivos disponíveis antes de aceitar ou ignorar o DataPackage. Essa é uma operação assíncrona e requer que o aplicativo de destino faça um adiamento e posteriormente conclua a operação (esse padrão é detalhado posteriormente neste artigo).
Depois que o destino determinou se ele pode processar os dados, ele deve definir a propriedade AcceptedOperation da instância DragEventArgs para permitir que o sistema forneça o feedback correto ao usuário.
Observe que, se o aplicativo retornar DataTransferOperation.None (ou uma operação não for aceita pela origem) de um manipulador de eventos, a operação soltar não ocorrerá mesmo que o usuário libere o ponteiro sobre o destino. Em vez disso, o evento DragLeave será gerado.
O aplicativo pode manipular DragEnter ou DragOver. A propriedade AcceptedOperation retornada por DragEnter é mantida se o evento DragOver não for manipulado. Como DragEnter é chamado apenas uma vez, ele deve ser preferencial em relação ao DragOver por motivos de desempenho. No entanto, no caso de destinos aninhados, ele é necessário para retornar o valor correto de DragOver no caso de um destino pai substituí-lo (a definição de Handled como verdadeiro impede que o evento seja propagado para o pai). No aplicativo de exemplo, cada espaço reservado para foto verifica por imagens no DataPackage e roteia o evento apenas para a grade pai se nenhuma imagem estiver disponível, o que permite que a grade aceite até mesmo texto se ele for solto fisicamente em um espaço reservado (consulteFigura 4).
Figura 4 Manipulação do DragEnter e inspeção do 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
}
Conceitos avançados
Personalizando o feedback visual O único feedback que o arrastar e soltar do OLE 2 fornecia era alterar o cursor do mouse de acordo com a resposta do destino para o evento DragOver. O arrastar e soltar moderno permite cenários mais avançados, assim como o feedback visual fornecido ao usuário é mais avançado. A interface do usuário de arrastar consiste em três partes: conteúdo visual, glifo e legenda.
O conteúdo visual representa os dados que estão sendo arrastados. Ele pode ser o UIElement sendo arrastado (se a origem for um aplicativo XAML), um ícone padrão escolhido pelo sistema com base no conteúdo do DataPackage ou um conjunto de imagens definidas pelo aplicativo.
O glifo reflete o tipo da operação aceita pelo destino. Ele pode ter quatro formatos diferentes correspondentes aos valores do tipo da DataPackageOperation. Ele não pode ser personalizado pelos aplicativos, mas pode estar oculto.
A legenda é uma descrição fornecida pelo destino. Dependendo do aplicativo de destino, uma operação de cópia, por exemplo, seria a adição de uma música a uma lista de reprodução, o carregamento de um arquivo para o OneDrive ou uma cópia de arquivo simples. A legenda permite o feedback mais preciso que o glifo e desempenha um papel muito semelhante a uma dica de ferramenta.
A tabela na Figura 5 mostra como a origem e o destino podem personalizar essas partes diferentes. Quando o ponteiro não está sobre um destino de soltar, a Interface do usuário arrastar é exatamente o que foi configurado na origem. Quando o ponteiro estiver sobre um destino de soltar, algumas partes do visual podem ser substituídas pelo destino; todas as substituições são limpas quando o ponteiro sair do destino.
Figura 5 Personalizações disponíveis para a origem e o destino
Fonte | Destino | |
Conteúdo Visual | Padrão = elemento arrastado Pode usar o conteúdo gerado pelo sistema com base no DataPackage Pode usar qualquer bitmap |
Padrão = o que foi definido pela origem Não é possível usar o conteúdo gerado pelo sistema Pode usar qualquer bitmap Pode mostrar ou ocultar |
Glifo | Sem acesso | Aspecto com base na AcceptedOperation Pode mostrar ou ocultar |
Legenda | Sem acesso | Pode usar qualquer cadeia de caracteres Pode mostrar ou ocultar |
Quando uma operação de arrastar e soltar é iniciada, se o aplicativo de origem não tenta personalizar a interface do usuário de arrastar no manipulador de eventos DragStarting, um instantâneo do UIElement arrastado é realizado pelo XAML e usado como o conteúdo da interface do usuário de arrastar. O UIElement inicial ainda é exibido em sua posição original, a qual é um comportamento diferente da ListView, onde os ListViewItems arrastados estão ocultos da sua posição inicial. Como o instantâneo do UIElement arrastado é feito após o evento DragStarting ter sido gerado, é possível disparar uma alteração do estado visual durante esse evento para alterar o instantâneo. (Observe que o estado do UIElement também é alterado e, mesmo se ele for restaurado, pode acontecer uma cintilação da luz.)
Ao manipular um evento DragStarting, a origem de arrastar pode personalizar o feedback visual por meio da propriedade DragUI da classe DragStartingEventArgs. Por exemplo, solicitar que o sistema use o conteúdo do DataPackage para gerar o conteúdo visual é feito por meio de SetContentFromDataPackage, conforme mostrado na Figura 6.
Figura 6 Usando SetContentFromDataPackage para gerar conteúdo visual
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();
}
}
Você pode definir um bitmap personalizado como o conteúdo da interface do usuário de arrastar usando duas classes diferentes: a classe BitmapImage XAML conhecida ou uma nova classe do Windows 10, SoftwareBitmap. Se esse bitmap for um recurso do aplicativo, é mais fácil usar uma BitmapImage e inicializá-lo com o URI do recurso:
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 o bitmap deve ser gerado dinamicamente quando a operação de arrastar for iniciada ou quando o ponteiro entrar no destino de soltar, um SoftwareBitmap pode ser criado do buffer gerado pela classe RenderTargetBitmap XAML, que gera um bitmap que contém a representação visual de um UIElement, conforme mostrado na Figura 7. Esse UIElement deve estar na árvore visual do XAML, mas não precisa estar na parte visível da página. Como RenderTargetBitmap faz esse processamento de forma assíncrona, é necessário fazer um adiamento aqui para que o XAML saiba se o bitmap não está pronto quando o manipulador de eventos é concluído e aguarda o adiamento para ser concluído para atualizar o conteúdo da Interface do Usuário de Arrastar. (Explicaremos o mecanismo de adiamento em maiores detalhes na próxima seção deste artigo.)
Figura 7 Personalização do conteúdo da interface do usuário de arrastar com 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();
}
}
Obviamente, se já tiver sido gerado o SoftwareBitmap, e ele pode estar em cache para as operações de arrastar e soltar subsequentes, nenhum adiamento é necessário.
Para SetContentFromBitmapImage e SetContentFromSoftwareBitmap, você pode especificar um ponto de ancoragem que indica como posicionar a Interface do Usuário de arrastar em relação à posição do ponteiro. Se você usar a sobrecarga sem parâmetros de ponto de ancoragem, o canto superior esquerdo do bitmap personalizado seguirá o ponteiro. O método DragStartingEventArgs GetPosition retorna a posição do ponteiro em relação a qualquer UIElement, que pode ser usado para definir a posição inicial da interface do usuário de arrastar exatamente onde o UIElement arrastado está localizado.
No lado do destino, as diferentes partes do visual arrastado podem ser personalizadas nos manipuladores de eventos DragEnter ou DragOver. A personalização é feita por meio da propriedade DragUIOverride da classe DragEventArgs, que expõe quatro métodos SetContentFrom idênticos ao DragUI na origem, bem como quatro propriedades que permitem ocultar partes diferentes do DragUI e alterar a legenda. Por fim, DragUIOverride também expõe um método Clear que redefine todas as substituições do DragUI feitas pelo destino.
Operações assíncronas A API de aplicativos universais do Windows impõe um padrão assíncrono para todas as operações que podem levar mais de alguns milissegundos. Isso é particularmente importante no caso de arrastar e soltar porque essas operações são conduzidas completamente pelo usuário. Devido a sua quantidade de recursos, o arrastar e soltar usa três diferentes padrões assíncronos: chamadas assíncronas, adiamentos e retornos de chamada.
Chamadas assíncronas são usadas quando o aplicativo chama uma API do sistema que pode levar algum tempo para ser concluída. Esse padrão agora é conhecido pelos desenvolvedores do Windows e foi simplificada pelas palavras-chave async e await em C# (ou create_task e em C++). Todos os métodos que recuperam os dados de DataPackage seguem esse padrão, como GetBitmapAsync, que nosso aplicativo de exemplo usa para recuperar uma referência de fluxo de imagem, conforme mostrado na Figura 8.
Figura 8 Usando chamadas assíncronas para ler o 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();
}
...
}
Os adiamentos são usados quando a estrutura XAML chama de volta no código de um aplicativo que pode emitir por si próprio uma chamada assíncrona antes de retornar um valor esperado pela estrutura. Esse padrão não foi amplamente usado nas versões anteriores do XAML, de forma que vamos dar tempo para analisá-lo. Quando um botão gera um evento de clique, ele é uma chamada unidirecional no sentido que nenhum valor precisa ser retornado pelo aplicativo. Se for feita uma chamada assíncrona pelo aplicativo, o resultado estará disponível após a conclusão do manipulador de eventos Click, mas isso é perfeitamente aceitável porque esse manipulador não retorna um valor.
Por outro lado, quando XAML gera um evento DragEnter ou um DragOver, ele espera o aplicativo para definir a propriedade AcceptedOperation dos argumentos do evento para indicar se o conteúdo do DataPackage pode ser tratado. Se o aplicativo só se preocupa com o tipo de dados disponível no DataPackage, isso ainda poderá ser feito de forma síncrona, por exemplo:
private void DropTextBox_DragOver(object sender, DragEventArgs e)
{
bool hasText = e.DataView.Contains(StandardDataFormats.Text);
e.AcceptedOperation = hasText ? DataPackageOperation.Copy :
DataPackageOperation.None;
}
No entanto, se, por exemplo, o aplicativo pode aceitar apenas alguns tipos de arquivo, ele não deve verificar somente os tipos de dados no DataPackage, mas também deve acessar os dados, o que só pode ser feito de forma assíncrona. Isso significa que a execução do código é suspensa até que os dados tenham sido lidos e que o manipulador de evento DragEnter (ou DragOver) seja concluído antes do aplicativo saber se ele pode aceitar os dados. Esse cenário é exatamente a finalidade do adiamento: fazendo um adiamento do objeto DragEventArg, o aplicativo informa o XAML que ele irá adiar alguns de seus processamentos e completando o adiamento, o aplicativo notifica o XAML que esse processamento foi feito e as propriedades de saída da instância DragEventArgs foram definidas. Volte à Figura 4 para ver como nosso exemplo de aplicativo verifica StorageItems depois de enfrentar um adiamento.
O adiamento também pode ser usado quando a personalização do conteúdo da interface do usuário de arrastar no lado do destino requer operações assíncronas, como método RenderAsync do RenderTargetBitmap.
No lado da origem de uma operação de arrastar e soltar, o DragStartingEventArgs expõe um adiamento, também, cuja finalidade é permitir que a operação seja iniciada assim que o manipulador de eventos é encerrado (mesmo que o adiamento não tenha sido concluído) para fornecer o feedback mais rápido para o usuário mesmo se ao criar um bitmap para personalizar a interface do usuário de arrastar leva algum tempo.
Os retornos de chamada são usados no DataPackage para adiar o fornecimento dos dados até que ele seja realmente necessário. Com esse mecanismo, o aplicativo de origem pode anunciar vários formatos em DataPackage, mas somente os dados realmente lidos por um destino precisarão ser preparados e transferidos. Em muitos casos, o retorno da chamada nunca será chamado — por exemplo, se nenhum destino puder entender o formato de dados correspondente, o que é uma otimização de ótimo desempenho.
Observe que, em muitos casos, fornecer os dados reais exigirá uma chamada assíncrona e, portanto, o parâmetro DataProviderRequest desse retorno de chamada apresentará um adiamento para que os aplicativos possam notificar que precisam de mais tempo para fornecer os dados e que os dados estão disponíveis, conforme mostrado na Figura 9.
Figura 9 Adiando os dados até que sejam realmente lidos
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();
}
Conclusão
Ao escrever um aplicativo que manipule os formatos de dados padrão, como arquivos, imagens ou texto, você deve considerar a implementação de arrastar e soltar como uma operação natural e conhecida dos usuários. as noções básicas de arrastar e soltar já são familiares para quem tiver programado com o Windows Forms e o Windows Presentation Foundation, o que reduz a curva de aprendizado desse recurso avançado, com seus conceitos específicos, como a personalização da interface do usuário de arrastar e os padrões relativamente não utilizados como o padrão de adiamento. Se você quiser oferecer suporte a cenários básicos de arrastar e soltar, você pode contar com sua experiência anterior e ter uma implementação simples ou, se preferir, você pode aproveitar ao máximo os novos recursos para oferecer uma experiência personalizada para o usuário.
Anna Pai é engenheira de software na equipe do Xbox. Ela trabalhou anteriormente no Silverlight, no Silverlight para Windows Phone e XAML para Windows e Windows Phone.
Alain Zanchetta é engenheiro de software na equipe de XAML do Windows. Anteriormente, era um arquiteto da divisão de consultoria da Microsoft na França.
Agradecemos ao seguinte especialista técnico da Microsoft pela revisão deste artigo: Clément Fauchère
Fauchere Clement é engenheiro de software na equipe do Windows Shell na Microsoft.