Сокращения для создания ViewDataDictionary с элементами модели и ViewData? - PullRequest
26 голосов
/ 03 марта 2009

Есть ли способ создать 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 }});

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

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

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

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

Ответы [ 5 ]

26 голосов
/ 03 марта 2009

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

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 });
12 голосов
/ 04 марта 2009

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

2 голосов
/ 27 июня 2014

Я создал метод расширения в HtmlHelper для копирования имен и значений свойств из анонимного объекта в ViewDataDictionary.

Sample

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);
}
0 голосов
/ 22 ноября 2014

Вот что у меня сработало в старом стиле mvc aspx view:

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

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

0 голосов
/ 21 октября 2012

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

Я подумал, что это может сработать (простите за синтаксис 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

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

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

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

...