Question

Supposons que j'ai ViewModel comme

public class AnotherViewModel
{
   public string Name { get; set; }
}
public class MyViewModel
{
   public string Name { get; set; }
   public AnotherViewModel Child { get; set; }
   public AnotherViewModel Child2 { get; set; }
}

Dans la vue, je peux rendre un partiel avec

<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>

Dans le partiel je vais le faire

<%= Html.TextBox("Name", Model.Name) %>
or
<%= Html.TextBoxFor(x => x.Name) %>

Cependant, le problème est que les rendra name="Nom" alors que j'ai besoin d'avoir name="Enfant.Nom de l'" pour que le modèle de classeur pour fonctionner correctement.Ou, nom="Enfant2.Le nom de" quand j'ai rendu la deuxième propriété à l'aide de la même vue partielle.

Comment puis-je faire ma vue partielle de reconnaître automatiquement le préfixe requis?Je peux le passer en paramètre mais c'est trop gênant.C'est encore pire quand je veux par exemple pour la rendre de manière récursive.Est-il un moyen de rendre les vues partielles avec un préfixe, ou, encore mieux, avec l'automatique reconition de l'appel de la lambda expression, afin que les

<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>

ajoutera automatiquement correcte "de l'Enfant." préfixe pour le nom généré par/id cordes?

Je peux accepter n'importe quelle solution, y compris la 3 ème partie de la vue des moteurs et des bibliothèques - je réellement utiliser Allumage du Moteur d'Affichage (j' "résoudre" le problème à l'aide de ses macros) et MvcContrib, mais ne pas y trouver une solution.XForms, InputBuilder, MVC v2 - n'importe quel outil/insight qui offrent cette fonctionnalité sera grande.

Actuellement, je pense que ce codage moi-même, mais il semble comme une perte de temps, je ne crois pas que ce choses triviales, n'est pas mis en œuvre déjà.

Beaucoup de manuel des solutions existent, et elles sont toutes les bienvenues.Par exemple, je peux forcer mes partiels d'être basé sur IPartialViewModel<T> { public string Prefix;T Modèle;}.Mais je préfère la préfère certains/solution approuvée.

Mise à JOUR:il y a une question similaire, avec pas de réponse ici.

Était-ce utile?

La solution

Vous pouvez étendre la classe d'aide Html par ceci:

using System.Web.Mvc.Html


 public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel, TProperty>> expression, string partialViewName)
    {
        string name = ExpressionHelper.GetExpressionText(expression);
        object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
        var viewData = new ViewDataDictionary(helper.ViewData)
        {
            TemplateInfo = new System.Web.Mvc.TemplateInfo
            {
                HtmlFieldPrefix = name
            }
        };

        return helper.Partial(partialViewName, model, viewData);

    }

et simplement l'utiliser dans vos vues comme ceci:

<%= Html.PartialFor(model => model.Child, "_AnotherViewModelControl") %>

et vous verrez tout est ok!

Autres conseils

à ce jour, je cherchais la même chose que j'ai trouvé ce post récent:

http : //davybrion.com/blog/2011/01/prefixing-input-elements-of-partial-views-with-asp-net-mvc/

<% Html.RenderPartial("AnotherViewModelControl", Model.Child, new ViewDataDictionary
{
    TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "Child1" }
})
%>

Ma réponse, basée sur la réponse de Mahmoud Moravej y compris le commentaire de Ivan Zlatev.

    public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel, TProperty>> expression, string partialViewName)
    {
            string name = ExpressionHelper.GetExpressionText(expression);
            object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
            StringBuilder htmlFieldPrefix = new StringBuilder();
            if (helper.ViewData.TemplateInfo.HtmlFieldPrefix != "")
            {
                htmlFieldPrefix.Append(helper.ViewData.TemplateInfo.HtmlFieldPrefix);
                htmlFieldPrefix.Append(name == "" ? "" : "." + name);
            }
            else
                htmlFieldPrefix.Append(name);

            var viewData = new ViewDataDictionary(helper.ViewData)
            {
                TemplateInfo = new System.Web.Mvc.TemplateInfo
                {
                    HtmlFieldPrefix = htmlFieldPrefix.ToString()
                }
            };

        return helper.Partial(partialViewName, model, viewData);
    }

