65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 EditorTemplate+MVC 在 Kendo GridView 中使用 Kendo Dropdown

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2016 年 5 月 26 日

CPOL

2分钟阅读

viewsIcon

23623

在 ASP.NET-MVC 中,使用 Editor Template 和 Client Template 实现 Kendo 子网格中的 Kendo 下拉框

引言

本文将指导您使用 Editor Templates 和 ASP.NET MVC 在 Kendo 子网格中渲染 Kendo 下拉框。

背景

Kendo 子网格最初使用 HTML 下拉框代替 Kendo 下拉框。它还包含一段冗长的 JavaScript 代码。我浏览了很多文章来尝试实现它,但每个人都缺少一些内容或不清楚,因此我一路学习!!

此实现最好的部分在于,首次渲染时,如果下拉框尚未保存任何值,则它会将其渲染为空白,但单击网格单元格后,它会变成一个用于选择的下拉框。
此外,只要您从网格单元格导航出去,编辑模式就会结束,并返回到数据库中保存的最后一个值。

使用代码

在以下代码中,OrderGrid(网格)是包含另一个 Kendo 网格(grid2_#=OpportunityId)的主 Kendo 网格。

在 OrderGrid.cshtml 中

@(Html.Kendo().Grid<Models.OrderGridViewModel>()

    .Name("grid")
    .HtmlAttributes(new { style = "line-height:10px;" })
    .Columns(columns =>
    {
         columns.Bound(m => m.VersionName).Title("Ver");
         columns.Bound(m => m.OrderStatusText).Title("Status");
         columns.Bound(m => m.StartDateTime).Title("Start Date");
         columns.Bound(m => m.EndDateTime).Title("End Date");
    })        
    .Selectable(s => s.Mode(GridSelectionMode.Single).Type(GridSelectionType.Cell))
    .Events(events => events.DataBound("grid_dataBound"))
    .Pageable()
    .Sortable() // Enable sorting
    .ClientDetailTemplateId("OrderDetailsAll")
    .DataSource(dataSource => dataSource
    .Ajax()
    .PageSize(5)
    .Read(read => read.Action("Get", "Order"))
    )
)

<script id="OrderDetailsAll" type="text/kendo-tmpl">
  
@(Html.Kendo().Grid<Models.OrderDetailAllViewModel>()
    .Name("grid2_#=OpportunityId#")
            .Events(e =>
            {
                e.DataBound("grid2_onDataBound");
                e.Edit("onEdit");
            })
    .Editable(editable => editable.Mode(GridEditMode.InCell))
    .Columns(columns =>
    {        
        columns.Bound(m => m.IncludeInForecast).HtmlAttributes(new { Align = "center" }).Title("Include In Forecast?").ClientTemplate("\\# if (IncludeInForecast  == true ) { \\#" + "Yes" +
                      "\\# }else { \\#" + "No" +
                      "\\# } \\#"); //this is a checkbox within Kendo Sub-grid               
    );                
        columns.Bound(m => m.SalesStrategyId).EditorTemplateName("SalesStrategies").Title("Sales Strategy").ClientTemplate("\\#=SalesStrategyName\\#"); //this is a dropdown within Kendo Sub-grid
    })
        .DataSource(dataSource => dataSource
            .Ajax()
            .Read(read => read.Action("GetDetailsAll", "Order", new { opportunityId = "#=OpportunityId#" }))
           .Model(model =>
               {                                 
                   model.Field(x => x.IncludeInForecast).Editable(true);
                   model.Field(x => x.EditIncludeInForecast).Editable(false);                   
                   model.Field(x => x.SalesStrategyList).DefaultValue(ViewData["ssDefault"] as OMSWeb.Models.OrderDetailAllViewModel);
               })
        )
        .ToClientTemplate())         
</script>

请注意,对于 ClientTemplate,我们有("\\#=SalesStrategyName\\#")- 这对于指示属性位于下一级别的子网格中是必要的。


请注意 EditorTemplateName(SalesStrategies)- 现在添加一个新的文件夹 - EditorTemplates,位于与您的页面所在的 Views 文件夹的同一级别,并在其中添加一个新的 cshtml 文件,名为“SalesStrategies.cshtml”(例如,我的文件夹层次结构为 - \~OMSWeb\Views\Order\EditorTemplates\SalesStrategies.cshtml,OMSWeb 是 Web 项目)

