Features

編集

編集

このサンプルでは、さまざまな方法でセルデータを編集する方法を示します。

機能

編集

Excel形式の編集

MultiRowでは、Excel形式の高速なセル内編集が組み込みでサポートされています。
余分な列を追加して、そこに表示モードと編集モードを切り替えるための[編集]ボタンを置く必要はありません。

ユーザーは、任意のセルでキー入力するだけで編集を開始できます。これは、「クイック編集」モードと呼ばれます。
このモードでは、矢印キーを押すと編集が終了し、グリッドの選択範囲が移動します。
[F2]キーを押すか、セルをダブルクリックすることで、編集を開始することもできます。
これは、「完全編集」モードと呼ばれます。
このモードでは、矢印キーを押すとエディタ内のカレットが移動し、編集を終了するには、Enter]、[Tab]、または[Esc]キーを押す必要があります。

グリッドオブジェクトまたは列オブジェクトのisReadOnlyプロパティを使用して、
グリッドレベルまたは列レベルで編集を無効にすることができます。

モバイルデバイス:
モバイルデバイスは、ダブルクリックイベントを使用してズームインとズームアウトを行い、
デフォルトではキーボードが表示されません。モバイルデバイスのセルの編集を開始するには、
セルをクリックして選択してから、再度クリックして編集の開始を示します。

自動型検証/強制:
ユーザーが列に無効な値(数値列または日付列に対して「hello」など)を入力すると、
その編集は適用されず、
セルは元の値を維持します。日時は、列に割り当てられた書式で解析されます。

チェックボックス:
デフォルトでは、(Excelと異なり)Boolean値はチェックボックスとして表示されます。ユーザーは、
スペースバーをクリックするか押して、チェックボックスの値を変更できます。
チェックボックスは、「TRUE」文字列や
「FALSE」文字列を含むフィールドよりも読みやすく、編集が容易です。

編集モード:
データを更新するには、次の2つのモードがあります。
デフォルトでは、編集が終了すると更新操作がサーバーにコミットされます。
ユーザーが更新操作をデータソースサーバーにコミットする場合は、更新アクション、削除アクション、または作成アクションのURLを提供する必要があります。
また、データソースを更新するために使用するコードは、対応するアクション内に記述する必要があります。
もう1つのモードはBatchEditです。ユーザーは複数の項目を更新、作成、または削除できます。
これらの変更は、確認後に1回だけデータソースに対してコミットされます。
これで、これらの変更はクライアント側のCollectionViewcommitメソッドによってコミットできます。
ユーザーは、ソート動作、ページング動作、またはフィルタ処理動作によってこれらをコミットすることもできます。

典型的な編集可能MultiRowを次に示します。

ポップアップ編集

ポップアップ編集は、Excel形式のクイックデータ入力を行うネイティブ編集を有効にしたまま、ユーザーが項目の詳細を編集するためのフォームを呼び出す[詳細の編集]ボタンを追加します。

この動作を確認するには、グリッドの項目を選択し、上の[詳細の編集]ボタンをクリックします。
これにより、現在の選択項目のデータをユーザーが編集できるフォームが表示されます。

詳細フォームは、より多くのスペースを必要とする一方で場合によってはデータ入力が容易になる特別な入力コントロールを使用します。このフォームには、変更をコミットする[OK]ボタンと元のデータを復元する[キャンセル]ボタンがあります。どちらのアクションも、グリッドのデータソースとして使用されるCollectionViewの1回の呼び出しで実行されます。


インライン編集

何らかの理由でExcel形式の編集を避け、各行に編集ボタンを追加する場合は(編集可能HTMLテーブルなど)、1つのItemFormatterといくつかのコントローラメソッドを使用してこれを実現できます。
ItemFormatterイベントハンドラで連結列を取得するには、MultiRowのgetBindingColumn関数を使用してください。

次のグリッドは、この方法を示します。セルのボタンは、コントローラのメソッドを呼び出して必要なアクションを実行します。

