2011-07-22 6 views
1

私はクラスの複数のプロパティを公開MVC HTMLヘルパーを構築しています。式ラムダ

これが私のクラスである:

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

私の問題は、3行のコメントアウトを解除すると(つまり:listという表現を使用すると)、それは悲惨に失敗します。予想通りvalue作品を使用したが、listを使用して、なぜ私は得ることはありません

はしていません。

私は、次の例外を取得:タイプの 'X'

変数のスコープから参照 'Namespace.Baz' ''、それは はBazは私で、再び

が定義されていません。ビューモデル。

私は間違っていますか?


編集:OK、これは私が思ったことを悪いです。私はDropDownListForと私の式のいずれかを使用する場合、それは動作しますが、それはHiddenFor、またはTextBoxForとしません。


編集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])からのスコープ内にあるパラメータ使用して2つのラムダを作成します。

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

これはかなり意味があります。ありがとうダーリン。今私は混乱しています、なぜあなたの表現が 'Html.DropDownListFor'で動作するのか考えていますか? –

+0

ちょうど私がこれを正しく理解していることを確認するために、listとvalueのパラメーターは同じ値を得るために異なる式を作成していましたが、元の式のコンテキストはありませんでしたか? –

+0

@Bertrand Marron、あなたのコードが 'DropDownListFor'で動作する理由は、あなたがこのヘルパーの中で実際に呼び出すことは決してないということです。あなたは単にあなたのヘルパーから 'MvcHtmlString'の結果を返すだけで、それは' @ 'カミソリメソッドによって '.Compile()'がラムダ上で呼び出されるビューの中にのみあります。あなたが 'ViewContext'で使用している' Write'メソッドを慎重に見れば 'HiddenFor'に関しては、' MvcHtmlString'をとるオーバーロードはありません。それは 'オブジェクト'を取るものを持っています。これは使用されているもので、 '.ToString()'はただちに...と呼ばれます。 –