Context :
Since we are developing in C# MVC3, we wanted to have some classes designed to handle the tables on a web page. (Pagination / search / etc…).
So we finally found that it could be the best to have the following classes :
The table object that will hold all other object and knows the current page / current search etc… (misc informations)
public class Table<T> where T : IPrivateObject
{
...
public ICollection<Column<T>> Columns { get; set; }
public ICollection<Row<T>> Rows { get; set; }
public ICollection<RowMenu<T>> Menus { get; set; }
public ICollection<T> Items { get; set; }
public Table(
ICollection<T> inputItems,
ICollection<Column<T>> columns,
ICollection<RowMenuItem<T>> rowMenuItems,
...)
{
...
this.Columns = columns;
}
The column object that knows which property should be displayed and and a header value
public class Column<T> where T : IPrivateObject
{
public string Value { get; set; }
public Expression<Func<T, object>> Property { get; set; }
public Column(Expression<Func<T, object>> property, string value)
{
this.Property = property;
this.Value = value;
}
}
The other classes are not really interesting so i won’t post them here.
In the controller, we use these classes like that :
public ActionResult Index(string search = null, string sort = null, int order = 1, int take = 10, int page = 1)
{
ICollection<Person> people = prismaManager.PersonManager.Search(search);
ICollection<Column<Person>> columns= new List<Column<Person>>();
columns.Add(new Column<Person>(Person => Person, "Person"));
columns.Add(new Column<Person>(Person => Person.LastMembershipApproval, "Last Membership approval"));
Table<Person> table = people.ToTable(columns);
}
We are now writing a helper that will display the table correctly.
It works well for the header but we face a problem with the Expressions when we want to use the @Html.DisplayFor() helper.
This is what we currently have for the content :
private static string TableRows<T>(HtmlHelper<Table<T>> helper, Table<T> table) where T : IPrivateObject
{
StringBuilder sb = new StringBuilder();
foreach (var item in table.Items)
{
sb.AppendLine("<tr>");
foreach (var column in table.Columns)
{
sb.AppendLine("<td>");
sb.AppendLine(helper.DisplayFor(obj => ??? ).ToString()); // How should I use the Expression that is stored in the column but for the current element ?
sb.AppendLine("</td>");
}
sb.AppendLine("</tr>");
}
return sb.ToString();
}
For this to work, we should set the value of the “Person” parameter from the Expression stored in the column to the current item.
new Column<Person>(Person => Person, "Person"));
How are we supposed to do that ?
Should we (if it is possible) modify the expression to set the value ?
Should we recreate a new Expression using the old one as a basic expression ?
I’ve been searching for 3 days now and I can’t find any answers.
Thanks for your help.
UPDATE :
The problem is (as @Groo & @Darin Dimitrov said) that the Helper is of type HtmlHelper> and not HtmlHelper.
Any idea how I could get an HtmlHelper from a HtmlHelper> ?
UPDATE :
Person class is as following :
public class Person : IPrivateObject
{
public int Id { get; set; }
public int? AddrId { get; set; }
[DisplayName("First Name")]
[StringLength(100)]
[Required]
public string FirstName { get; set; }
[DisplayName("Last Name")]
[StringLength(100)]
[Required]
public string LastName { get; set; }
[DisplayName("Initials")]
[StringLength(6)]
public string Initials { get; set; }
[DisplayName("Last membership approval")]
public Nullable<DateTime> LastMembershipApproval { get; set; }
[DisplayName("Full name")]
public string FullName
{
get
{
return FirstName + " " + LastName;
}
}
public override string ToString()
{
return FullName;
}
}
Here’s how you could proceed. Start by writing a custom view data container implementation which could be as simple as:
and then just instantiate a
HtmlHelper<T>which is what you need:UPDATE:
The previous example doesn’t handle value types because the expression in the column is of type
Expression<Func<T, object>>and when you are pointing to a value type property the value will be boxed and ASP.NET MVC doesn’t allow such expressions to be used with the template helpers. To remedy this problem one possibility is to test whether the value was boxed and extract the actual type: