Como habilitar ações de reordenar, arrastar e soltar em ListView

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente ]

Saiba como adicionar o recurso de reordenar, arrastar e soltar itens a um controle ListView. (somente Windows)

O que você precisa saber

Tecnologias

Pré-requisitos

Instruções

Etapa 1: Configurar o exemplo

Este exemplo demonstra como criar um controle ListView e um ItemContainer para exibir informações sobre um item na lista.

Use a marcação HTML a seguir como base para o controle ListView. Você pode copiar e colar o código no arquivo default.html dentro de um Aplicativo em branco no Microsoft Visual Studio 2013.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>List_View_demo</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>

    <!-- List_View_demo references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
    <script src="js/data.js"></script>
</head>
<body>
    <div id="listViewTemplate">
        <div id="listTemplate" 
            data-win-control="WinJS.Binding.Template">
            <div class="listTemplate">
                <div>
                    <h4 data-win-bind="innerText: title"></h4>
                    <h6 data-win-bind="innerText: text"></h6>
                </div>
            </div>
        </div>
        <div id="listView" 
             data-win-control="WinJS.UI.ListView"
             data-win-options="{
                itemDataSource : DataExample.itemList.dataSource,
                itemTemplate: select('#listTemplate'),
                itemsDraggable: true,
                itemsReorderable: true,
                layout: { type: WinJS.UI.GridLayout }
             }">
        </div>
    </div>
    <div id="listViewDetail" >
        <h2>Details</h2><br/><br/>
        <div id="listViewDetailInfo" 
             draggable="true"
             data-win-control="WinJS.UI.ItemContainer">
            <h4>Cherry chocolate swirl</h4>
            <h6>Ice cream</h6>
            <p>Description: 
                <span>A sumptious blending of cherry 
                and dark chocolate.</span>
            </p>
        </div>
    </div>
</body>
</html>

O exemplo também usa os estilos de CSS para ajustar o controle ListView e o ItemContainer na página HTML. Adicione o seguinte código CSS à folha de estilos associada ao controle ListView (css/default.css no modelo de Aplicativo em branco).


/* Layout the app page as a grid. */
body {
    display: -ms-grid;
    -ms-grid-columns: 600px 1fr;
    -ms-grid-rows: 1fr;
}

/* Style the template for the ListView control.
.listTemplate {
    width: 282px;
    height: 70px;
    padding: 5px;
    overflow: hidden;
}

.listTemplate div {
    margin: 5px;
}

/* Style the ListView control. */
#listView {
    -ms-grid-column: 1;
    -ms-grid-row: 1;
    height: 500px; 
    width: 500px; 
    border: 2px solid gray;
}

#listView .win-container {
    margin: 10px;
}

#listView .win-container:hover {
    color: red;
}

/* Style the ItemContainer control.*/
#listViewDetail {
    -ms-grid-column: 2;
    -ms-grid-row: 1;
}

#listViewDetailInfo {
    width: 300px;
}

O exemplo usa alguns dados predefinidos para popular o controle ListView. Os dados estão em um arquivo chamado 'data.js' na pasta js (js/data.js). Siga as instruções abaixo para adicionar os dados de ListView ao aplicativo.

Dn423315.wedge(pt-br,WIN.10).gifPara adicionar um arquivo de dados JavaScript ao seu aplicativo

  1. No Gerenciador de Soluções, clique com o botão direito do mouse na pasta js e escolha Adicionar > Novo Arquivo JavaScript.

  2. Na caixa de diálogo Adicionar Novo Item, na caixa Nome, digite 'data.js' e depois clique em Adicionar.

  3. No Gerenciador de Soluções, clique duas vezes no novo arquivo JavaScript e adicione o seguinte código.

    (function () {
        "use strict";
    
        // Define the dataset.
        var dataArray = [
            { title: "Basic banana", 
              text: "Low-fat frozen yogurt", 
              description: "Go bananas for some frozen yogurt." },
            { title: "Banana blast", 
              text: "Ice cream", 
              description: "More banana than allowed by law." },
            { title: "Brilliant banana", 
              text: "Frozen custard", 
              description: "Custard with banana; an excellent desert." },
            { title: "Orange surprise", 
              text: "Sherbet", 
              description: "Orange sherbert with a little extra something." },
            { title: "Original orange", 
              text: "Sherbet", 
              description: "The orange sherbert you know and love." },
            { title: "Vanilla", 
              text: "Ice cream", 
              description: "The one and only, classic vanilla ice cream." },
            { title: "Very vanilla", 
              text: "Frozen custard", 
              description: "What's better than custard with vanilla flavoring?" },
            { title: "Marvelous mint", 
              text: "Gelato", 
              description: "Mint meets gelato in this delicious desert." },
            { title: "Succulent strawberry", 
              text: "Sorbet", 
              description: "A joyful confection of strawberries." }
        ];
    
        // Load the dataset into a List object.
        var dataList = new WinJS.Binding.List(dataArray);
    
        // Expose the List object to the rest of the app.
        WinJS.Namespace.define("DataExample", {
            itemList: dataList
        });
    
    })();
    

