Share via


ListView에서 순서 다시 매기기, 끌기 및 놓기를 사용하도록 설정하는 방법

[ 이 문서는 Windows 런타임 앱을 작성하는 Windows 8.x 및 Windows Phone 8.x 개발자를 대상으로 합니다. Windows 10용으로 개발하는 경우에는 최신 설명서를 참조하세요.]

ListView 컨트롤에 항목 순서 다시 매기기, 끌기 및 놓기 기능을 추가하는 방법을 알아봅니다. (Windows만 해당)

알아야 할 사항

기술

사전 요구 사항

  • WinJS 컨트롤을 사용하는 JavaScript로 작성한 기본 Windows 스토어 앱을 만들 수 있어야 합니다. WinJS 컨트롤을 시작하는 방법에 대한 자세한 내용은 빠른 시작: WinJS 컨트롤 및 스타일 추가를 참조하세요.

  • 기능을 추가하기 전에 기본 ListView 컨트롤을 만드는 방법을 알아야 합니다. 간단한 ListView를 만드는 방법을 빠르게 살펴보려면 빠른 시작: ListView 추가를 참조하거나 ListView 컨트롤 참조를 검토하세요.

지침

단계 1: 예제 설정

이 예제에서는 ListView 컨트롤 및 목록의 항목 정보를 표시하기 위한 ItemContainer를 만드는 방법을 보여줍니다.

다음 HTML 태그를 ListView 컨트롤의 토대로 사용합니다. 코드를 복사하여 Microsoft Visual Studio 2013의 새 응용 프로그램에 있는 default.html 파일에 붙여 넣을 수 있습니다.

<!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 스타일을 사용하여 HTML 페이지의 ListView 컨트롤과 ItemContainer를 조정합니다. ListView 컨트롤(빈 앱 템플릿의 css/default.css)과 연결된 스타일시트에 다음 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 컨트롤을 채웁니다. 데이터는 js 폴더에 포함된 'data.js' 파일(js/data.js)에 있습니다. 다음 지침에 따라 ListView 데이터를 앱에 추가합니다.

Dn423315.wedge(ko-kr,WIN.10).gifJavaScript 데이터 파일을 앱에 추가하려면

  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, moveAftermoveToStart 메서드를 구현해야 합니다. 실제로 WinJS에서 제공하는 List 개체를 사용하여 데이터 원본을 래핑하는 것이 좋습니다.

또한 앱의 HTML 태그에서 정의된 Template 개체는 titletext 속성을 가진 항목이 포함된 데이터 원본을 사용합니다. 데이터에 title 또는 text 속성이 없는 경우 Template 개체의 정의를 조정해야 합니다.

 

단계 2: ListView 컨트롤에 순서 다시 매기기 접근 권한 값 추가

ListView 컨트롤에 순서 다시 매기기 접근 권한 값을 쉽게 추가할 수 있습니다. 코드를 약간만 변경하거나 추가하면 됩니다. 기본적으로 ListView 컨트롤의 itemsReorderable 속성을 '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>

다음 예제는 런타임에 JavaScript를 사용하여 ListView 컨트롤에 순서 다시 매기기 접근 권한 값을 추가하는 방법을 보여 줍니다.

(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 ...

})();

ListView 컨트롤의 itemsReorderable 속성을 변경한 후 프로젝트를 실행합니다(F5 키를 누름). ListView에서 항목을 선택하고 동일한 ListView 내의 다른 위치로 끕니다.

단계 3: ListView에 끌기 기능 추가

기본 수준에서, 순서 다시 매기기 기능을 추가하는 것만큼 쉽게 ListView 컨트롤에 끌기 접근 권한 값을 추가할 수 있습니다. ListView 컨트롤에는 컨트롤의 HTML에서 선언적으로 설정하거나 런타임에 변경할 수 있는 itemsDraggable 속성이 있습니다.

다음 예제는 컨트롤의 HTML 태그에서 ListView에 단순한 끌기 기능을 추가하는 방법을 보여 줍니다.

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