@using Kendo.Mvc.UI
@using Utility;
@using System.Collections;
@model OMSWeb.Models.OrderDetailAllViewModel

@(Html.Kendo().DropDownListFor(m => m.SalesStrategyList)
    .OptionLabel("-- Select Sales Strategy --")
    .DataValueField("Value")
    .DataTextField("Text")        
    .BindTo(ViewData["ssList"] as IEnumerable<List<SelectListItem>>)
    .AutoBind(true)
    .Name("SalesStrategyddList")
    .Events(e =>
    {
      e.DataBound("onDataBound"); //Logic/code for this event is written in OrderGrid.cshtml page below
    })
)

ViewModel (OrderDetailAllViewModel.cs)
(请注意,模型包含其他相关属性,但为了保持简洁和清晰,已省略了它们)

public class OrderDetailAllViewModel : BaseModel
{
    public OrderDetailAllViewModel()
    {
        this.SalesStrategyList = new List<SelectListItem>();
    }
    
    public string SalesStrategyName { get; set; }
    public int? SalesStrategyId { get; set; }
    [UIHint("SalesStrategies")] //This has to match the EditorTemplateName given above for Bound column - SalesStrategy in the sub-grid
    public List<SelectListItem> SalesStrategyList { get; set; }
}

Controller 代码(在 ~OMSWeb\Controllers\OrderController.cs 中),OrderBusinessService.cs

//to get OrderDetails for sub-grid (in OrderController.cs file)
public ActionResult GetDetailsAll([DataSourceRequest] DataSourceRequest request,Guid opportunityId)
{
         _iOrderBusinessService = new OrderBusinessService();
         List<OrderDetailAllViewModel> mList = new List<OrderDetailAllViewModel>();

         if(opportunityId != null)
         {
              mList = _iOrderBusinessService.GetOrderDetails(opportunityId).OrderBy(d => d.SubSystemId).ThenBy(d => d.StartDate).ToList(); //function call as described immediately below
         }

          DataSourceResult result = mList.ToDataSourceResult(request);
          if (mList!= null && mList[0].SalesStrategyList.Any())
          {                
              ViewData["ssList"] = mList[0].SalesStrategyList;
          }
          return Json(result);
}

//Gets Sales Strategy from Database, handles null/empty values (in OrderBusinessService.cs file)
public List<OrderDetailAllViewModel> GetOrderDetails(Guid opportunityId)
{
    OrderDetailAllViewModel m;
    List<OrderDetailAllViewModel> mList = new List<OrderDetailAllViewModel>();
    ISalesStrategy ssMgr = new SalesStrategyManager();
    List<OrderDetail> dList = _iOrderManager.GetOrderDetails(opportunityId, false);//Gets OrderDetails from OrderManager which in turn calls the Database

    foreach (OrderDetail d in dList)
    {        
        m.SalesStrategyId = d.SalesStrategyId.HasValue ? d.SalesStrategyId.Value : 0; //Have value a Zero if null
        var ssItem = ssMgr.GetSalesStrategyById(m.SalesStrategyId.Value);
        if(ssItem != null)
        {
            m.SalesStrategyName = string.IsNullOrEmpty(ssItem.SalesStrategyName) ? string.Empty : ssItem.SalesStrategyName;
        }
        else
        {
            m.SalesStrategyName = string.Empty; //Name as empty string
        }
        mList.Add(m);
    }
    return mList;
}


// To get SalesStrategies from Database (in OrderController.cs file)
public JsonResult GetSalesStrategies([DataSourceRequest] DataSourceRequest request)
{
    _iOrderBusinessService = new OrderBusinessService();
    OrderDetailAllViewModel vm = new OrderDetailAllViewModel();
    var salesStrategyList = _iOrderBusinessService.GetSalesStrategiesList();
    ViewData["ssList"] = vm.SalesStrategyList;
    return Json(salesStrategyList, JsonRequestBehavior.AllowGet);
}


