2011-07-22 71 views
1

我正在構建一個公開類的多個屬性的MVC HTML助手。訪問子屬性的表達式lambda表達式

這是我的課:

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

這裏是我的幫助:

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); 
    } 
} 

然後,我的觀點裏,我叫助手

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

這裏是我的查看模式:

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

我的問題是,如果我取消三條註釋掉的註釋(即:使用list表達式),它會失敗。

我不明白爲什麼使用value按預期工作,但使用list沒有。

我得到以下異常:

變量 'X' 型的 'Namespace.Baz' 從範圍'引用,但它 沒有定義

再次,Baz是我的查看模型。

我在做什麼錯?


編輯:好吧,這是我想象的還要糟糕。如果我使用DropDownListFor中的任何一個表達式,但它不與HiddenForTextBoxFor一起使用。


編輯2:這裏是如何Helper定義。

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 }; 
    } 
} 
+0

可能重複:http://stackoverflow.com/questions/6106283/memberexpression-invalidoperationexpression-variable-x-referenced-from-scope –

+0

@NickLarsen我在哪裏使用相同的名稱創建不同的參數? –

+0

出於好奇,註釋掉的代碼直接向輸出寫入隱藏,爲什麼要這樣做?另外,你能否更新這段代碼來顯示Helper的定義? –

回答

3

使用正在從範圍主要表達的參數(即expression.Parameters[0])創建兩個lambda表達式:

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] 
); 

現在你可以取消註釋HiddenFor呼叫,這是要去工作。

+0

是的,這很有意義。謝謝Darin。現在我很困惑,你有什麼想法,爲什麼我的表達式使用'Html.DropDownListFor'? –

+0

只是爲了確保我正確理解這一點,參數列表和值創建不同的表達式來獲得相同的值,但他們沒有原始表達式的上下文? –

+0

@Bertrand Marron,你的代碼與'DropDownListFor'一起工作的原因是你永遠不會在這個幫助器中調用它。你只是簡單地從你的助手中返回'MvcHtmlString'結果,它只是在'@'razor方法在lambda表達式中調用'.Compile()'的視圖。就'HiddenFor'而言,如果仔細觀察,你在'ViewContext'中使用的'Write'方法沒有一個需要'MvcHtmlString'的重載。它有一個需要「對象」。這是什麼使用和'.ToString()'立即被稱爲...繼續 –