Добавление переупорядочения и перетаскивания в ListView

[ Эта статья адресована разработчикам приложений среды выполнения Windows для Windows 8.x и Windows Phone 8.x. В случае разработки приложений для Windows 10 см. раздел последняя документация]

Сведения о том, как добавить переупорядочение и перетаскивание элементов в элемент управления ListView. (только Windows)

Что необходимо знать

Технологии

Необходимые условия

Инструкции

Этап 1: Настройка примера

В этом примере показано, как создать элемент управления ListView и контейнер ItemContainer для отображения сведений об элементе в списке.

Используйте следующую разметку HTML в качестве основы для элемента управления ListView. Вы можете скопировать и вставить этот код в файл default.html из шаблона Пустое приложение в 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>

В примере также используются стили CSS для настройки элемента управления ListView и контейнера ItemContainer на HTML-странице. Добавьте приведенный ниже код CSS в таблицу стилей, связанную с элементом управления ListView (css/default.css в шаблоне Пустое приложение).


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

В примере используются некоторые предопределенные данные для заполнения элемента управления ListView. Эти данные содержатся в файле data.js, который находится в папке js (js/data.js). Чтобы добавить данные ListView в приложение, следуйте приведенным далее инструкциям.

Dn423315.wedge(ru-ru,WIN.10).gifДобавление файла данных JavaScript в приложение

  1. В окне Обозреватель решений щелкните правой кнопкой мыши папку js и выберите пункты Добавить > Новый файл JavaScript.

  2. В диалоговом окне Добавление нового элемента в поле Имя введите "data.js" и нажмите кнопку Добавить.

  3. В окне Обозреватель решений дважды щелкните новый файл JavaScript и добавьте следующий код.

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

Примечание  Приведенные данные можно заменить любыми другими по своему усмотрению. Чтобы заменить источник данных, можно изменить набор данных, передаваемый в метод конструктора WinJS.Binding.List.

Если вы хотите использовать источник данных, отличный от объекта IListDataSource, он должен реализовать методы moveBefore, moveAfter и moveToStart. На практике рекомендуется заключать источник данных в объект List, предоставляемый WinJS.

Также обратите внимание, что объект Template, определенный в разметке HTML для приложения, использует источник данных, содержащий элементы со свойствами title и text. Если ваши данные не содержат свойств title или text, необходимо скорректировать определение объекта Template.

 

Этап 2: Добавление возможностей переупорядочения в элемент управления ListView

Добавить возможности переупорядочения в элемент управления ListView очень легко. Для этого требуется лишь незначительное изменение или дополнение кода. В общем случае нужно просто задать для свойства itemsReorderable элемента управления ListView значение "true". (Значение по умолчанию — "false".)

Можно декларативно задать это свойство в разметке HTML для элемента управления либо добавить эту возможность во время выполнения при помощи JavaScript. В следующем примере показано, как добавить возможность переупорядочения, скорректировав разметку HTML для элемента управления.

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

Затем продемонстрировано добавление возможности переупорядочения в элемент управления ListView во время выполнения при помощи 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 ...

})();

Изменив свойство itemsReorderable элемента управления ListView, запустите проект (нажмите клавишу F5). Выберите элемент в ListView и перетащите его в другое расположение в том же элементе ListView.

Этап 3: Добавление функции перетаскивания в ListView

На базовом уровне добавить функцию перетаскивания в элемент управления ListView так же легко, как и возможность переупорядочения. Элемент управления ListView содержит свойство itemsDraggable, которое можно задать декларативно в разметке HTML для элемента управления либо изменить во время выполнения.

В следующем примере показано, как добавить простую функцию перетаскивания в ListView в разметке HTML для этого элемента управления.

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

Затем продемонстрировано добавление простой функции перетаскивания в элемент управления ListView во время выполнения при помощи 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 ...

})();

Задав для свойства itemsDraggable значение "true", запустите приложение (нажмите клавишу F5). В приложении выберите элемент из элемента управления ListView и перетащите его за пределы ListView. Будет создана копия элемента через интерфейс приложения за пределами ListView. Когда вы отпустите кнопку мыши, элемент исчезнет. Затем создаются соответствующие события перетаскивания.

Чтобы взаимодействовать с базовым источником данных элемента управления ListView, необходимо также реализовать обработчики некоторых событий перетаскивания ListView. В следующем примере был добавлен обработчик события ListView.itemdragstart, а также события dragover и drop контейнера ItemContainer.

Чтобы использовать этот код с предыдущим образцом, добавьте его в обработчик событий app.onactivated, определенный в файле default.js из шаблона 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;
            }
        });

});

В предыдущем примере выбранные данные, перетащенные из ListView, были сохранены в объекте DataTransfer, связанном с событием itemdragstart. Поскольку оба обработчика могут обращаться к одному и тому же источнику данных, сохраняется только индекс выбранного элемента. В противном случае вы можете сериализовать объект как строку в формате JSON в объекте DataTransfer.

В обработчике события dragover для ItemContainer обработка по умолчанию (запрет перетаскивания одного элемента на другой) блокируется. В обработчике событий drop для объекта ItemContainer индекс выбранного элемента из источника данных извлекается из объекта DataTransfer, а затем элемент извлекается из источника данных ListView. Наконец, HTML-код контейнера ItemContainer изменяется с учетом новых данных.

Примечание   Если в приложении выполняется переупорядочение или перетаскивание элементов между группами в элементе управления ListView, необходимо удалить элементы из источника данных, а затем вставить их в новую группу. Для решения этой задачи нельзя использовать методы moveAfter, moveBefore или moveToStart.

 

Этап 4: Добавление функции перетаскивания в ListView

Добавить функцию перетаскивания в элемент управления ListView можно таким же образом, как мы добавляли ее в ItemContainer в предыдущем примере.

Чтобы добавить возможность перетаскивания данных из ItemContainer в ListView, воспользуйтесь следующим примером кода.

Чтобы использовать этот код с предыдущим образцом, добавьте его в обработчик событий app.onactivated, определенный в файле default.js из шаблона 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));
});

В предыдущем примере кода был добавлен обработчик событий dragstart для контейнера ItemContainer, а также события itemdragenter и itemdragdrop элемента управления ListView. Обработчик событий ItemContainer.dragstart извлекает данные из ItemContainer и сохраняет их в объекте DataTransfer, связанном с событием, в виде строки в формате JSON. В обработчике событий ListView.onitemdragenter обработка события по умолчанию блокируется, чтобы содержимое HTML можно было перетаскивать на элемент управления ListView. Наконец, при возникновении события ListView.onitemdragdrop данные извлекаются из объекта DataTransfer и вставляются в источник данных элемента управления ListView.

Примечание   Если пользователь попытается переупорядочить элемент управления ListView при помощи клавиатуры, объект DataTransfer, передаваемый в качестве аргумента событию itemdragdrop, будет не определен. В обработчике событий itemdragdrop нужно убедиться в существовании объекта DataTransfer перед считыванием данных, которые он содержит.

 

Примечания

Подробнее об использовании элементов управления ListView и добавлении возможностей переупорядочения и перетаскивания в элементы управления ListView см. в примере перетаскивания и переупорядочения элемента управления HTML ListView.

Полный пример

Связанные разделы

Пример перетаскивания и переупорядочения элемента управления ListView на HTML

Элементы управления