这里的逻辑是,在 SalesStrategy 下拉框的 Databound 事件上,我正在进行 ajax 调用以从数据库获取值。为了绑定回保存的值,使用 existingValue (以下代码在 OrderGrid.schtml 中编写)

<script type="text/javascript">

var dataItem,selectedOrderDetailId,existingValue,newSelectedValue,existingForecast,selectedProposalId,newIIFValue;

function onDataBound(e) 
{
    $.ajax({
        url: "/Order/GetSalesStrategies",
        type: "GET",
        success: function (result)
        {
            if(result != null && result.length > 0)
            {
                $("#SalesStrategyddList").kendoDropDownList({
                    dataTextField: "Text",
                    dataValueField: "Value",
                    selectedIndex: <code>existingValue</code>, //this is assigned in the onEdit event that is fired before onDataBound
                    dataSource: result,
                    optionLabel: "-- Select Sales Strategy --"
                });
                $("#SalesStrategyddList").val(existingValue);
            }
        },
    });
}

function onEdit(e)
{
    selectedOrderDetailId = e.model.OrderDetailId;
    <code>existingValue</code> = e.model.SalesStrategyId;
    existingForecast = e.model.ForecastYesNo;
    selectedGuid = e.model.OpportunityId;
    selectedProposalId = e.model.ProposalId;
    var isEditIIF = e.model.EditIncludeInForecast;

    var orderDetailGrid = $('#grid2_' + selectedGuid).data("kendoGrid");
   
    if (e.container[0].innerHTML.indexOf('Sales Strategy') >= 0) //check if SalesStrategyddList edited
    {
        orderDetailGrid.table.on("change", "#SalesStrategyddList", onChange); //trigger onChange event for SalesStrategyddList only
    }
    else if (e.container[0].innerHTML.indexOf('Forecast') >= 0) //check if IncludeInForecast edited
    {
        // custom logic to handle IncludeInForecast checkbox
        if (isEditIIF)
        {
            $(this)[0].element[0].disabled = false;
            orderDetailGrid.table.on("change", "#IncludeInForecast", onChange); //trigger onChange event for IncludeInForecast only when EditIncludeInForecast true
        }
        else 
        {
            $(this)[0].element[0].disabled = true;                
        }
    }
}

function onChange(e)
{
    var orderDetailGrid = $('#grid2_' + selectedGuid).data("kendoGrid");

    if (e.target.name == "IncludeInForecast")
    {
        //code for custom logic to handle change for IncludeInForecast
    }
    else if (e.target.name == "SalesStrategyddList")
    {            
        newSelectedValue = e.target.value;
    
        //call for SalesStrategy Update
        var dataToSend =
        {
            orderDetailId: selectedOrderDetailId,
            selectedSalesStrategy: newSelectedValue
        };

        if (selectedOrderDetailId != 0 && newSelectedValue != 0)
        {
            $.ajax({
                url: "/Order/UpdateSalesStrategy",
                type: "POST",
                data: dataToSend,
                success: function (result)
                {                    
                    if (result != null && result == "True")
                    {
                       orderDetailGrid.dataSource.page(1); //refresh datagrid if update was successfull to reflect new changes
                    }
                },
            });
        }       
    }
}

</script>

Ajax 调用 Controller 代码以更新数据库中的 SalesStrategy(在 OrderController.cs 文件中

[HttpPost]
public bool UpdateSalesStrategy(int orderDetailId, int selectedSalesStrategy)
{
    _iOrderBusinessService = new OrderBusinessService(); //this is turn calls OrderManager to update in Database
    return _iOrderBusinessService.UpdateSalesStrategy(orderDetailId, selectedSalesStrategy);
}

关注点

在 Kendo 网格中存在 Kendo 下拉框的情况下,onEdit 事件会捕获 SalesStrategy 的保存值,而 Kendo 下拉框(用于 SalesStrategy)的 onDatabound 事件会进行 ajax 调用以从数据库获取值。我浏览了很多帖子,但没有找到更好的方法来完成此操作。

请注意 - 在其中一张图片(SalesStrategy_OnCellClick.jpg)中,显示了工具提示(在 SalesStrategy 网格单元格上鼠标悬停时)- 请注意我没有在此帖子中包含该代码,如果有人要求/需要它,我会这样做。

© . All rights reserved.