Share via


Cómo habilitar funcionalidades para reordenar, arrastrar y colocar en un ListView

[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows Runtime. Si estás desarrollando para Windows 10, consulta la documentación más reciente ]

Aprende cómo agregar características para reordenar, arrastrar y colocar elementos a un control ListView. (solo Windows)

Lo que debes saber

Tecnologías

Requisitos previos

  • Debes saber crear una aplicación de la Tienda Windows básica con JavaScript que use controles de WinJS. Para obtener instrucciones sobre cómo empezar a usar controles de WinJS, consulta Inicio rápido: Agregar controles y estilos de WinJS.

  • Antes de agregar más funcionalidad, conviene que sepas cómo crear un control ListView básico. Para ver una introducción rápida sobre cómo crear un ListView sencillo, consulta Inicio rápido: Agregar un ListView o repasa la referencia del control ListView.

Instrucciones

Paso 1: Configurar el ejemplo

En este ejemplo se explica cómo crear un control ListView y un ItemContainer para mostrar información sobre un elemento de la lista.

Usa el siguiente marcado HTML como base para el control ListView. Puedes copiar y pegar el código en el archivo default.html en una Aplicación vacía en 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>

En el ejemplo se usan también estilos CSS para ajustar el control ListView y ItemContainer en la página HTML. Agrega el siguiente código CSS a la hoja de estilos asociada con el control ListView (css/default.css en la plantilla Aplicación vacía).


