http://demos.telerik.com/aspnet-mvc/razor/grid/editingajax
Do you have a similar example where the Grid is bound to a DataTable? I can get InForm and Popup to work with a DataTable, but get following error message for InLine option:
Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
4 Answers, 1 is accepted
Unfortunately inline editing with datatable is not supported because ASP.NET MVC cannot generate an editor for a grid column (Html.EditorFor(row => row.Property)) when the model is a datarowview. You can however use popup and inform editing as shown in this code library project.
Greetings,Atanas Korchev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Let's review what happens in your code when the Grid is rendered. Render calls WriteHtml which eventually calls InitializeEditors which contains the following code:
if (Editing.Mode != GridEditMode.InLine && Editing.Mode != GridEditMode.InCell) { var container = new HtmlElement("div").AddClass(UIPrimitives.Grid.InFormContainer); htmlHelper.EditorForModel(dataItem, Editing.TemplateName).AppendTo(container); EditorHtml = container.InnerHtml; } else { var cellBuilderFactory = new GridCellBuilderFactory(); VisibleColumns.Each(column => { var cellBuilder = cellBuilderFactory.CreateEditCellBuilder(column, htmlHelper); var editor = cellBuilder.CreateCell(dataItem); column.EditorHtml = editor.InnerHtml; }); } InLine mode falls to the else block which creates a GridCellBuilder for each column. CreateCell calls AppendCellContent which calls several other functions:
protected override void AppendCellContent(IHtmlNode td, object dataItem) { var htmlHelper = new HtmlHelper<TModel>(ViewContext, new GridViewDataContainer<TModel>((TModel)dataItem, ViewContext.ViewData)); AppendEditor(td, htmlHelper); AppendValidator(td, htmlHelper); } private void AppendEditor(IHtmlNode container, HtmlHelper<TModel> htmlHelper) { if (TemplateName.HasValue()) { AppendEditorTemplate(htmlHelper, container); } else { AppendEditorFor(htmlHelper, container); } } private void AppendEditorFor(HtmlHelper<TModel> htmlHelper, IHtmlNode container) { var editor = htmlHelper.EditorFor(Expression); if (editor != null) { container.Children.Add(new LiteralNode(editor.ToHtmlString())); } } private void AppendEditorTemplate(HtmlHelper<TModel> htmlHelper, IHtmlNode container) { var editor = htmlHelper.Editor(Member, TemplateName); if (editor != null) { container.Children.Add(new LiteralNode(editor.ToHtmlString())); } } At this point you actually create a new HtmlHelper object with the appropriate Model and call either Html.EditorFor or Html.Editor (if an override Template name was provided).
Here is the quick fix. At this point for a DataRow simply pull the object from the data row for the appropriate column and place it temporarily in the ViewDataDictionary with the Column Name as the key. (You could even create a default object of that type if the DataTable is empty -- the column definitions should still exist.) Then call Html.Editor(ColumnName) (Include TemplateName override as well if provided). The Dictionary is inspected first (look at ViewDataEvaluator.GetPropertyValue in MVC code) before calling TypeDescriptor.GetProperties for the model.
Here is a snippet of code that demonstrates the workaround using a simple html table.
@model DataTable @{ DataColumnCollection cols = Model.Columns; DataRowCollection rows = Model.Rows; } <table> <thead><tr> @foreach (DataColumn col in cols) { <th>@col.ColumnName</th> } </tr></thead> <tbody> @for (int i = 0; i < rows.Count; i++) { <tr> @for (int j = 0; j < cols.Count; j++) { ViewData[cols[j].ColumnName] = rows[i][cols[j].ColumnName]; <td>@Html.Editor(cols[j].ColumnName)</td> } </tr> } </tbody> </table> This creates the appropriate editor components for every row in the grid. Your code will be slightly different where you are capturing the Html needed for editing per column, but you can use the same approach. You do have to be careful with proper clean up of ViewData, but you are creating a new HtmlHelper object anyway, so that shouldn't be a concern.
I'm working on several other approaches as well. The most elegant would be to wrap the DataRow in a DynamicObject that exposes the columns as properties.
The bottom line is that you are in the driver seat. Please provide the same functionality for DataTable as you do for an Enumerable Object. We have some portions of our application that are dynamically created at runtime where it is not feasible to create a tightly bound object -- hence the need for DataTable.
Thank you for your help.
I have logged this as a feature request. We will evaluate the suggested approach and see if we can plug that in. You can vote for it here.
Atanas Korchev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Do you have a sample project that uses this technique? It is not clear from the post where each of the code parts you show would be implemented.