using C1.Web.Mvc;
using System;
using System.Linq;
using C1.Web.Mvc.Serialization;
using Microsoft.AspNetCore.Mvc;
using MultiRowExplorer.Models;
using System.Data.SqlClient;
using Microsoft.EntityFrameworkCore;

namespace MultiRowExplorer.Controllers
{
    public partial class MultiRowController : Controller
    {
        private readonly C1NWindEntities _db;

        public MultiRowController(C1NWindEntities db)
        {
            _db = db;
        }

        public ActionResult Editing()
        {
            return View();
        }

        public ActionResult MultiRowBindSupplier([C1JsonRequest] CollectionViewRequest<Supplier> requestData)
        {
            return this.C1Json(CollectionViewHelper.Read(requestData, _db.Suppliers.ToList()));
        }

        public ActionResult MultiRowUpdateSupplier([C1JsonRequest]CollectionViewEditRequest<Supplier> requestData)
        {
            return Update(requestData, _db.Suppliers);
        }

        public ActionResult MultiRowCreateSupplier([C1JsonRequest]CollectionViewEditRequest<Supplier> requestData)
        {
            var supplier = requestData.OperatingItems.First();
            if (supplier.CompanyName == null)
            {
                supplier.CompanyName = "";
            }

            return Create(requestData, _db.Suppliers);
        }

        public ActionResult MultiRowDeleteSupplier([C1JsonRequest]CollectionViewEditRequest<Supplier> requestData)
        {
            return Delete(requestData, _db.Suppliers, item => item.SupplierID);
        }


        public ActionResult MultiRowBindCustomer([C1JsonRequest] CollectionViewRequest<Customer> requestData)
        {
            return this.C1Json(CollectionViewHelper.Read(requestData, _db.Customers.ToList()));
        }

        public ActionResult MultiRowUpdateCustomer([C1JsonRequest]CollectionViewEditRequest<Customer> requestData)
        {
            return Update(requestData, _db.Customers);
        }

        public ActionResult MultiRowCreateCustomer([C1JsonRequest]CollectionViewEditRequest<Customer> requestData)
        {
            return Create(requestData, _db.Customers);
        }

        public ActionResult MultiRowDeleteCustomer([C1JsonRequest]CollectionViewEditRequest<Customer> requestData)
        {
            return Delete(requestData, _db.Customers, item => item.CustomerID);
        }

        private ActionResult Update<T>(CollectionViewEditRequest<T> requestData, DbSet<T> data) where T : class
        {
            return this.C1Json(CollectionViewHelper.Edit<T>(requestData, item =>
            {
                string error = string.Empty;
                bool success = true;
                try
                {
                    _db.Entry(item as object).State = EntityState.Modified;
                    _db.SaveChanges();
                }
                catch (Exception e)
                {
                    error = GetExceptionMessage(e);
                    success = false;
                }
                return new CollectionViewItemResult<T>
                {
                    Error = error,
                    Success = success,
                    Data = item
                };
            }, () => data.ToList<T>()));
        }

        private ActionResult Create<T>(CollectionViewEditRequest<T> requestData, DbSet<T> data) where T : class
        {
            return this.C1Json(CollectionViewHelper.Edit<T>(requestData, item =>
            {
                string error = string.Empty;
                bool success = true;
                try
                {
                    data.Add(item);
                    _db.SaveChanges();
                }
                catch (Exception e)
                {
                    error = GetExceptionMessage(e);
                    success = false;
                }
                return new CollectionViewItemResult<T>
                {
                    Error = error,
                    Success = success,
                    Data = item
                };
            }, () => data.ToList<T>()));
        }

