web-dev-qa-db-ja.com

モデルとViewDataアイテムの両方を使用してViewDataDictionaryを作成するための省略形?

1行のコードでモデルと追加のプロパティを使用してViewDataDictionaryを作成する方法はありますか。複数行にわたってViewDataDictionaryを明示的にアセンブルせずに、モデルといくつかの追加の表示構成プロパティの両方をアセンブルしながら、強く型付けされたビューに対してRenderPartial呼び出しを行おうとしています。モデルRenderPartialobjectの両方をとるViewDataDictionaryオーバーロードを考えると可能であるように見えますが、それらがViewDataDictionaryを無視するように見えます。両方とも入力されます。

// FAIL: This will result in ViewData being a ViewDataDictionary
// where Model = MyModelObject and there are no other parameters available.
this.Html.RenderPartial("SomePartialView", MyModelObject, new ViewDataDictionary(new { SomeDisplayParameter = true }));

同じ問題 の人を見つけましたが、その解決策は私が見つけたのと同じ複数行の概念です。モデルを使用して離散ViewDataDictionaryを作成し、新しいパラメーターを追加して、 RenderPartial呼び出しで使用します。

var SomeViewData = new ViewDataDictionary(MyModelObject);
SomeViewData.Add("SomeDisplayParameter", true);
this.Html.RenderPartial("SomePartialView", SomeViewData);

そのロジックをいつでもChainedAddメソッドにラップして、新しい要素が追加された重複辞書を返すことができますが、これを行うViewDataDictionaryを作成する方法がないようです。 (そしてそれは私が望んでいたよりも少しオーバーヘッドがあります)。

this.Html.RenderPartial("SomePartialView", new ViewDataDictionary(MyModelObject).ChainedAdd("SomeDisplayParameter", true));

public static ViewDataDictionaryExtensions {
    public static ViewDataDictionary ChainedAdd(this ViewDataDictionary source, string key, object value) {
        return source.ChainedAdd(new KeyValuePair<string,object>(key, value));
    }
    public static ViewDataDictionary ChainedAdd(this ViewDataDictionary source, KeyValuePair<string, object> keyAndValue) {
        ViewDataDictionary NewDictionary = new ViewDataDictionary(source);
        NewDictionary.Add(keyAndValue);
        return NewDictionary;
    }
}

同様に、明示的なViewDataDictionaryModelを使用してModelStateをアセンブルしようとすると、ModelStateが読み取り専用であるため、コンパイルエラーが発生します。

