Сокращение для создания ViewDataDictionary как с моделью, так и с элементами ViewData?

Есть ли способ создать ViewDataDictionary с моделью и дополнительными свойствами с одной строкой кода. Я пытаюсь сделать вызов RenderPartial строго типизированному представлению при сборке как модели, так и некоторых дополнительных свойств конфигурации дисплея без явной сборки ViewDataDictionary в нескольких строках. Похоже, что при перегрузке RenderPartial можно было бы взять как модель object, так и 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;
    }
}

Кроме того, попытка собрать ViewDataDictionary с явным Model и ModelState просто вызывает ошибку компиляции, потому что ModelState доступен только для чтения.

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

ANSWER (S): Похоже, что Крейг и я нашли два отдельных синтаксиса, которые сделают работу. В этом случае я определенно предвзятый, но мне нравится идея сначала установить модель и "украсить" ее.

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

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

Конечно, я все равно буду крутить колеса без его [в конечном счете спот-на] ответе, поэтому круг получает квадрат.

Ответ 1

Используйте инициализатор объектов и инициализаторы коллекции:

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

Ответ 2

Использование Craig в качестве отправной точки - я даже не знал, что вы могли бы объединить вызов конструктора и инициализатор объекта - я наткнулся на этот фрагмент из Палермо, что приводит к комбинации, которая работает. Он использует какое-то словосочетание, которое как-то заканчивает заполнение 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 в инициализаторе, но, похоже, он поддерживает как исходный объект модели, так и "добавленные" параметры для представления. Определенно существует ряд других перестановок этого синтаксиса, которые не работают - вы не можете комбинировать модель со словарем в одном объекте или использовать синтаксис инициализатора объекта для значений словаря, но, похоже, эта работа работает.

Ответ 3

Я создал метод расширения на 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);
}

Ответ 4

Я пришел сюда с тем же вопросом.

То, что, как я думал, может работать, было (простить синтаксис 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/{Модель | Shared}/EditorTemplates/templatename.vbhtml

Мой шаблон для адреса - это строго типизированное частичное представление, но метод EditorFor дает возможность легко добавлять дополнительные элементы данных обзора с помощью анонимного объекта.

В приведенном выше примере мне не нужно было включать имя шаблона "Адрес", поскольку MVC будет искать шаблон с тем же именем, что и тип модели.

Вы также можете переопределить шаблон отображения таким же образом.

Ответ 5

Это то, что сработало для меня в старом стиле mvc aspx:

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

вещь здесь заключается в том, что в конструкторе я использую текущие viewdata "новый ViewDataDictionary (this.ViewData)", который представляет собой viewdatadictionary, содержащий модельное состояние, которое мне нужно для валидационных сообщений.