        private ActionResult Delete<T>(CollectionViewEditRequest<T> requestData, DbSet<T> data, Func<T, object> getKey) where T : class
        {
            return this.C1Json(CollectionViewHelper.Edit(requestData, item =>
            {
                string error = string.Empty;
                bool success = true;
                try
                {
                    T resultItem = null;
                    foreach (var i in data)
                    {
                        if (string.Equals(getKey(i).ToString(), getKey(item).ToString()))
                        {
                            resultItem = i;
                            break;
                        }
                    }

                    if (resultItem != null)
                    {
                        data.Remove(resultItem);
                        _db.SaveChanges();
                    }
                }
                catch (Exception e)
                {
                    error = GetExceptionMessage(e);
                    success = false;
                }
                return new CollectionViewItemResult<T>
                {
                    Error = error,
                    Success = success,
                    Data = item
                };
            }, () => data.ToList()));
        }

        /// <summary>
        /// In order to get the real exception message.
        /// </summary>
        private static SqlException GetSqlException(Exception e)
        {
            while (e != null && !(e is SqlException))
            {
                e = e.InnerException;
            }
            return e as SqlException;
        }

        // Get the real exception message
        internal static string GetExceptionMessage(Exception e)
        {
            var msg = e.Message;
            var sqlException = GetSqlException(e);
            if (sqlException != null)
            {
                msg = sqlException.Message;
            }
            return msg;
        }
    }
}
@model C1NWindEntities
@{
    ViewBag.DemoDescription = false;
}

