开发者

Expression lambdas to access sub properties

I'm building a MVC HTML helper that exposes multiple properties of a class.

This is my class:

public class Foo {
    public string Section { get; set; }
    public string Value { get; set; }
}

And here is my helper:

public partial class FooBuilder<TModel> {
    public MvcHtmlString DropDownFooListFor( Expression<Func<TModel, Foo>> expression, string optionLabel = null, IDictionary<string, object> htmlAttributes = null ) {
        var metadata = ModelMetadata.FromLambdaExpression( expression, Helper.ViewData );
        var model = metadata.Model as Foo;

        var items = FooUtility.GetFooValues( metadata.PropertyName ).Select( x => new SelectListItem {
            Text = x,
            Value = x,
            Selected = model != null && model.Value == x
        } );

        var value = Expression.Lambda<Func<TModel, string>>( Expression.MakeMemberAccess( expression.Body, typeof( Foo ).GetProperty( "Value" ) ), Expression.Parameter( typeof( TModel ), "value" ) );
        var list = Expression.Lambda<Func<TModel, string>>( Expression.MakeMemberAccess( expression.Body, typeof( Foo ).GetProperty( "Section" ) ), Expression.Parameter( typeof( TModel ), "section" ) );

        //Helper.ViewContext.Writer.Write(
        //    Helper.HiddenFor( list, new { value = string.Format( "{0}#{1}", FooUtility.GetCurrentSection(), metadata.PropertyName ) } )
        //);

        return Helper.DropDownListFor( value, items, optionLabel, htmlAttributes );
    }
}

Then, inside my view, I call the helper

@(Html.Foo().DropDownFooListFor( x => x.Bar ))

And here is my view model:

public class Baz {
    public Foo Bar { get; set; }
}

My problem is that if I uncomment the three lines commented out (i.e: use the list expression), it miserably fails.

I don't get why using value works as expected but using list doesn't.

I get the following exception:

variable 'x' of type 'Namespace.Baz' referenced from scope '', but it is not defined

Again, Baz is my view model.

What am I doing wrong?


Edit: Ok, this is worse that I thought. It works if I use any of my expr开发者_C百科essions with DropDownListFor, but it doesn't with HiddenFor, or TextBoxFor.


Edit 2: Here is how Helper is defined.

public partial class FooBuilder<TModel> {
    public HtmlHelper<TModel> Helper { get; set; }
}

public static class FooHelpers {
    public static FooBuilder<TModel> Foo<TModel>( this HtmlHelper<TModel> helper ) {
        return new FooBuilder<TModel> { Helper = helper };
    }
}


Create the two lambdas using the parameter which is in scope from the main expression (i.e. expression.Parameters[0]):

var value = Expression.Lambda<Func<TModel, string>>(
    Expression.MakeMemberAccess(
        expression.Body, 
        typeof(Foo).GetProperty("Value")
    ),
    expression.Parameters[0]
);

var list = Expression.Lambda<Func<TModel, string>>(
    Expression.MakeMemberAccess(
        expression.Body, 
        typeof(Foo).GetProperty("Section")
    ),
    expression.Parameters[0]
);

Now you can uncomment the HiddenFor call and it's gonna work.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