Telerik MVC Griglia con Dinamica Colonne in fase di Esecuzione da una Raccolta o un Dizionario

Dopo aver trascorso gli ultimi due giorni di ricerca, ho ufficialmente bloccato. Sto lavorando su un associazione di un oggetto per il Telerik MVC 3 Griglia, ma il problema è che ha bisogno di avere creato dinamicamente colonne (non generato automaticamente). Tre le colonne sono noti, altri sconosciuti, e questa è la parte difficile. In sostanza, si può essere come in questi esempi:

KnownColumn1 | KnownColumn2 | UnknownColumn1 | KnownColumn3
KnownColumn1 | KnownColumn2 | UnknownColumn1 | UnknownColumn2 | UnknownColumn3 | KnownColumn3
ecc.

Perché sto mettendo l’ignoto colonne in un elenco (ho provato un dizionario troppo in modo da poter ottenere i nomi di colonna), questo ha complicato le cose per me quando vincolante. Il mio codice è il seguente:

Modello (Ci può essere da zero a centinaia di righe, ma questo modello è un modello di visualizzazione del tipo di Elenco, ci può essere anche 0 a 20 più colonne che vengono aggiunti dinamicamente)

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() { }
}

Vista (La sezione commentato stava cercando di usare il dizionario)

<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>

Usare il dizionario approccio, sono stato in grado di ottenere le colonne generate correttamente con l’intestazione a destra del testo, ma i valori per le colonne (nel mio test c’erano solo 2 colonne) sono le stesse. Qualcuno può aiutarmi con questo? Questo sembra essere un tipo strano problema. Solo cercando di capire come farlo correttamente.

Aggiornamento: Qui c’è una schermata con il dizionario approccio che mostra il problema. Le intestazioni di colonna sono corrette, ma i valori sono gli stessi per entrambi i la dinamica colonne.

Telerik MVC Griglia con Dinamica Colonne in fase di Esecuzione da una Raccolta o un Dizionario

OriginaleL’autore Eric Garrison | 2012-07-13

5 Replies
  1. 7

    Utilizzando definiti in modo dinamico le colonne con il Telerik griglia di controllo può essere difficile. Ma nel tuo caso, si tratta soprattutto di una tipica trappola di chiusure.

    In questo ciclo, il compilatore associare ogni istanza di gl => gl.Amounts[i - 1] alla variabile i e valutare poi:

    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);
    }

    Infatti, è valutato dopo il ciclo è finito. Così i avrà sempre il valore che portano al completamento del ciclo.

    La correzione è quello di utilizzare una variabile temporanea:

    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);
    }
    Impressionante, che ha funzionato (ho dovuto fare una piccola modifica al “per” istruzione però, ho rimosso il “- 1” condizionale parte. Grazie per il suggerimento, ho davvero apprezzare. Ho appena controllato, e questo funziona anche per il dizionario approccio troppo, utilizzando una variabile temp per la chiave di dizionario. Grazie ancora!
    Come utilizzare gl.Importi[columnIndex] in ClientTemplate. Mi restituisce errore columnIndex non definito
    Si prega di aprire una nuova domanda e aggiungi il tuo codice. È difficile dire perché si ottiene un errore senza vedere il codice.

    OriginaleL’autore Codo

  2. 2

    Ho avuto lo stesso problema, ed è stato googling un sacco di ore in tutto, e abbiamo fatto un sacco di tentativi da varie linee di assistenza. Ma anche così, non era così banale da risolvere!

    E per tale motivo, e per avere anche un altro esempio qui, fornisco anche la mia soluzione!

    Informazioni: funziona solo al mio posto con un IList Modello. Altre collezioni, aveva anche causato problemi!

    @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()
    )

    Controller:

    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);
    }

    Modelli:

    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; }
        }
    }

    FieldDefinition

    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; }
        }
    }

    Campo

    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; }
        }
    }

    OriginaleL’autore florian.isopp

  3. 2

    Ho associare dinamicamente le colonne a runtime con una riflessione:

    @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);
        }
    }

    OriginaleL’autore thepirat000

  4. 1

    Ecco la soluzione:

    @(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)

    )

    //Metodo di estensione per genarate colonne in modo dinamico

    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);
    
                });
            }
    
        }
    }

    //Colonna impostazioni di classe

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

    OriginaleL’autore sajid khan

  5. 0

    Ho fatto questo semplice modo. NOTA : la seguente soluzione funziona in ajax modalità di modifica (non solo una griglia di sola lettura) :

    quando il Viewmodel sono :

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

    public class PriceSheetColumnViewModel
    {
    public int Id { get; set; }
    public string Titolo { get; set; }
    }

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

    la vista può essere simile a questo (parte di vista.cshtml file…) :

        ....
    @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++;
                }    
    
    ....

    e il PriceSheetCellPrice.cshtml editor di file di modello (in shared\editortemplates cartella) :

      @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)
    )

    OriginaleL’autore Mahmoud Moravej

Lascia un commento