@section Scripts{
    <script type="text/javascript" src="~/Scripts/jquery.js"></script>
    <script type="text/javascript" src="~/Scripts/BootStrap/bootstrap.js"></script>

    <script>
        var editMultiRow, editCV,
            showEditDialogBtn,
            idInput, companyNameInput, contactNameInput, contactTitleInput, countryInput, regionInput, cityInput, addressInput;

        c1.documentReady(function () {
            editMultiRow = wijmo.Control.getControl('#editMultiRow');
            editCV = editMultiRow.collectionView;
            showEditDialogBtn = document.getElementById('showEditDialogBtn');
            idInput = document.getElementById('SupplierID');
            companyNameInput = document.getElementById('CompanyName');
            contactNameInput = document.getElementById('ContactName');
            contactTitleInput = document.getElementById('ContactTitle');
            countryInput = document.getElementById('Country');
            regionInput = document.getElementById('Region');
            cityInput = document.getElementById('City');
            addressInput = document.getElementById('Address');

            updateButton();
            editCV.currentChanged.addHandler(updateButton);
        });
        function showEditDialog() {
            var current;

            if (!editCV || !editCV.currentItem) {
                return;
            }
            current = editCV.currentItem;
            // fill the current item data to the inputs.
            idInput.value = current.SupplierID || '';
            companyNameInput.value = current.CompanyName || '';
            contactNameInput.value = current.ContactName || '';
            contactTitleInput.value = current.ContactTitle || '';
            countryInput.value = current.Country || '';
            regionInput.value = current.Region || '';
            cityInput.value = current.City || '';
            addressInput.value = current.Address || '';
        }
        function updateButton() {
            if (!showEditDialogBtn) {
                return;
            }
            if (!editCV || !editCV.currentItem) {
                showEditDialogBtn.disabled = true;
            } else {
                showEditDialogBtn.disabled = false;
            }
        }
        function commitUpdate() {
            if (!editCV) {
                return;
            }

            var editItem = editCV.currentItem;

            // begin to edit the current item
            editCV.editItem(editItem);

            //update the data
            editItem.CompanyName = companyNameInput.value;
            editItem.ContactName = contactNameInput.value;
            editItem.ContactTitle = contactTitleInput.value;
            editItem.Country = countryInput.value;
            editItem.Region = regionInput.value;
            editItem.City = cityInput.value;
            editItem.Address = addressInput.value;
            // commit the edit
            editCV.commitEdit();
        }

        var inlineEditMultiRow, inlineEditCV,
            editIndex = -1;
        c1.documentReady(function () {
            inlineEditMultiRow = wijmo.Control.getControl('#inlineEditMultiRow');
            inlineEditMultiRow.rows.defaultSize = 50;
            inlineEditCV = inlineEditMultiRow.collectionView;
        });
        function itemFormatter(panel, r, c, cell) {
            var col, html, hasUpdated = false;
            var rowIndex = Math.floor(r / panel.grid.rowsPerItem);
            if (panel.cellType == wijmo.grid.CellType.Cell) {
                col = panel.grid.getBindingColumn(panel, r, c);
                if (rowIndex == editIndex) {
                    switch (col.name) {
                        case "CustomerID":
                            break;
                        case 'Buttons':
                            html = '<div>' +
                                '&nbsp;&nbsp;' +
                                '<button class="btn btn-primary btn-sm" style="width:80px;" onclick="commitRow(' + rowIndex + ')">' +
                                '<span class="glyphicon glyphicon-ok"></span> OK' +
                                '</button>' +
                                '<br/>&nbsp;&nbsp;' +
                                '<button class="btn btn-warning btn-sm" style="width:80px;" onclick="cancelRow(' + rowIndex + ')">' +
                                '<span class="glyphicon glyphicon-ban-circle"></span> Cancel' +
                                '</button>' +
                                '</div>';
                            hasUpdated = true;
                            break;
                        default:
                            var theId = "the" + col.name;
                            html = '<input id="' + theId + '" class="form-control" onkeydown="keyDown(event)" value="' + panel.getCellData(r, c, true) + '"/>';
                            hasUpdated = true;
                            break;
                    }
                }
                else {
                    switch (col.name) {
                        case 'Buttons':
                            hasUpdated = true;
                            html = '<div>' +
                                '&nbsp;&nbsp;' +
                                '<button class="btn btn-default btn-sm" style="width:80px;" onclick="editRow(' + rowIndex + ')">' +
                                '<span class="glyphicon glyphicon-pencil"></span> Edit' +
                                '</button>' +
                                '<br/>&nbsp;&nbsp;' +
                                '<button class="btn btn-default btn-sm" style="width:80px;" onclick="deleteRow(' + rowIndex + ')">' +
                                '<span class="glyphicon glyphicon-remove"></span> Delete' +
                                '</button>' +
                                '</div>';
                            break;
                    }
                }
                if (hasUpdated) {
                    cell.innerHTML = html;
                    cell.style.padding = '3px';
                }
            }
        }
        function scrollPositionChanged() {
            cancelEditingMode();
        }
        function resizingColumn() {
            cancelEditingMode();
        }
        function draggingColumn() {
            cancelEditingMode();
        }
        function sortingColumn() {
            cancelEditingMode();
        }
        function cancelEditingMode() {
            if (editIndex > -1) {
                cancelRow(editIndex);
            }
        }
        function keyDown(e) {
            e.stopPropagation();
        }
        function editRow(rowIndex) {
            if (!inlineEditMultiRow || !inlineEditCV) {
                return;
            }
            editIndex = rowIndex;
            inlineEditMultiRow.invalidate();
        }
        function deleteRow(rowIndex) {
            if (!inlineEditCV) {
                return;
            }
            editIndex = -1;
            inlineEditCV.removeAt(rowIndex);
        }
        function commitRow(rowIndex) {
            var countryInput, addressInput, editItem;
            if (!inlineEditCV) {
                return;
            }
            //update the data
            inlineEditCV.editItem(inlineEditCV.items[rowIndex]);
            editItem = inlineEditCV.currentEditItem;
            if (!editItem) {
                return;
            }
            editItem.CompanyName = document.getElementById('theCompanyName').value;
            editItem.ContactName = document.getElementById('theContactName').value;
            editItem.ContactTitle = document.getElementById('theContactTitle').value;
            editItem.Country = document.getElementById('theCountry').value;
            editItem.Region = document.getElementById('theRegion').value;
            editItem.City = document.getElementById('theCity').value;
            editItem.Address = document.getElementById('theAddress').value;
            editIndex = -1;
            inlineEditCV.commitEdit();
        }

        function cancelRow() {
            editIndex = -1;
            inlineEditMultiRow.invalidate();
        }
    </script>
}

