Raccourci pour créer un ViewDataDictionary avec à la fois un modèle et des éléments ViewData?

Est-il possible de créer un ViewDataDictionary, avec un modèle et propriétés supplémentaires avec une seule ligne de code. J'essaie de faire un appel RenderPartial à une vue fortement typée tout en assemblant à la fois le modèle et certaines propriétés de configuration d'affichage supplémentaires sans assembler explicitement ViewDataDictionary sur plusieurs lignes. Il semble que ce serait possible étant donné la surcharge RenderPartial prenant à la fois un modèle object et un ViewDataDictionary mais il semble qu'il ignore simplement le ViewDataDictionary chaque fois qu'ils sont tous les deux peupler.

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

, j'ai trouvé quelqu'un d'autre avec le même problème, mais leur solution est la même multi-ligne concept que j'ai trouvé: créer un discret ViewDataDictionary avec le modèle, ajoutez le paramètre(s) et de l'utiliser dans le {[6],} appeler.

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

Je peux toujours envelopper cette logique dans une méthode ChainedAdd qui renvoie un dictionnaire en double avec le nouvel élément ajouté mais il semble juste que je manque un moyen de créer un ViewDataDictionary qui le ferait pour moi (et c'est un peu plus de frais généraux que ce que j'espérais).

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

En outre, essayer d'assembler un ViewDataDictionary avec un Model explicite et ModelState provoque simplement une erreur de compilation car ModelState est en lecture seule.

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

Réponse (S): on dirait que Craig et moi avons fini par trouver deux syntaxes distinctes qui feront le travail. Je suis définitivement biaisé dans ce cas, mais j'aime l'idée de mettre le modèle en premier et de le "décorer" ensuite.

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

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

Bien sûr, je serais toujours en train de tourner mon roues sans sa réponse [éventuellement spot-on], alors, circle obtient le carré.

26
demandé sur Community 2009-03-03 23:19:20

5 réponses

Utilisez un initialiseur d'objet et des initialiseurs de collection:

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

Le viewdatadictionary interne obtient sa collection initialisée, puis cela remplit le" vrai " ViewDataDictionary en utilisant la surcharge du constructeur qui prend ViewDataDictionary au lieu de object. Enfin, l'initialiseur d'objet définit le modèle.

Ensuite, passez le tout sans définir MyModelObject séparément:

this.Html.RenderPartial("SomePartialView", null, 
    new ViewDataDictionary(new ViewDataDictionary() { {"SomeDisplayParameter", true }})
        { Model = MyModelObject });
26
répondu Craig Stuntz 2009-03-04 14:55:44

En utilisant la réponse de Craig comme point de départ-je ne savais même pas que vous pouviez combiner à la fois un appel de constructeur et un initialiseur d'objet-je suis tombé sur cet extrait de Palerme qui conduit à une combinaison qui fonctionne. Il utilise une sorte de raccourci de dictionnaire qui finit par remplir le ModelState lorsqu'il est consommé par l'initialiseur d'objet 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" } };

Je ne vois toujours pas comment cela finit par fonctionner étant donné que vous ne pouvez pas définir le ModelState explicitement dans un initialiseur, mais c'est le cas semblent maintenir à la fois l'objet modèle d'origine et les paramètres "ajoutés" pour la vue. Il y a certainement un certain nombre d'autres permutations de cette syntaxe qui ne fonctionnent pas-vous ne pouvez pas combiner le modèle avec le dictionnaire dans un seul objet ou utiliser la syntaxe object-initializer pour les valeurs du dictionnaire-mais la version ci-dessus semble fonctionner.

12
répondu patridge 2009-03-04 15:04:51

J'ai créé une méthode d'extension sur HtmlHelper pour copier les noms de propriétés et les valeurs d'un objet anonyme dans un ViewDataDictionary.

Exemple de

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

Extension 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
répondu Lucifer Sam 2014-06-26 22:43:21

Je suis venu ici avec exactement la même question.

Ce que je pensais pouvoir fonctionner était ceci (pardonnez la syntaxe VB Razor)

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

, Mais bien sûr, vous obtenez cette erreur au moment de l'exécution:

Système.InvalidOperationException n'a pas été gérée par le code utilisateur

Message = L'élément de modèle passé dans le dictionnaire est de type 'VB $ AnonymousType_1' 1 [System.String]", mais ce dictionnaire nécessite un élément de modèle de type " ViewModel.Adresse".

Mais ce que j'ai trouvé, c'est ce que je voulais vraiment était d'utiliser était Modèle de L'éditeur de toute façon.

Au lieu de RenderPartial utiliser:

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

Un modèle d'éditeur est juste une vue partielle qui vit

~ / Vues/{modèle / partagé} / EditorTemplates / templatename.vbhtml

Mon modèle D'adresse est une vue partielle fortement typée, mais la méthode EditorFor permet d'ajouter facilement des éléments de données de vue supplémentaires avec un objet anon.

Dans l'exemple ci-dessus, je n'avais pas besoin d'inclure le nom du modèle "Address" , car MVC chercher un modèle avec le même nom que le type de modèle.

Vous pouvez également remplacer le modèle d'affichage de la même manière.

0
répondu Darrel Lee 2012-10-29 19:02:21

C'est ce qui a fonctionné pour moi dans l'ancienne vue MVC aspx:

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

La chose ici est que dans le constructeur j'utilise le ViewData actuel " new ViewDataDictionary (this.ViewData) " qui est un viewdatadictionary contenant le modelstate dont j'ai besoin pour les validationmessages.

0
répondu Jeroen van der Meer 2018-02-16 02:50:57