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 の作成方法を示します。

ListView コントロールの基盤として次の HTML マークアップを使います。このコードをコピーして、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>

この例では、HTML ページの ListView コントロールと ItemContainer を調整するために CSS スタイルも使います。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 フォルダー (js/data.js) 内の 'data.js' という名前のファイルに格納されています。次の手順を使って、アプリに ListView データを追加します。

Dn423315.wedge(ja-jp,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 メソッド、moveAfter メソッド、moveToStart メソッドを実装する必要があります。実際には、データ ソースをラップするために WinJS で提供される List オブジェクトを使うことをお勧めします。

アプリの HTML マークアップで定義された Template オブジェクトが、title プロパティと text プロパティを持つ項目を含むデータ ソースを使う点にも注意してください。データが 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 の一部のドラッグ アンド ドロップ イベントのハンドラーを実装することも必要です。次の例では、ハンドラーが ItemContainerdragover イベントと drop イベントのほか、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 形式の文字列としてシリアル化することができます。

ItemContainerdragover イベントのハンドラーでは、既定の動作は抑制されます (既定の動作では、ある要素を別の要素にドロップすることを許可していません)。ItemContainer オブジェクトの drop イベント ハンドラーで、データ ソースから選ばれた項目のインデックスは DataTransfer オブジェクトから抽出され、その項目は ListView のデータ ソースから取得されます。最後に、ItemContainer の HTML が、新しいデータで更新されます。

   アプリのグループ化された ListView コントロールで、項目をグループ間で並べ替えたり、ドラッグ アンド ドロップしたりした場合、データ ソースから項目を削除し、もう一度新しいグループに挿入する必要があります。これには、moveAftermoveBeforemoveToStart を使うことはできません。

 

ステップ 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));
});

前のコード例では、イベント ハンドラーは、ListView コントロールの itemdragenter イベントと itemdragdrop イベントのほか、ItemContainerdragstart イベントに追加されます。ItemContainer.dragstart イベントのハンドラーは、ItemContainer からデータを抽出し、イベントに関連付けられた DataTransfer オブジェクトに JSON 形式の文字列として保存します。ListView.onitemdragenter イベント ハンドラーでは、イベントの既定の動作が抑制されており、ListView コントロールに HTML コンテンツをドロップできます。最後に ListView.onitemdragdrop イベントが発生すると、データは DataTransfer オブジェクトから抽出され、ListView コントロールのデータ ソースに挿入されます。

   ユーザーがキーボードを使って ListView コントロールを並べ替えようとする場合、引数として itemdragdrop イベントに渡された DataTransfer オブジェクトは定義されていません。itemdragdrop イベントのハンドラーでは、データの読み取りを試みる前に、それを格納する DataTransfer オブジェクトが存在することを確かめる必要があります。

 

注釈

ListView コントロールの使い方と、並べ替え機能、ドラッグ機能、ドロップ機能を ListView コントロールで有効にする方法について詳しくは、HTML ListView のドラッグ アンド ドロップと並べ替えのサンプルをご覧ください。

完全な例

関連トピック

HTML ListView のドラッグ アンド ドロップと並べ替えのサンプルに関するページ

コントロールの一覧