@section Summary{
    @Html.Raw(MultiRowRes.Editing_Text25)
}

    <h3>
        @Html.Raw(MultiRowRes.Editing_Text27)
    </h3>

<h4>
    @Html.Raw(MultiRowRes.Editing_Text26)
</h4>
<p>@Html.Raw(MultiRowRes.Editing_Text0)</p>

<p>@Html.Raw(MultiRowRes.Editing_Text1)</p>

<div class="collapsed-content collapse">
    <p>@Html.Raw(MultiRowRes.Editing_Text2)</p>

    <p>@Html.Raw(MultiRowRes.Editing_Text3)</p>

    <p>@Html.Raw(MultiRowRes.Editing_Text4)</p>

    <p>@Html.Raw(MultiRowRes.Editing_Text5)</p>

    <p>@Html.Raw(MultiRowRes.Editing_Text6)</p>

</div>

<p>@Html.Raw(MultiRowRes.Editing_Text7)</p>

<p>@Html.Raw(MultiRowRes.Editing_Text8)</p>

<c1-multi-row id="editMultiRow" allow-add-new="true" allow-delete="true" class="multirow">
    <c1-items-source read-action-url="@Url.Action("MultiRowBindSupplier")"
                     update-action-url="@Url.Action("MultiRowUpdateSupplier")"
                     create-action-url="@Url.Action("MultiRowCreateSupplier")"
                     delete-action-url="@Url.Action("MultiRowDeleteSupplier")"></c1-items-source>
    <c1-multi-row-cell-group>
        <c1-multi-row-cell binding="SupplierID" is-read-only="true" format="d" align="center"></c1-multi-row-cell>
    </c1-multi-row-cell-group>
    <c1-multi-row-cell-group colspan="2">
        <c1-multi-row-cell binding="CompanyName" colspan="2"></c1-multi-row-cell>
        <c1-multi-row-cell binding="ContactName" width="150"></c1-multi-row-cell>
        <c1-multi-row-cell binding="ContactTitle" width="200"></c1-multi-row-cell>
    </c1-multi-row-cell-group>
    <c1-multi-row-cell-group colspan="3">
        <c1-multi-row-cell binding="Country"></c1-multi-row-cell>
        <c1-multi-row-cell binding="Region"></c1-multi-row-cell>
        <c1-multi-row-cell binding="City"></c1-multi-row-cell>
        <c1-multi-row-cell binding="Address" colspan="3"></c1-multi-row-cell>
    </c1-multi-row-cell-group>
</c1-multi-row>

<!-- a dialog for editing item details -->
<div class="modal fade" id="dlgDetail">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button"
                        class="close"
                        data-dismiss="modal"
                        aria-hidden="true">
                    &times;
                </button>
                <h4 class="modal-title">@Html.Raw(MultiRowRes.Editing_Text14)</h4>
            </div>
            <div class="modal-body">
                <dl class="dl-horizontal">
                    <dt>@Html.Raw(MultiRowRes.Editing_Text15)</dt>
                    <dd>
                        <input id="SupplierID" class="form-control" disabled />
                    </dd>
                    <dt>@Html.Raw(MultiRowRes.Editing_Text16)</dt>
                    <dd>
                        <input id="CompanyName" class="form-control" />
                    </dd>
                    <dt>@Html.Raw(MultiRowRes.Editing_Text17)</dt>
                    <dd>
                        <input id="ContactName" class="form-control" />
                    </dd>
                    <dt>@Html.Raw(MultiRowRes.Editing_Text18)</dt>
                    <dd>
                        <input id="ContactTitle" class="form-control" />
                    </dd>
                    <dt>@Html.Raw(MultiRowRes.Editing_Text19)</dt>
                    <dd>
                        <input id="Country" class="form-control" />
                    </dd>
                    <dt>@Html.Raw(MultiRowRes.Editing_Text20)</dt>
                    <dd>
                        <input id="Region" class="form-control" />
                    </dd>
                    <dt>@Html.Raw(MultiRowRes.Editing_Text21)</dt>
                    <dd>
                        <input id="City" class="form-control" />
                    </dd>
                    <dt>@Html.Raw(MultiRowRes.Editing_Text22)</dt>
                    <dd>
                        <input id="Address" class="form-control" />
                    </dd>
                </dl>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" data-dismiss="modal"
                        onclick="commitUpdate()">
                    <span class="glyphicon glyphicon-ok"></span>
                    @Html.Raw(MultiRowRes.Editing_Text23)
                </button>
                <button type="button" class="btn btn-warning" data-dismiss="modal">
                    <span class="glyphicon glyphicon-ban-circle"></span>
                    @Html.Raw(MultiRowRes.Editing_Text24)
                </button>
            </div>
        </div><!-- modal-content -->
    </div><!-- modal-dialog -->