Observação  Você pode substituir os dados fornecidos por quaisquer dados necessários. Para substituir a fonte de dados, é possível mudar o conjunto de dados que é transmitido ao método construtor WinJS.Binding.List.

Se você optar por usar uma fonte de dados diferente de um objeto IListDataSource, ela deverá implementar os métodos moveBefore, moveAfter e moveToStart. Na prática, convém usar o objeto List fornecido por WinJS para encapsular sua fonte de dados.

Observe também que o objeto Template definido na marcação HTML do aplicativo usa uma fonte de dados que contém itens com propriedades title e text. Se os seus dados não contiverem propriedades title ou text, você precisará ajustar a definição do objeto Template.

 

Etapa 2: Adicionar recursos de reordenação ao controle ListView

Você pode reordenar as funcionalidades em um controle ListView com muita facilidade. Isso pede apenas uma pequena mudança ou adição no código. Basicamente, você só precisa definir a propriedade itemsReorderable do controle ListView como "true" (verdadeiro). (A configuração padrão é "false".)

Você pode fazer isso declarativamente na marcação HTML do controle ou pode adicionar esse recurso em tempo de execução usando JavaScript. O exemplo a seguir demonstra como adicionar o recurso de reordenação, ajustando a marcação HTML para o controle.

<!-- The definition of the ListView control. 
    Note that the data-win-options attribute for the 
    control includes the itemsReorderable property. -->
<div id="listView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{
        itemDataSource : DataExample.itemList.dataSource,
        itemTemplate: select('#listTemplate'),
        itemsReorderable : true,
        layout: { type : WinJS.UI.GridLayout }
    }">
</div>

O exemplo seguinte demonstra como adicionar a funcionalidade de reordenação a um controle ListView em tempo de execução usando JavaScript.

(function () {

    // Other JavaScript code ...

    // Get a reference to the ListView control.
    var listView = 
        document.querySelector('#listView').winControl;

    // Set the controls itemsReorderable property.
    listView.itemsReorderable = true;

    // Other JavaScript code ...

})();

Após mudar a propriedade itemsReorderable do controle ListView, execute o projeto (pressione F5). Selecione um item em ListView e arraste-o para outro local dentro do mesmo ListView.

Etapa 3: Adicionar funcionalidade de arrastar a um ListView

Em um nível básico, é tão fácil adicionar a funcionalidade de arrastar a um controle ListView quanto a funcionalidade de reordenar. O controle ListView inclui uma propriedade itemsDraggable que você pode definir de modo declarativo no HTML para o controle ou alterar em tempo de execução.

O próximo exemplo mostra como adicionar a funcionalidade simples de arrastar a um ListView na marcação HTML do controle.

<!-- The definition of the ListView control. 
    Note that  the data-win-options attribute for the 
    control includes the itemsDraggable property. -->
<div id="listView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{
        itemDataSource : DataExample.itemList.dataSource,
        itemTemplate: select('#listTemplate'),
        itemsDraggable : true,
        layout: { type : WinJS.UI.GridLayout }
    }">
</div>

O exemplo seguinte mostra como adicionar uma funcionalidade simples de arrastar a um controle ListView em tempo de execução usando JavaScript.

(function () {

    // Other JavaScript code ...

    // Get a reference to the ListView control.
    var listView = 
        document.querySelector('#listView').winControl;

    // Set the controls itemsReorderable property.
    listView.itemsDraggable = true;

    // Other JavaScript code ...

})();

Depois de definir a propriedade itemsDraggable como "true", execute o aplicativo (pressione F5). No aplicativo, selecione um item do controle ListView e arraste-o para fora do ListView. O item é duplicado na interface do aplicativo fora do ListView. Quando você soltar o botão do mouse, o item desaparecerá. Os eventos de soltar adequados são acionados.

Para interagir com a fonte de dados subjacente de um controle ListView, você também tem que implementar manipuladores em alguns eventos do tipo "arrastar e soltar" de ListView. No exemplo a seguir, um manipulador foi adicionado ao evento ListView.itemdragstart e também aos eventos dragover e drop de ItemContainer.

Para usar esse código com a amostra anterior, adicione-o ao manipulador de eventos app.onactivated definido no arquivo default.js fornecido no modelo Blank app (js/default.js).

// Get the data from the ListView when the user drags an item.
listView.addEventListener("itemdragstart", function (evt) {

    // Store the index of the item from the data source of 
    // the ListView in the DataTransfer object of the event.
    evt.detail.dataTransfer.setData("Text",
        JSON.stringify(evt.detail.dragInfo.getIndices()));
});

// Allows the drop to occur. The default behavior disallows
// an element from being dropped upon another.
listViewDetailInfo.addEventListener('dragover', function (evt) {
    evt.preventDefault();
});