다음 예제는 런타임에 JavaScript를 사용하여 ListView 컨트롤에 단순한 끌기 기능을 추가하는 방법을 보여 줍니다.

(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의 일부 끌어서 놓기 이벤트에 대한 처리기도 구현해야 합니다. 다음 예제에서는 처리기가 ItemContainerdragoverdrop 이벤트는 물론 ListView.itemdragstart 이벤트에도 추가되었습니다.

이전 샘플과 함께 이 코드를 사용하려면 Blank app 템플릿에 제공된 default.js 파일(js/default.js)에서 정의된 app.onactivated 이벤트 처리기에 이 코드를 추가합니다.

// 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에서 선택하여 끌어온 데이터는 itemdragstart 이벤트와 연결된 DataTransfer 개체에 저장되었습니다. 두 처리기 모두 동일한 데이터 원본에 액세스할 수 있으므로 선택한 항목의 인덱스만 저장됩니다. 그렇지 않으면 개체를 DataTransfer 개체에 JSON 형식 문자열로 직렬화할 수 있습니다.

ItemContainer에 대한 dragover 이벤트 처리기에서 기본 동작이 억제됩니다(기본 동작은 한 요소를 다른 요소에 놓을 수 없도록 차단함). ItemContainer 개체에 대한 drop 이벤트 처리기에서는 데이터 원본에서 선택한 항목의 인덱스가 DataTransfer 개체에서 추출된 다음 ListView의 데이터 원본에서 항목이 검색됩니다. 마지막으로, ItemContainer의 HTML이 새 데이터로 업데이트됩니다.

참고   앱이 그룹화된 ListView 컨트롤의 그룹 간에 항목을 끌어서 놓거나 항목의 순서를 다시 매기는 경우 데이터 원본에서 항목을 제거한 다음 새 그룹에 다시 삽입해야 합니다. 이 경우 moveAfter, moveBefore 또는 moveToStart를 사용할 수 없습니다.

 

단계 4: ListView에 놓기 기능 추가

이전 예제에서 ItemContainer 컨트롤에 끌기 기능을 추가한 방법과 비슷하게 ListView 컨트롤에 놓기 기능을 추가할 수 있습니다.

다음 코드 예제를 사용하여 ItemContainer에서 ListView로 데이터를 끌어 놓는 기능을 추가합니다.

이전 샘플과 함께 이 코드를 사용하려면 Blank app 템플릿에 제공된 default.js 파일(js/default.js)에서 정의된 app.onactivated 이벤트 처리기에 이 코드를 추가합니다.

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

이전 코드 예제에서는 이벤트 처리기가 ListViewitemdragenteritemdragdrop 이벤트는 물론 ItemContainerdragstart 이벤트에도 추가되었습니다. ItemContainer.dragstart 이벤트 처리기는 ItemContainer에서 데이터를 추출하여 이벤트와 연결된 DataTransfer 개체에 JSON 형식 문자열로 저장합니다. ListView.onitemdragenter 이벤트 처리기에서 이벤트의 기본 동작이 HTML 콘텐츠를 ListView 컨트롤에 끌어 놓을 수 있도록 억제되었습니다. 마지막으로, ListView.onitemdragdrop 이벤트가 발생하면 DataTransfer 개체에서 데이터가 추출된 다음 ListView 컨트롤의 데이터 원본에 삽입됩니다.

참고   사용자가 키보드를 사용하여 ListView 컨트롤의 순서를 다시 매기려고 하면 itemdragdrop 이벤트에 인수로 전달되는 DataTransfer 개체가 정의되지 않습니다. itemdragdrop 이벤트 처리기에서 개체에 포함된 데이터를 읽기 전에 DataTransfer 개체가 있는지 확인해야 합니다.

 

설명

ListView 컨트롤을 사용하고 ListView 컨트롤 내에서 순서 다시 매기기, 끌기 및 놓기를 사용하도록 설정하는 방법에 대한 자세한 내용은 HTML ListView 끌어서 놓기 및 순서 다시 매기기 샘플을 참조하세요.

전체 예제

관련 항목

HTML ListView 끌어서 놓기 및 순서 다시 매기기 샘플

컨트롤