</div><!-- modal -->

<div class="well grid-sort-group">

    <!-- edit details in a popup -->
    <button id="showEditDialogBtn"
            class="btn btn-default"
            data-toggle="modal"
            data-backdrop="static"
            data-keyboard="false"
            data-target="#dlgDetail"
            onclick="showEditDialog()">
        <span class="glyphicon glyphicon-new-window"></span>
        @Html.Raw(MultiRowRes.Editing_Text28)
    </button>
</div>

<h4>
    @Html.Raw(MultiRowRes.Editing_Text29)
</h4>
<p>@Html.Raw(MultiRowRes.Editing_Text9)</p>

<p>@Html.Raw(MultiRowRes.Editing_Text10)</p>

<p>@Html.Raw(MultiRowRes.Editing_Text11)</p>

<br />
<h4>
    @Html.Raw(MultiRowRes.Editing_Text30)
</h4>
<p>@Html.Raw(MultiRowRes.Editing_Text12)</p>

<p>@Html.Raw(MultiRowRes.Editing_Text13)</p>

<c1-multi-row id="inlineEditMultiRow" is-read-only="true" selection-mode="None"
              class="multirow" item-formatter="itemFormatter"
              scroll-position-changed="scrollPositionChanged" resizing-column="resizingColumn" dragging-column="draggingColumn" sorting-column="sortingColumn">
    <c1-items-source read-action-url="@Url.Action("MultiRowBindCustomer")"
                     update-action-url="@Url.Action("MultiRowUpdateCustomer")"
                     create-action-url="@Url.Action("MultiRowCreateCustomer")"
                     delete-action-url="@Url.Action("MultiRowDeleteCustomer")"></c1-items-source>
    <c1-multi-row-cell-group>
        <c1-multi-row-cell binding="CustomerID" name="CustomerID" header="ID" width="80" align="center" is-read-only="true"></c1-multi-row-cell>
    </c1-multi-row-cell-group>
    <c1-multi-row-cell-group colspan="2">
        <c1-multi-row-cell binding="CompanyName" name="CompanyName" colspan="2"></c1-multi-row-cell>
        <c1-multi-row-cell binding="ContactName" name="ContactName" width="150"></c1-multi-row-cell>
        <c1-multi-row-cell binding="ContactTitle" name="ContactTitle" width="150"></c1-multi-row-cell>
    </c1-multi-row-cell-group>
    <c1-multi-row-cell-group colspan="3">
        <c1-multi-row-cell binding="Country" name="Country" width="80"></c1-multi-row-cell>
        <c1-multi-row-cell binding="Region" name="Region" width="80"></c1-multi-row-cell>
        <c1-multi-row-cell binding="City" name="City"></c1-multi-row-cell>
        <c1-multi-row-cell binding="Address" name="Address" colspan="3"></c1-multi-row-cell>
    </c1-multi-row-cell-group>
    <c1-multi-row-cell-group>
        <c1-multi-row-cell name="Buttons" width="100"></c1-multi-row-cell>
    </c1-multi-row-cell-group>
</c1-multi-row>