Edit: La réponse de Mohamoud est incorrect pour le rendu partiel imbriqué. Vous devez ajouter le nouveau préfixe à l'ancien préfixe, que si elle est nécessaire. Cela n'a pas été clair dans les dernières réponses (:

Utilisation MVC2 vous pouvez y parvenir.

Voici le point de vue fortement typé:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcLearner.Models.Person>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>

    <% using (Html.BeginForm()) { %>
        <%= Html.LabelFor(person => person.Name) %><br />
        <%= Html.EditorFor(person => person.Name) %><br />
        <%= Html.LabelFor(person => person.Age) %><br />
        <%= Html.EditorFor(person => person.Age) %><br />
        <% foreach (String FavoriteFoods in Model.FavoriteFoods) { %>
            <%= Html.LabelFor(food => FavoriteFoods) %><br />
            <%= Html.EditorFor(food => FavoriteFoods)%><br />
        <% } %>
        <%= Html.EditorFor(person => person.Birthday, "TwoPart") %>
        <input type="submit" value="Submit" />
    <% } %>

</asp:Content>

est ici le point de vue fortement typé pour la classe enfant (qui doit être stocké dans un sous-dossier du répertoire de vue appelé EditorTemplates):

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MvcLearner.Models.TwoPart>" %>

<%= Html.LabelFor(birthday => birthday.Day) %><br />
<%= Html.EditorFor(birthday => birthday.Day) %><br />

<%= Html.LabelFor(birthday => birthday.Month) %><br />
<%= Html.EditorFor(birthday => birthday.Month) %><br />

Voici le contrôleur:

public class PersonController : Controller
{
    //
    // GET: /Person/
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Index()
    {
        return View();
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Create()
    {
        Person person = new Person();
        person.FavoriteFoods.Add("Sushi");
        return View(person);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person person)
    {
        return View(person);
    }
}

Voici les classes personnalisées:

public class Person
{
    public String Name { get; set; }
    public Int32 Age { get; set; }
    public List<String> FavoriteFoods { get; set; }
    public TwoPart Birthday { get; set; }

    public Person()
    {
        this.FavoriteFoods = new List<String>();
        this.Birthday = new TwoPart();
    }
}

public class TwoPart
{
    public Int32 Day { get; set; }
    public Int32 Month { get; set; }
}

Et la source de sortie:

<form action="/Person/Create" method="post"><label for="Name">Name</label><br /> 
    <input class="text-box single-line" id="Name" name="Name" type="text" value="" /><br /> 
    <label for="Age">Age</label><br /> 
    <input class="text-box single-line" id="Age" name="Age" type="text" value="0" /><br /> 
    <label for="FavoriteFoods">FavoriteFoods</label><br /> 
    <input class="text-box single-line" id="FavoriteFoods" name="FavoriteFoods" type="text" value="Sushi" /><br /> 
    <label for="Birthday_Day">Day</label><br /> 
    <input class="text-box single-line" id="Birthday_Day" name="Birthday.Day" type="text" value="0" /><br /> 

    <label for="Birthday_Month">Month</label><br /> 
    <input class="text-box single-line" id="Birthday_Month" name="Birthday.Month" type="text" value="0" /><br /> 
    <input type="submit" value="Submit" /> 
</form>

Maintenant, cela est terminé. Définir un point d'arrêt dans l'action du contrôleur Créer un message pour vérifier. Ne pas utiliser avec des listes mais parce que cela ne fonctionnera pas. Voir ma question sur l'utilisation EditorTemplates avec IEnumerable pour plus sur ce point.

Ceci est une question ancienne, mais pour tous ceux qui arrivent ici à la recherche d'une solution, pensez à utiliser EditorFor, comme l'a suggéré dans un commentaire dans https : //stackoverflow.com/a/29809907/456456 . Pour passer d'une vue partielle à un modèle d'éditeur, procédez comme suit.

  1. Vérifiez que votre vue partielle est lié à ComplexType .

  2. Passez votre vue partielle à un sous-dossier EditorTemplates du dossier de vue en cours ou dans le dossier Shared . Maintenant, il est un modèle d'éditeur.

  3. Modifier @Html.Partial("_PartialViewName", Model.ComplexType) à @Html.EditorFor(m => m.ComplexType, "_EditorTemplateName"). Le modèle de l'éditeur est facultative si elle est le seul modèle pour le type complexe.

Html éléments d'entrée seront automatiquement nommés ComplexType.Fieldname.

PartailFor pour asp.net Core 2 au cas où quelqu'un en a besoin.

    public static ModelExplorer GetModelExplorer<TModel, TResult>(this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TResult>> expression)
    {
        if (expression == null)
            throw new ArgumentNullException(nameof(expression));
        return ExpressionMetadataProvider.FromLambdaExpression(expression, htmlHelper.ViewData, htmlHelper.MetadataProvider);
    }

    public static IHtmlContent PartialFor<TModel, TResult>(this IHtmlHelper<TModel> helper, Expression<Func<TModel, TResult>> expression, string partialViewName, string prefix = "")
    {
        var modelExplorer = helper.GetModelExplorer(expression);
        var viewData = new ViewDataDictionary(helper.ViewData);
        viewData.TemplateInfo.HtmlFieldPrefix += prefix;
        return helper.Partial(partialViewName, modelExplorer.Model, viewData);
    }

Je suis tombé sur cette question aussi et après beaucoup de douleur que j'ai trouvé qu'il était plus facile de redessiner mes interfaces telles que je ne l'ai pas besoin de republier objets de modèle imbriqués. Cela m'a forcé à changer mes flux de travail d'interface: que j'ai besoin maintenant à l'utilisateur de faire en deux étapes ce que je rêvais de faire sur un, mais la maintenabilité de la facilité d'utilisation et le code de la nouvelle approche est d'une plus grande valeur pour moi maintenant

.

Espérons que cela aide certains.

Vous pouvez ajouter une aide pour le RenderPartial qui prend le préfixe et il apparaît dans le ViewData.

    public static void RenderPartial(this HtmlHelper helper,string partialViewName, object model, string prefix)
    {
        helper.ViewData["__prefix"] = prefix;
        helper.RenderPartial(partialViewName, model);
    }

Puis un autre helper qui concatène les ViewData valeur

    public static void GetName(this HtmlHelper helper, string name)
    {
        return string.Concat(helper.ViewData["__prefix"], name);
    }

et donc, dans la vue ...

<% Html.RenderPartial("AnotherViewModelControl", Model.Child, "Child.") %>

dans le partiel ...

<%= Html.TextBox(Html.GetName("Name"), Model.Name) %>

Comme vous, j'ajouter la propriété Prefix (une chaîne) à mes ViewModels que j'append devant mes noms d'entrée du modèle lié. (YAGNI empêchant le bas)

Une solution plus élégante pourrait être un modèle de vue de base qui a cette propriété et quelques HtmlHelpers qui vérifient si le modèle de vue découle de cette base et le cas échéant le préfixe append au nom de l'entrée.

Hope qui aide,

Dan

Que diriez-vous juste avant que vous appelez RenderPartial-vous

<% ViewData["Prefix"] = "Child."; %>
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>

Ensuite, dans votre partiel que vous avez

<%= Html.TextBox(ViewData["Prefix"] + "Name", Model.Name) %>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top