【问题标题】:Telerik MVC Grid with Dynamic Columns at Run Time from a Collection or DictionaryTelerik MVC 网格在运行时来自集合或字典的动态列
【发布时间】:2012-07-13 14:53:06
【问题描述】:

在花了最后几天搜索之后,我正式陷入困境。我正在将一个对象绑定到 Telerik MVC 3 Grid,但问题是它需要动态创建列(不是自动生成的)。其中三列是已知的,其他列是未知的,这是棘手的部分。基本上可以像这些例子:

KnownColumn1 |已知列2 |未知列1 |已知列3 已知列1 |已知列2 |未知列1 |未知列2 |未知列3 |已知列3 等等

因为我将未知列放在一个列表中(我也尝试过使用字典,所以我可以获取列名),这在绑定时对我来说很复杂。我的代码如下:

模型(可以有0到数百行,但是这个模型是在List类型的视图模型中,也可以有0到20加上动态添加的列)

public class VendorPaymentsGLAccount
{
    public string GeneralLedgerAccountNumber { get; set; }
    public string GeneralLedgerAccountName { get; set; }
    public string DisplayName { get { return string.Format("{0} - {1}", GeneralLedgerAccountNumber, GeneralLedgerAccountName); } }
    public Dictionary<string, double> MonthAmount { get; set; }
    public double Total { get { return MonthAmount.Sum(x => x.Value); } }
    public List<string> Columns { get; set; }
    public List<double> Amounts { get; set; }

    public VendorPaymentsGLAccount() { }
}

查看(被注释掉的部分是试图使用字典)

<fieldset>
    <legend>General Ledger Account Spend History</legend>
    @if (Model.VendorPaymentsGLAccounts != null)
    {

            <br />
            @(Html.Telerik().Grid(Model.VendorPaymentsGLAccounts)
                    .Name("Grid")
                    .Columns(columns =>
                    {
                        columns.Bound(gl => gl.DisplayName).Title("General Ledger Account").Width(200).Filterable(false).Sortable(false);

                        //foreach (var month in Model.VendorPaymentsGLAccounts[0].MonthAmount)
                        //{
                        //    //columns.Bound(gl => gl.MonthAmount[month.Key.ToString()].ToString()).Title(month.Key.ToString()).Width(100).Filterable(false).Sortable(false);
                        //    //columns.Template(v => Html.ActionLink(v.VoucherID, "VoucherSummary", new { id = v.VoucherID, bu = v.BusinessUnitID, dtt = v.InvoiceDate.Ticks })).Title("Voucher").Width(100);
                        //    columns.Template(gl => Html.ActionLink(gl.MonthAmount[month.Key.ToString()].ToString(), "VoucherSummary")).Title(month.Key.ToString()).Width(100);
                        //}

                        for (int i = 1; i <= (Model.VendorPaymentsGLAccounts[0].Columns.Count() - 1); i++)
                        {
                            string colTemp = Model.VendorPaymentsGLAccounts[0].Columns[i - 1];
                            columns.Template(gl => gl.Amounts[i - 1]).Title(colTemp).Width(100);
                        }

                        columns.Template(gl => String.Format("{0:C}", gl.Total)).Title("Total");
                    })
                    .Sortable()
                    .Pageable()
                    .Filterable()
                    .Footer(true))
    }
    else
    {
        <br />
        @:There are no records that match your selected criteria.
    }
</fieldset>

使用字典方法,我能够使用正确的标题文本正确生成列,但列的值(在我的测试中只有 2 列)是相同的。有人能帮忙吗?这似乎是一个奇怪的问题。只是想弄清楚如何正确地做到这一点。

更新:这是使用字典方法显示问题的屏幕截图。列标题正确,但两个动态列的值相同。

