如何将具有动态列数的数据表绑定到带有SignalR的Kendo UI Grid?

时间:2015-10-14 09:32:25

标签: asp.net-mvc kendo-grid kendo-asp.net-mvc signalr-hub

我需要使用SignalR将Kendo Grid绑定到具有动态列数的Datatable。我怎样才能做到这一点。我可以直接将DataTable对象从Hub传递给View吗?我的代码如下: 视图:

@model System.Data.DataTable
<script>
    var TestGridHub = {};
    $(function () {
        TestGridHub = $.connection.TestGridHub;
    })
</script>
<table><tr><td>
    @(Html.Kendo().Grid(Model)
    .Name("TestGrid")
    .Columns(columns =>
    {
      foreach (System.Data.DataColumn col in DataTable.Columns)
      {
       columns.Bound(col.ColumnName).Title("Name")
              .ClientTemplate("#=name#");
           }
         })
       .DataSource(dataSource => dataSource
            .SignalR()
            .PageSize(10)
            .Transport(tr => tr
                .Promise("hubStart")
                .Hub("TestGridHub")
                .Client(c => c.Read("TestGrid_Read"))
                .Server(s => s.Read("TestGrid_Read"))
             )
          .Schema(schema => schema
            .Model(m =>m.Id(p => p.Id))
         ))
        )
    </td></tr></table>

Hub:

public DataTable TestGrid_Read()
    {
      var queryResult = TestRepository.TestGrid_Read_Dynamic();
      return queryResult;
    }

存储库:

public DataTable TestGrid_Read_Dynamic()
{
  using (SqlConnection connection = new SqlConnection(dbContext.Database.Connection.ConnectionString))
        {
          using (SqlCommand cmd = new SqlCommand("SP_TestGrid", connection))
          {
            var dt = new DataTable();
            SqlDataAdapter adapter = new SqlDataAdapter(cmd);
            adapter.SelectCommand.CommandType = System.Data.CommandType.StoredProcedure;
            adapter.SelectCommand.Parameters.Add(new SqlParameter("@Id", GlobalVaribleDeclarations.Id));
            adapter.Fill(dt);

            return dt;
          }
        }
}

1 个答案:

答案 0 :(得分:3)

我想自从你提出这个问题已经过了几个月了,但这是我一直在修补的事情,并注意到仍然没有找到答案。这就是我为使其发挥作用而做的事情:

不使用Html.Kendo().Grid(Model),而是使用Html.Kendo().Grid<dynamic>()

使用ViewData传递列定义。我得到了DataTable的.Clone()并将其分配给控制器中的ViewData["columns"],然后在视图中绑定Grid列时迭代它。

Hub应该将数据作为DataTable返回。如果您决定使用服务器操作,那么您希望Read方法接受DataSourceRequest参数并返回DataSourceResult对象。您需要定义自己的DataSourceResult类,以便它的Data属性是DataTable。

更新:扩展您的实施方式

因此Grid的构建方式与其他任何类似,但在Kendo Grid列构建器中,您需要遍历DataTable的列集:

.Columns(col => 
{
    for(var i = 0; i < table.Columns.Count; i++)
    {
        if(table.Columns[i].ColumnName == "ID")
        {
            col.Bound(table.Columns[i].ColumnName).Hidden();
        }
        else
        {
            col.Bound(table.Columns[i].ColumnName);
        }
    }
}

您可以以类似的方式定义网格模型:

.Model(mod => 
{
    for(var i = 0; i < table.Columns.Count; i++)
    {
        if(table.Columns[i].ColumnName == "ID")
        {
            mod.Id(table.Columns[i].ColumnName);
            mod.Field(table.Columns[i].ColumnName, typeof(table.Columns[i].DataType).Editable(false);
        }
        else
        {
            mod.Field(table.Columns[i].ColumnName, typeof(table.Columns[i].DataType);
        }
    }
}

但是,即使定义了包含上述数据类型的模型,Kendo HTML帮助程序也不知道如何为每列选择编辑器。这可以通过构建Stack<string>列名称来解决,它们在数据表中出现的顺序与堆栈的顶部中的第一列相同,在Controller中传递到了视野。然后使用Kendo EditorTemplates并修改它们以从堆栈中弹出一个名称并将其用于编辑器,如下所示:

//DynamicInteger.cshtml
@model int?

@{
    Stack<string> columnStack = (Stack<string>)ViewData["columns"];
    var name = columnStack.Pop();
}

@(Html.Kendo().IntegerTextBoxFor(m => m).Name(name)
    .HtmlAttributes(new { style = "width:100%" })
    .Min(int.MinValue)
    .Max(int.MaxValue)
)

并更改列定义以使用修改后的EditorTemplates:

//...
}
else if (table.Columns[i].DataType == typeof(int))
{
    col.Bound(table.Columns[i].ColumnName).EditorTemplateName("DynamicInteger");
}

这将导致编辑器被正确地分配给每一列,因此您可以获得格式良好的编辑器,甚至是复杂的编辑器,如DatePicker或DropDownLists,而不是纯文本框。