Hi; every kind of solution binding data webgrid static models. But my Data is dynamic. Please dont say: why do you use DataTable?
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(string submitButton, FormCollection fc)
{
ViewData["Customers"] = new SelectList(CustomerOperation.GetCustomers().Items, "Id", "Name", null);
ViewData["Jobs"] = new SelectList(JobOperation.GetCustomersAssemblyList().Items, "scheduleId", "name", null);
int Id = ConvertUtil.ToInt(fc["Customers"]);
int scheduleId = ConvertUtil.ToInt(fc["Jobs"]);
DataTable dt = JobOperation.GetJobsBySchedulerIdAndCustomerId(scheduleId, Id);
return View(Json(dt,JsonRequestBehavior.AllowGet));
}
View:
<%
List<WebGridColumn> cols = new List<WebGridColumn>();
WebGrid grid = null;
if (Model != null)
{
grid = new WebGrid(source: Model.Data, rowsPerPage: 3);
System.Reflection.PropertyInfo[] propertiesofColumn = new System.Reflection.PropertyInfo[] { };
foreach (object column in Model)
{
propertiesofColumn = column.GetType().GetProperties();
}
foreach (System.Reflection.PropertyInfo propInfo in propertiesofColumn)
{
cols.Add(grid.Column(propInfo.Name, propInfo.Name));
}
}
using (Html.BeginForm())
{ %>
Error is occured on grid = new WebGrid(source: Model.Data, rowsPerPage: 3);.
ERROR:
RunTimeBinderException: The best overloaded method match for 'System.Web.Helpers.WebGrid.WebGrid(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable, string, int, bool, bool, string, string, string, string, string, string, string)' has some invalid arguments
Please dont say: why do you use DataTable?
There's nothing wrong in using DataTable. DataTables have been around since the early ages of .NET and it is completely understandable that there is still lots of existing code that relies on them. But that's not a reason why those DataTables should traverse the frontiers from the controller to the view. A controller should always pass a view model to the view. So let's start by defining this view model, shall we:
public class MyViewModel
{
public int? SelectedCustomerId { get; set; }
public IEnumerable<SelectListItem> Customers { get; set; }
public int? SelectedJobId { get; set; }
public IEnumerable<SelectListItem> Jobs { get; set; }
public IEnumerable<string> Columns { get; set; }
public IEnumerable<object> Values { get; set; }
}
We shall also define a view model for the request in order to avoid the ugly parsing that you are currently performing:
public class RequestViewModel
{
public string SubmitButton { get; set; }
public int Customers { get; set; }
public int Jobs { get; set; }
}
Now, how do we hide this DataTable
? We could write an extension method which will convert it to a dynamic object:
public static class DataTableExtensions
{
private sealed class Row : DynamicObject
{
private readonly DataRow _row;
public Row(DataRow row)
{
_row = row;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var value = _row.Table.Columns.Contains(binder.Name);
result = value ? _row[binder.Name] : null;
return value;
}
}
public static IEnumerable<dynamic> AsDynamicEnumerable(this DataTable table)
{
return table.AsEnumerable().Select(row => new Row(row));
}
}
So far so good. The last peace of the puzzle is in the controller action where we shall create our view model:
[HttpPost]
public ActionResult Index(RequestViewModel request)
{
int id = request.Customers;
int scheduleId = request.Jobs;
DataTable dt = JobOperation.GetJobsBySchedulerIdAndCustomerId(scheduleId, id);
// Now let's build the view model for the result:
var model = new MyViewModel();
model.Columns = dt.Columns.Cast<DataColumn>().Select(x => x.ColumnName);
model.Values = dt.AsDynamicEnumerable();
model.Customers = new SelectList(CustomerOperation.GetCustomers().Items, "Id", "Name");
model.Jobs = new SelectList(JobOperation.GetCustomersAssemblyList().Items, "scheduleId", "name");
return View(model);
}
and now we could of course have a strongly typed view:
<%
var grid = new WebGrid(Model.Values);
var columns = Model.Columns.Select(x => grid.Column(x));
%>
<%= grid.GetHtml(columns: columns) %>
// and then we could have dropdowns and other stuff
<%= Html.DropDownListFor(x => x.SelectedCustomerId, Model.Customers, "-- customer --") %>
<%= Html.DropDownListFor(x => x.SelectedJobId, Model.Jobs, "-- job --") %>