【问题讨论】:

    标签: asp.net-mvc-3 data-binding dynamic telerik-grid


    【解决方案1】:

    在 Telerik 网格控件中使用动态定义的列可能会很棘手。但在你的情况下,这主要是一个典型的闭包陷阱。

    在以下循环中,编译器会将gl =&gt; gl.Amounts[i - 1] 的每个实例绑定到变量i 并稍后对其进行评估:

    for (int i = 1; i <= (Model.VendorPaymentsGLAccounts[0].Columns.Count() - 1); i++)
    {
      string colTemp = Model.VendorPaymentsGLAccounts[0].Columns[i - 1];
      columns.Template(gl => gl.Amounts[i - 1]).Title(colTemp).Width(100);
    }
    

    事实上,它是在循环结束后计算的。因此i 将始终具有导致循环完成的值。

    解决方法是使用临时变量:

    for (int i = 1; i <= (Model.VendorPaymentsGLAccounts[0].Columns.Count() - 1); i++)
    {
      string colTemp = Model.VendorPaymentsGLAccounts[0].Columns[i - 1];
      int columnIndex = i - 1;
      columns.Template(gl => gl.Amounts[columnIndex]).Title(colTemp).Width(100);
    }
    

    【讨论】:

    • 太棒了,这很有效(不过,我不得不对“for”语句进行一些小改动,我从条件部分中删除了“- 1”。感谢您的提示,我真的很感激。我刚刚检查过,这也适用于字典方法,使用临时变量作为字典键。再次感谢!
    • 如何在 ClientTemplate 中使用 gl.Amounts[columnIndex]。对我来说,它返回错误 columnIndex not defined
    • 请打开一个新问题并添加您的代码。不看代码就很难知道为什么会出错。
    【解决方案2】:

    我遇到了同样的问题,并且在谷歌上搜索了很多小时,并且从各种援助热线进行了很多尝试。但即便如此,解决起来也不是那么简单!

    出于这个原因,并且这里还有另一个工作示例,我也会提供我的解决方案!

    信息:它只适用于我的 IList 模型。其他收藏也有问题!

    @model IList<CBS.Web.Models.Equipment.EquipmentViewModel>
    @(Html.Telerik().Grid(Model)
        .Name("Grid")
    
        .DataKeys(keys =>
        {
            keys.Add(m => m.ID);
        })
    
        .DataBinding(dataBinding =>
        {
            dataBinding.Ajax()
                // renders the grid initially
                .Select("EquipmentGrid", "Equipment");
        })                    
    
        .Columns(columns =>
        {
            // Equipment IDs
            columns.Bound(m => m.ID).Hidden(true);
            columns.Bound(m => m.Name).Title("Equipments").Width(200);
    
            // Every item (EquipmentViewModel) of the Model has the same Count of Fields
            for (int i = 0; i < (Model[0].Fields.Count()); i++)
            {
                // Name of the column is everytime same as in Model[0]
                string columnName = Model[0].Fields.ElementAt(i).FieldDefinition.Name;
                // Constructs i-counted columns, dynamically on how much
                // Fields are owned by an Equipment. But note, that all Equipment-items
                // in the Model must have the same Count and disposal of Fields! 
                columns.Template(m => m.Fields
                                        .Where(f => f.FieldDefinition.Name == columnName)
                                        .Where(f => f.EquipmentId == m.ID).First().Value)
                                        .Title(columnName)
                                        .Width(columnName.Length * 8); // * 8 was the optimal lenght per character
            }
        })
    
        .ClientEvents(events => events.OnRowSelect("onRowSelected"))
    
        .Selectable()
        .Resizable(resizing => resizing.Columns(true))
        .Pageable()
        .Scrollable()
        .Groupable()
        .Filterable()
    )
    

    控制器:

    public ActionResult EquipmentGrid(Guid id)
    {            
        var belongingEquipments = _equipmentRepository.GetNotDeleted()
                                    .OrderBy(e => e.Name).ToList()
                                    .Where(e => e.RevisionId == id);
    
        List<EquipmentViewModel> equVMList = new List<EquipmentViewModel>();
    
        for (int i = 0; i < belongingEquipments.Count(); i++)
        {
            var equVM = new EquipmentViewModel
            {
                ID = belongingEquipments.ElementAt(i).ID,
                Name = belongingEquipments.ElementAt(i).Name,
                RevisionId = belongingEquipments.ElementAt(i).RevisionId,
                EquipmentTypeId = belongingEquipments.ElementAt(i).EquipmentTypeId,
    
                Fields = SortFields(belongingEquipments.ElementAt(i).Fields.ToList())
            };
            equVMList.Add(equVM);
        }
    
        return PartialView("EquipmentGrid", equVMList);
    }
    

    型号:

    namespace CBS.Web.Models.Equipment
    {
        public class EquipmentViewModel
        {
            public Guid ID { get; set; }
            public string Name { get; set; }
    
            public Guid RevisionId { get; set; }                            
            public Guid EquipmentTypeId { get; set; }
    
            public virtual ICollection<FieldEntity> Fields { get; set; }
        }
    }
    

    字段定义

    namespace CBS.DataAccess.Entities
    {
        public class FieldDefinitionEntity : EntityBase
        {
            [Required]
            public virtual Guid EquipmentTypeId { get; set; }
            public virtual EquipmentTypeEntity EquipmentType { get; set; }
    
            [Required(AllowEmptyStrings = false)]
            public virtual string Name { get; set; }
    
            public virtual int Numbering { get; set; }
    
            [Required]
            public virtual Guid TypeInformationId { get; set; }
            public virtual TypeInformationEntity TypeInformation { get; set; }
    
            public virtual ICollection<FieldEntity> Fields { get; set; }
        }
    }
    

    字段

    namespace CBS.DataAccess.Entities
    {
        public class FieldEntity : EntityBase
        {
            [Required]
            public virtual Guid EquipmentId { get; set; }
            public virtual EquipmentEntity Equipment { get; set; }
    
            [Required]
            public virtual Guid FieldDefinitionId { get; set; }
            public virtual FieldDefinitionEntity FieldDefinition { get; set; }
    
            public virtual string Value { get; set; }
        }
    }
    

    【讨论】:

      【解决方案3】:

      我在运行时使用反射动态绑定列:

      @model IEnumerable<object>
      @using System.Collections
      @using System.Collections.Generic
      @using System.Reflection;
      
      @(Html.Telerik().Grid(Model)
          .Name("Grid")
          .Columns(columns =>                    
              {
                  Type t = Model.GetType().GetGenericArguments()[0];
                  foreach (var prop in t.GetProperties())
                  {
                      if (IsCoreType(prop.PropertyType))
                      {
                          columns.Bound(prop.PropertyType, prop.Name);
                      }
                  }
              })    
              .DataBinding(binding => binding.Ajax()                                        
                  .Select("SelectMethod", "SomeController")                                    
              )    
          .Sortable()    
          .Pageable()
          .Filterable()
          .Groupable()
      )
      
      @functions{
          public bool IsCoreType(Type type)
          {
              if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
              {
                  return IsCoreType(type.GetGenericArguments()[0]);
              }
              return !(type != typeof(object) && Type.GetTypeCode(type) == TypeCode.Object);
          }
      }
      

      【讨论】:

        【解决方案4】:

        这里是解决方法:

        @(Html.Telerik().Grid(Model.Users)
            .Name("Grid")
            .Columns(columns => {
                columns.GenerateCustomColumns(columnSettings);          
               }).DataBinding(dataBinding => dataBinding.Ajax().Select("_getusers", "home"))
                   .Scrollable(scrolling => scrolling.Enabled(true).Height("auto"))
                   .Pageable(paging => paging.Enabled(true)
                   .PageSize(10, new int[] { 5, 10, 20, 50, 100, 500 })
                   .Position(GridPagerPosition.Both)
                   .Total(Model.Users.Count)
                   .Style(GridPagerStyles.PageSizeDropDown | GridPagerStyles.NextPreviousAndNumeric)
                                   .PageTo(1))
                   .Filterable(filtering => filtering.Enabled(true))
                   .Reorderable(reordering => reordering.Columns(true))
                       .NoRecordsTemplate(" ")
                   .EnableCustomBinding(true)
        

        )

        //动态生成列的扩展方法

        public static class TelerikMvcGridColumnHelper
        {
            public static void GenerateCustomColumns<T>(this GridColumnFactory<T>   columns,List<GridCustomColumnSettings> settings) where T:class
            {
                if (settings != null)
                {
                    settings.ForEach(column =>
                    {
                        var boundedColumn = columns.Bound(column.Member);
                        if (column.ClientFooterTemplate != null)
                            boundedColumn.ClientFooterTemplate(column.ClientFooterTemplate);
        
                        if (!string.IsNullOrEmpty(column.Width))
                            boundedColumn.Width(column.Width);
        
                    });
                }
        
            }
        }
        

        // 列设置类

        public class GridCustomColumnSettings : GridColumnSettings
         {
            public string ClientFooterTemplate { get; set; }
        
         }
        

        【讨论】:

          【解决方案5】:

          我做了这个简单的方法。注意:以下解决方案也适用于 ajax 编辑模式(不仅仅是只读网格):

          当 ViewModel 是:

          public class PriceSheetEditGridViewModel
          {
              public IEnumerable<PriceSheetRowViewModel> Rows { get; set; }
              public IEnumerable<PriceSheetColumnViewModel> Columns { get; set; }
          }
          

          公共类 PriceSheetColumnViewModel { 公共 int ID { 获取;放; } 公共字符串标题 { 获取;放; } }

          public class PriceSheetRowViewModel 
              {
          
                  public int RowNo { get; set; }
                  public string Description { get; set; }
                  public double?[] Prices { get; set; }
          
              }
          

          视图可以是这样的(view.cshtml 文件的一部分...):

              ....
          @model PriceSheetEditGridViewModel
          ...
                          columns.Bound(o => o.Description ).Width(150);
          
                          int i = 0;
                          foreach (var col in Model.Columns)
          
          
          {
                          columns
                              .Bound(model => model.Prices).EditorTemplateName("PriceSheetCellPrice").EditorViewData(new { ColumnId = i })
                              .ClientTemplate("<span><#=Prices ? jsHelper.addCommas(Prices[" + i.ToString() + "]):null#></span>")
                              .Title(col.Title).Width(80);
                          i++;
                      }    
          
          ....
          

          PriceSheetCellPrice.cshtml 编辑器模板文件(在shared\editortemplates 文件夹中):

            @model decimal?
          @(Html.Telerik().NumericTextBox()
                  .Name(ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty)+"["+ViewBag.ColumnId+"]")
                              .InputHtmlAttributes(new { style = "width:100%" })
          })
                  .EmptyMessage("")
                  .DecimalDigits(0)
                  .DecimalSeparator(",")
                  .MinValue(0)
                  .Value((double?) Model)
          )
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-06-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-23
            • 1970-01-01
            相关资源
            最近更新 更多