// FAIL: Compilation error
this.Html.RenderPartial("SomePartialView", new ViewDataDictionary { Model = MyModelObject, ModelState = new ViewDataDictionary( new { SomeDisplayParameter = true }});

ANSWER(S):Craigと私は、仕事を成し遂げる2つの別々の構文を見つけることになったようです。この場合、私は間違いなく偏見がありますが、最初にモデルを設定し、後でそれを「装飾」するというアイデアが好きです。

new ViewDataDictionary(MyModelObject) { { "SomeDisplayParameter", true }, { "SomeOtherParameter", 3 }, { "SomeThirdParameter", "red" } };

new ViewDataDictionary(new ViewDataDictionary() { {"SomeDisplayParameter", true }})
    { Model = MyModelObject };

もちろん、私は彼の[最終的にはスポットオン]の答えがなくてもホイールを回転させているので、円は正方形になります。

26
patridge

オブジェクト初期化子 およびコレクション初期化子を使用します。

new ViewDataDictionary(new ViewDataDictionary() { {"SomeDisplayParameter", true }})
    {
        Model = MyModelObject
    }

内部のViewDataDictionaryはコレクションを初期化し、オブジェクトの代わりにViewDataDictionaryを受け取るコンストラクターオーバーロードを使用して「実際の」ViewDataDictionaryにデータを入力します。最後に、オブジェクト初期化子がモデルを設定します。

次に、MyModelObjectを個別に設定せずに、すべてを渡します。

this.Html.RenderPartial("SomePartialView", null, 
    new ViewDataDictionary(new ViewDataDictionary() { {"SomeDisplayParameter", true }})
        { Model = MyModelObject });
26
Craig Stuntz

クレイグの答えを出発点として使用すると(コンストラクター呼び出しとオブジェクト初期化子の両方を組み合わせることができるとは知りませんでした)、パレルモからこれに遭遇しました スニペット これが機能する組み合わせにつながります。彼はある種の辞書の省略形を使用しており、ModelStateオブジェクト初期化子によって消費されるとどういうわけかViewDataDictionaryにデータを入力することになります。

new ViewDataDictionary(MyModelObject) { { "SomeDisplayParameter", true }, { "SomeOtherParameter", 3 }, { "SomeThirdParameter", "red" } };
// Of course, this also works with typed ViewDataDictionary objects (what I ended up using)
new ViewDataDictionary<SomeType>(MyModelObject) { { "SomeDisplayParameter", true }, { "SomeOtherParameter", 3 }, { "SomeThirdParameter", "red" } };

イニシャライザでModelStateを明示的に設定できないため、これがどのように機能するかはまだわかりませんが、元のモデルオブジェクトとビューの「追加された」パラメータの両方を維持しているようです。この構文には、機能しない他の多くの順列があることは間違いありません。単一のオブジェクトでモデルをディクショナリと組み合わせたり、ディクショナリ値にオブジェクト初期化構文を使用したりすることはできませんが、上記のバージョンは機能しているようです。

12
patridge

HtmlHelperで拡張メソッドを作成して、プロパティの名前と値を匿名オブジェクトからViewDataDictionaryにコピーしました。

サンプル

Html.RenderPartial("SomePartialView", MyModelObject, new { SomeDisplayParameter = true })

HtmlHelper拡張機能

public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName, object model, object viewData)
{
    var vdd = new ViewDataDictionary(model);
    foreach (var property in viewData.GetType().GetProperties()) {
        vdd[property.Name] = property.GetValue(viewData);
    }
    htmlHelper.RenderPartial(partialViewName, vdd);
}
2
Lucifer Sam

これは、古いスタイルのmvcaspxビューで私のために働いたものです:

<% Html.RenderPartial("ContactPartial", Model.ContactFactuur, new ViewDataDictionary(this.ViewData ) { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "Factuur" } }); %>

ここで重要なのは、コンストラクターで、検証メッセージに必要なモデル状態を含むviewdatadictionaryである現在のviewdata "new ViewDataDictionary(this.ViewData)"を使用することです。

0

私はまったく同じ質問でここに来ました。

私がうまくいくと思ったのはこれでした(VB Razor構文を許してください)

 @Code Html.RenderPartial("Address", Model.MailingAddress, New ViewDataDictionary(New With {.AddressType = "Mailing Address"}))End Code

しかしもちろん、実行時にこのエラーが発生します。

System.InvalidOperationExceptionはユーザーコードによって処理されませんでした

メッセージ=ディクショナリに渡されるモデルアイテムのタイプは「VB $ AnonymousType_1`1 [System.String]」ですが、このディクショナリにはタイプ「ViewModel.Address」のモデルアイテムが必要です。

しかし、私が見つけたのは、とにかく私が本当に使いたかったのはエディターテンプレートだったということです。

RenderPartialの代わりに:

@Html.EditorFor(Function(model) model.MailingAddress, "Address",  New With {.AddressType = "Mailing Address"})

エディターテンプレートは、存続するビューの一部にすぎません

〜/ Views/{Model | Shared} /EditorTemplates/templatename.vbhtml

Addressのテンプレートは強く型付けされた部分ビューですが、EditorForメソッドを使用すると、anonオブジェクトを使用してビューデータアイテムを簡単に追加できます。

上記の例では、MVCがモデルタイプと同じ名前のテンプレートを検索するため、テンプレート名「Address」を含める必要はありませんでした。

同じ方法で表示テンプレートを上書きすることもできます。

0
Darrel Lee