2009-03-03 7 views
25

Czy istnieje sposób na utworzenie modelu ViewDataDictionary z modelem i dodatkowymi właściwościami za pomocą pojedynczej linii kodu. Próbuję wykonać wywołanie RenderPartial do mocno napisanego widoku, jednocześnie łącząc zarówno model, jak i niektóre dodatkowe właściwości konfiguracji wyświetlania, bez konieczności jawnego składania obiektu ViewDataDictionary w wielu wierszach. Wygląda na to, że byłoby to możliwe, biorąc pod uwagę przeciążenie RenderPartial, przyjmując zarówno model object, jak i ViewDataDictionary, ale wygląda na to, że po prostu ignoruje ViewDataDictionary, gdy oba są wypełnione.Skrócona instrukcja tworzenia obiektu ViewDataDictionary z elementami modelu i elementami ViewData?

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

znalazłem kogoś z same problem, ale ich rozwiązanie jest takie samo multi-line koncepcja znalazłem: tworzenie dyskretnego ViewDataDictionary z modelem, dodać nowy parametr (-y) i używać go w zaproszeniu RenderPartial .

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

zawsze mogę owinąć tej logiki w ChainedAdd metody zwracającej duplikat słownik z nowego elementu dodanego ale to wydaje się mi brakuje jakiś sposób tworzenia ViewDataDictionary że byłoby to zrobić dla mnie (i to jest nieco bardziej narzutowy, niż miałem nadzieję).

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

Jak dobrze, starając się zebrać ViewDataDictionary z wyraźną Model i ModelState prostu powoduje błąd kompilacji, ponieważ ModelState jest tylko do odczytu.

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

ODPOWIEDŹ (S): Wygląda jak Craig i skończyło się na znalezieniu dwóch oddzielnych składnie, że dostanie pracę. Jestem zdecydowanie stronniczy w tym przypadku, ale podoba mi się pomysł ustawienia modelu i "dekorowania" go później.

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

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

Oczywiście, wciąż obracałbym moje koła bez jego [ostatecznie celnej] odpowiedzi, tak, koło dostaje kwadrat.

Odpowiedz

25

stosowania jako object initializer i zbierania inicjalizatory:

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

Wewnętrzna ViewDataDictionary dostaje jego zbiór zainicjowany, wówczas wypełnia „prawdziwy” ViewDataDictionary pomocą przeciążenia konstruktora który zaczyna ViewDataDictionary zamiast obiektu. Wreszcie inicjator obiektu ustawia model.

Następnie wystarczy przekazać całość bez ustawiania MyModelObject oddzielnie:

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

To wydaje się tworzyć ViewDataDictionary z modelem równym anonimowemu obiektowi, a następnie zastępuje właściwość Model obiektem MyModelObject, nie pozostawiając żadnych dołączonych właściwości. Nauczyłem mnie, że mogę połączyć konstruktora z dodatkowymi inicjalizatorami; coś, czego nie wiedziałem - dzięki. – patridge

+0

Właśnie sprawdziłem kod źródłowy. Ustawienie Model nie powoduje wyczyszczenia słownika. –

+0

Zgadzam się; ustawienie modelu nie powoduje wyczyszczenia słownika. Ale nie ustawiasz słownika w tym kodzie.Tworzysz ViewDataDictionary z modelem anonimowego obiektu zawierającego właściwość SomeDisplayParameter. Następnie za pomocą inicjalizatora zmieniasz model na MyModelObject. – patridge

12

Korzystanie odpowiedź Craiga jako punkt wyjścia - Ja nawet nie wiedziałem, że można połączyć zarówno wywołanie konstruktora obiektu initializer-- Natknąłem się na to snippet z Palermo, które prowadzi do kombinacji, która działa. Używa jakiegoś skrótu słownikowego, który jakoś kończy się zapełnianiem ModelState, gdy jest zużywany przez inicjator obiektu 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" } }; 

ja nadal nie wiem, jak to kończy pracę biorąc pod uwagę, że nie można ustawić ModelState wyraźnie do inicjowania, ale wydaje się, aby utrzymać zarówno oryginalnego obiektu modelu i „uzupełnione” Parametry widoku .Z pewnością istnieje wiele innych permutacji tej składni, które nie działają - nie można połączyć modelu ze słownikiem w jednym obiekcie lub użyć składni inicjalizatora obiektu dla wartości słownika - ale powyższa wersja wydaje się działać.

0

Przyszedłem tutaj z tym samym pytaniem.

Co myślałem praca może było to (przepraszam składni Razor VB)

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

Ale oczywiście można dostać ten błąd w czasie wykonywania:

System.InvalidOperationException był nieobsługiwany przez kod użytkownika

Komunikat = Element modelu przekazany do słownika jest typu "VB $ AnonymousType_1`1 [System.String]", ale ten słownik wymaga elementu modelu typu "ViewModel.Address".

Ale to, co znalazłem, to to, że tak naprawdę chciałem użyć szablonu edytora.

Zamiast renderPartial użytku:

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

Szablon edytor jest tylko częściowy widok, który żyje

~/Views/{model | shared} /EditorTemplates/templatename.vbhtml

My szablon dla adresu jest mocno napisanym widokiem częściowym, ale metoda EditorFor daje możliwość łatwego dodawania dodatkowych elementów danych widoku za pomocą obiektu anon.

W powyższym przykładzie nie musiałem podawać nazwy szablonu "Adres", ponieważ MVC szukałoby szablonu o tej samej nazwie co typ modelu.

Można również przesłonić szablon wyświetlania w ten sam sposób.

2

Utworzono metodę rozszerzenia na HtmlHelper, aby skopiować nazwy właściwości i wartości z anonimowego obiektu do obiektu ViewDataDictionary.

Próbka

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

HtmlHelper Extension

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

Dokładnie tego, czego szukałem! Dzięki –

0

To co pracował dla mnie w starym stylu mvc widoku aspx:

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

rzeczą jest to, że w con Structor Używam bieżących viewdata "new ViewDataDictionary (this.ViewData)", który jest viewdatadictionary zawierający numer modelu, który jest mi potrzebny do sprawdzania poprawności wiadomości.