/* 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;
}

En el ejemplo se usan algunos datos predefinidos con los que se rellena el control ListView. Los datos están incluidos en un archivo denominado 'data.js' situado dentro de la carpeta js (js/data.js). Usa las siguientes instrucciones para agregar los datos de ListView a la aplicación.

Dn423315.wedge(es-es,WIN.10).gifPara agregar un archivo de datos JavaScript a tu aplicación

  1. En el Explorador de soluciones, haz clic con el botón secundario en la carpeta js y haz clic en Agregar > Nuevo archivo JavaScript.

  2. En el cuadro de diálogo Agregar nuevo elemento, en el cuadro Nombre, escribe 'data.js' y haz clic en Agregar.

  3. En el Explorador de soluciones, haz doble clic en el nuevo archivo JavaScript y agrega el código siguiente.

    (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
        });
    
    })();
    

Nota  Puedes reemplazar los datos proporcionados con los datos que necesites. Para reemplazar el origen de datos, puedes cambiar el conjunto de datos que se pasa al método constructor WinJS.Binding.List.

Si decides usar un origen de datos que no sea un objeto IListDataSource, dicho origen debe implementar los métodos moveBefore, moveAfter y moveToStart. En la práctica, es recomendable que uses el objeto List proporcionado por WinJS para contener el origen de datos.

Ten en cuenta también que el objeto Template definido en el marcado HTML de la aplicación toma un origen de datos que contiene elementos con las propiedades title y text. Si tus datos no contienen las propiedades title o text, debes ajustar la definición del objeto Template.

 

Paso 2: Agregar funcionalidad para reordenar al control ListView

Se pueden agregar funcionalidades para reordenar a un control ListView con suma facilidad. Solo es necesario un pequeño cambio o adición al código. Básicamente, lo único que hay que hacer es establecer la propiedad itemsReorderable del control ListView en 'true' (el valor predeterminado es 'false').

Puedes hacerlo mediante declaración en el marcado HTML del control o puedes agregar esta funcionalidad en tiempo de ejecución usando JavaScript. Este ejemplo muestra cómo agregar la funcionalidad para reordenar ajustando el marcado HTML del control.

<!-- 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>

En el siguiente ejemplo se indica cómo agregar la funcionalidad para reordenar a un control ListView en tiempo de ejecución mediante 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 ...

})();

Después de cambiar la propiedad itemsReorderable del control ListView, ejecuta el proyecto (presiona F5). Selecciona un elemento de ListView y arrástralo a otra ubicación dentro del mismo ListView.

Paso 3: Agregar funcionalidad para arrastrar a un control ListView

En un nivel básico, puedes agregar funcionalidad para arrastrar a un control ListView tan fácilmente como se agrega la funcionalidad para reordenar. El control ListView contiene una propiedad itemsDraggable que puede definirse mediante declaración en el código HTML del control, o bien modificarse en tiempo de ejecución.

El ejemplo siguiente muestra cómo agregar una sencilla funcionalidad para arrastrar a un ListView en el marcado HTML del control.

<!-- 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>

En el siguiente ejemplo se indica cómo agregar funcionalidad básica para arrastrar a un control ListView en tiempo de ejecución mediante 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 ...

})();

Después de establecer la propiedad itemsDraggable en true, ejecuta la aplicación (presiona F5). En la aplicación, selecciona un elemento del control ListView y arrástralo fuera de ListView. El elemento es un elemento fantasma en la interfaz de la aplicación fuera de ListView. Al soltar el botón del mouse, el elemento desaparece. Tras ello, se activan los eventos para colocar correspondientes.

Si quieres interactuar con el origen de datos subyacente de un control ListView, debes implementar también controladores para algunos de los eventos de arrastrar y colocar de ListView. En el siguiente ejemplo se ha agregado un controlador al evento ListView.itemdragstart, así como a los eventos dragover y drop del ItemContainer.

Para usar este código con el ejemplo anterior, agrega este código al controlador del evento app.onactivated definido en el archivo default.js proporcionado en la plantilla 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;
            }
        });

});

En el ejemplo anterior, los datos seleccionados arrastrados desde ListView se han almacenado en el objeto DataTransfer asociado al evento itemdragstart. Dado que ambos controladores pueden acceder al mismo origen de datos, solo se almacena el índice del elemento seleccionado. De lo contrario, podrías serializar el objeto como una cadena con el formato JSON en el objeto DataTransfer.

En el controlador del evento dragover de ItemContainer, se suprime el comportamiento predeterminado, que es no permitir colocar un elemento encima de otro. En el controlador del evento drop del objeto ItemContainer, el índice del elemento seleccionado del origen de datos se extrae del objeto DataTransfer y, luego, el elemento se recupera del origen de datos de ListView. Por último, el código HTML del ItemContainer se actualiza con los nuevos datos.

Nota   Si tu aplicación reordena, arrastra o coloca elementos entre grupos de un control ListView agrupado, debes quitar los elementos del origen de datos y, después, volver a insertarlos en el nuevo grupo. No puedes usar moveAfter, moveBefore ni moveToStart para lograr esto.

 

Paso 4: Agregar funcionalidad para colocar a un control ListView

Puedes agregar funcionalidad para colocar a un control ListView del mismo modo en que la hemos agregado al control ItemContainer del ejemplo anterior.

Usa el siguiente código de ejemplo para agregar la capacidad de colocar datos desde ItemContainer en ListView.

Para usar este código con el ejemplo anterior, agrega este código al controlador del evento app.onactivated definido en el archivo default.js proporcionado en la plantilla 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));
});

En el ejemplo de código anterior, se agrega un controlador de eventos al evento dragstart de ItemContainer, así como los eventos itemdragenter e itemdragdrop del control ListView. El controlador del evento ItemContainer.dragstart extrae los datos del ItemContainer y los almacena en el objeto DataTransfer asociado con el evento como una cadena con formato JSON. En el controlador de eventos ListView.onitemdragenter, el comportamiento predeterminado del evento se suprime para poder colocar contenido HTML en el control ListView. Finalmente, cuando el evento ListView.onitemdragdrop se genera, los datos se extraen del objeto DataTransfer y, luego, se insertan en el origen de datos del control ListView.

Nota   Si el usuario intenta reordenar un control ListView con el teclado, el objeto DataTransfer pasado como argumento al evento itemdragdrop no estará definido. En el controlador del evento itemdragdrop, debes asegurarte de que el objeto DataTransfer existe antes de leer los datos que contiene.

 

Observaciones

Para obtener más información sobre cómo usar los controles ListView y poder reordenar, arrastrar y colocar en los controles ListView, consulta la Muestra en HTML para reordenar, arrastrar y colocar un ListView.

Ejemplo completo

Temas relacionados

Muestra en HTML para reordenar, arrastrar y colocar un ListView

Controles