Even though I know that such libraries already exist, I have decided to create an MVC5 HtmlHelper library to generate Tables from a model. The point is to practice (actually learn) about generics and lambdas in C#.
I want my library to be able to generate an HTML table using a syntax such as:
@Html.DisplayTable(model => model.ListTest).Render()
At this point in time, the above code works perfectly. But when I attempted to add the method exclude
it all went wrong ... And this is where I see how poor my understanding of lambdas and delegate is. (it is actually the first I wrote any code that took a delegate as a parameter)
Below is how I want my call to be made
@Html.DisplayTable(model => model.ListTest).Exclude(l => l.Col1).Render()
then here is the model that I provide to my view
public class TestViewModel
{
public List<RowViewModel> ListTest { get; set; }
}
where RowViewModel
is defined as follow
public class RowViewModel
{
public string Col1 { get; set; } = "Col1Value";
public string Col2 { get; set; } = "Col2Value";
public string Col3 { get; set; } = "Col3Value";
}
My helper
public static class TableHelpers
{
public static HtmlTable<TValue> DisplayTable<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression) where TValue : IList
{
Func<TModel, TValue> deleg = expression.Compile();
var result = deleg(helper.ViewData.Model);
return new HtmlTable<TValue>(result);
}
}
And my "library logic"
public class HtmlTable<TValue> where TValue : IList
{
private TValue _inputModel;
private readonly TableViewModel _outputViewModel = new TableViewModel();
public HtmlTable(TValue model)
{
Init(model);
}
public HtmlTable<TValue> Init(TValue model)
{
if(model.Count == 0)
throw new ArgumentException("The list must not be empty");
_inputModel = model;
UpdateViewModel();
return this;
}
private void UpdateViewModel()
{
var subType = _inputModel.GetContainedType();
var properties = subType.GetProperties();
_outputViewModel.Header = properties.Select(p => p.Name).ToList();
_outputViewModel.Rows = new List<List<string>>();
foreach (var row in _inputModel)
{
var values = _outputViewModel.Header.Select(col => subType.GetProperty(col).GetValue(row, null).ToString()).ToList();
_outputViewModel.Rows.Add(values);
}
}
public HtmlTable<TValue> Exclude<TSubValue>(Expression<Func<TValue, TSubValue>> expression)
{
Func<TValue, TSubValue> deleg = expression.Compile();
var result = deleg(_inputModel);
return this;
}
}
I kind of have an idea of how it should be done if i was to specify the model of a row to my helper such as
@Html.DisplayTable<RowViewModel>(model => model.ListTest).Exclude(l => l.Col1).Render()
but I would really like to be able to determine the type contained in a list to make lambdas work.
All of this might not make any sense, but after struggling with understand lambdas from a theory point of view for a while i decided that it was better to stop reading articles and try to do something with it ...
Aucun commentaire:
Enregistrer un commentaire