Alex Rivera | Logout

Iterating over properties of a lambda expression

Asked 2012-09-10T19:14:22.150
8

I am attempting to genericise a complex control which is used in my website quite often but with different fields. The functionality in the control is always the same, it's just the underlying fields which change.

To achieve the method of showing different fields I am attempting to create a HTMLHelper extension which accepts a Expression<Func<TModel,TProperty>> as a parameter, which would contain the properties of a class required for display in the control. For example:

The view:

@model Project.Core.Page
@Html.MyHelper(p => new { p.Author.Name, p.Author.Location, p.Author.Age });

It's the extension I'm having problems with - how can I iterate over the provided params in the lambda to provide each with a TextBoxFor(), or even manually create a input element and populate it with the value and name of the lambda parameter?

The extention in psuedo:

public static MvcHtmlString MyHelper<TModel,TProperty>(
    this HtmlHelper<TModel> helper, 
    Expression<Func<TModel,TProperty>> expression) {
    foreach (var parameter in expression.???) {
        // helper.TextBoxFor(???) 
        // TagBuilder("input").Attributes("name", expression.???)
    }
}

I feel like I've been staring at this for far too long, and I'm also feeling there's a more simple way I'm overlooking of achieving this.

Any help is greatly appreciated. If you need further details, or I've missed something important, let me know.

Edit
Report

2 Answers

1

Perhaps a builder-style API might simplify things:

@(Html.MyHelper(p)
    .Add(p => p.Author.Age)
    .Add(p => p.Author.LastName, "Last Name")
    .Build())

Notice that this allows you to add optional params in case you need them.

The code would look something like this

public static class Test
{
    public static Helper<TModel> MyHelper<TModel>(this HtmlHelper helper, TModel model)
    {
        return new Helper<TModel>(helper, model);
    }
}

public class Helper<TModel>
{
    private readonly HtmlHelper helper;
    private readonly TModel model;

    public Helper(HtmlHelper helper, TModel model)
    {
        this.helper = helper;
        this.model = model;
    }

    public Helper<TModel> Add<TProperty>(Expression<Func<TModel, TProperty>> expression)
    {
        // TODO
        return this;
    }

    public MvcHtmlString Build()
    {
        return new MvcHtmlString("TODO");
    }
}
answered 2012-09-10T19:59:41.343
1

Consider this:

Create App_Code folder

Put the razor helper file Templates.cshtml.

It looks like below:

 @helper Print(string myvalue,string special="")
 {
   <pre> <input id="id" type="text" value ="@myvalue" data-val="@special"/> </pre>
 }

This way you dont have to write HTML in C# files. It is very handy.

Authors.cshtml looks like below:

@model IEnumerable<MvcApplication1.Models.Author>
@{
   ViewBag.Title = "Authors";
}

<h2>Authors</h2>

@foreach(var auth in Model)
{
   @Templates.Print(auth.Name);    
}

books.cshtml looks like below:

@model IEnumerable<MvcApplication1.Models.Book>
@{
    ViewBag.Title = "Books";
 }

<h2>Books</h2>

@foreach(var book in Model)
{
   @Templates.Print(book.Title,book.ISBN);    
}

Plugin all the special properties as you need per model class. If it gets too complicated, look into dynamic and expando object. It depends on how complex your models/viewmodels are.

answered 2012-09-10T22:58:58.077

Your Answer