// Insert the content (from the ListView) into the ItemContainer.
listViewDetailInfo.addEventListener('drop', function (evt) {

    // Get the index of the selected item out of the event object.
    var dragIndex = JSON.parse(evt.dataTransfer.getData("Text")),
        dataSource = listView.winControl.itemDataSource;

    // Extract the selected data from the data source 
    // connected to the ListView control.
    dataSource.itemFromIndex(Number(dragIndex)).
        then(function (item) {
            if (item) {
                var itemData = item.data;

                // Update the ItemContainer with the data from
                // the item dragged from the ListView control.
                listViewDetailInfo.querySelector('h4').innerText = itemData.title;
                listViewDetailInfo.querySelector('h6').innerText = itemData.text;
                istViewDetailInfo.querySelector('span').innerText = itemData.description;
            }
        });

});

No exemplo anterior, os dados selecionados arrastados de ListView foram armazenados no objeto DataTransfer associado ao evento itemdragstart. Como ambos os manipuladores podem acessar a mesma fonte de dados, apenas o índice do item selecionado é armazenado. Caso contrário, você poderia serializar o objeto como uma cadeia de caracteres formatada em JSON no objeto DataTransfer.

No manipulador do evento dragover para ItemContainer, o comportamento padrão é suprimido (o comportamento padrão é não permitir que um elemento seja solto em outro). No manipulador de eventos drop do objeto ItemContainer, o índice do item selecionado da fonte de dados é extraído do objeto DataTransfer e depois recuperado da fonte de dados de ListView. Finalmente, o HTML de ItemContainer é atualizado com os novos dados.

Observação   Se o aplicativo reordenar ou arrastar e soltar itens entre grupos em um controle ListView agrupado, você terá de remover os itens da fonte de dados e depois reinseri-los no novo grupo. Não é possível usar moveAfter, moveBefore ou moveToStart para fazer isso.

 

Etapa 4: Adicionar a funcionalidade de soltar a um ListView

Você pode adicionar a funcionalidade de soltar a um controle ListView da mesma forma que ela foi adicionada ao controle ItemContainer no exemplo anterior.

Use o exemplo de código para adicionar o recurso de soltar dados de ItemContainer a ListView.

Para usar esse código com a amostra anterior, adicione-o ao manipulador de eventos app.onactivated definido no arquivo default.js fornecido no modelo Blank app (js/default.js).

// Drop content (from the ItemContainer) onto the ListView control.
listView.addEventListener("itemdragdrop", function (evt) {
    if (evt.detail.dataTransfer) {
        var dragData = JSON.parse(
            evt.detail.dataTransfer.getData("Text"));

        // It's a good idea to validate the data before 
        // attempting to insert it into the data source!
        if (dragData && dragData.title && dragData.text) {
            var dropIndex = evt.detail.insertAfterIndex;

            // Insert the new item into the data source.
            DataExample.itemList.splice(dropIndex, 0, {
                title: dragData.title,
                text: dragData.text,
                description: dragData.description
            });
        }
    }
});

// Allows the drop to occur. The default behavior disallows
// an element from being dropped upon another.
listView.addEventListener("itemdragenter", function (evt) {
    if (evt.detail.dataTransfer &&
        evt.detail.dataTransfer.types.contains("Text")) {
        evt.preventDefault();
    }
});

// Drag content from the ItemContainer.
listViewDetailInfo.addEventListener('dragstart', function (evt) {

    // Get the data displayed in the ItemContainer and
    // store it in an anonymous object.
    var target = evt.target,
        title = target.querySelector('h4').innerText,
        text = target.querySelector('h6').innerText,
        description = target.querySelector('span').innerText,
        dragData = {
            source: target.id,
            title: title,
            text: text,
            description: description
        };
    
    // Store the data in the DataTransfer object as a
    // JSON-formatted string.                
    evt.dataTransfer.setData("Text", 
        JSON.stringify(dragData));
});

No exemplo de código anterior, um manipulador de eventos foi adicionado ao evento dragstart de ItemContainer e também aos eventos itemdragenter e itemdragdrop do controle ListView. O manipulador do ItemContainer.dragstart evento extrai os dados de ItemContainer e os armazena no objeto DataTransfer associado ao evento como uma cadeia de caracteres formatada em JSON. No manipulador de eventos ListView.onitemdragenter, o comportamento padrão do evento é suprimido para permitir que o conteúdo HTML seja solto no controle ListView. Por fim, quando o evento ListView.onitemdragdrop é acionado, os dados são extraídos do objeto DataTransfer e inseridos na fonte de dados do controle ListView.

Observação   Se o usuário tentar reordenar um controle ListView usando o teclado, o objeto DataTransfer passado como argumento para o evento itemdragdrop ficará indefinido. No manipulador do evento itemdragdrop, você tem de verificar se o objeto DataTransfer existe antes de tentar ler seus dados.

 

Comentários

Para saber mais sobre como usar os controles ListView e habilitar as funcionalidades de reordenar, arrastar e soltar nos controles ListView, veja o exemplo de como reordenar, arrastar e soltar ListView em HTML.

Exemplo completo

Tópicos relacionados

Amostra de ações reordenar, arrastar e soltar de ListView em HTML

Controles