ASP.NET частичные представления MVC: префиксы входных имен
Предположим, у меня есть ViewModel, как
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; }
}
в представлении я могу сделать частичный с
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
в частичном я сделаю
<%= Html.TextBox("Name", Model.Name) %>
or
<%= Html.TextBoxFor(x => x.Name) %>
однако проблема в том, что оба будут отображать name= "Name", В то время как мне нужно иметь name="Child.Name" для того, чтобы модель связующего работала должным образом. Или, имя="Child2.Name" когда я визуализирую второе свойство, используя тот же частичный вид.
как мне сделать мой частичный вид автоматически распознать необходимые префикс? Я могу передать его в качестве параметра, но это слишком неудобно. Это еще хуже, когда я хочу, например, сделать его рекурсивно. Есть ли способ отобразить частичные представления с префиксом или, еще лучше, с автоматическим повторным вызовом лямбда-выражения, чтобы
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
автоматически добавит правильный " ребенок."префикс сгенерированное имя/идентификатор строки?
Я могу принять любое решение, в том числе 3-й партии двигателей и библиотек - я на самом деле использовать свечи View Engine (я "решаю" проблему с помощью своих макросов) и MvcContrib, но не нашел там решения. XForms, InputBuilder, MVC v2 - любой инструмент/insight, который обеспечивает эту функциональность, будет отличным.
В настоящее время я думаю о кодировании этого сам, но это кажется пустой тратой времени, я не могу поверить, что этот тривиальный материал уже не реализован.
много ручной решений может существовать, и все они приветствуются. Например, я могу принудительно отключить мои частичные файлы IPartialViewModel {Public string Prefix; T Model;}. Но я бы предпочел какое-то существующее/утвержденное решение.
обновление: есть аналогичный вопрос без ответа здесь.
10 ответов:
вы можете расширить вспомогательный класс Html следующим образом:
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); }и просто использовать его в вид такой :
<%= Html.PartialFor(model => model.Child, "_AnotherViewModelControl") %>и вы увидите, что все в порядке!
до сих пор я искал то же самое, что я нашел в этом недавнем посте:
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" } }) %>
С помощью MVC2 вы можете достичь этого.
вот строго типизированное представление:
<%@ 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>вот строго типизированное представление для дочернего класса (которое должно храниться в подпапке каталога представления под названием 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 />вот контроллер:
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); } }вот пользовательские классы:
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; } }и выходное источник:
<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>теперь это завершено. Установите точку останова в сообщении создать действие контроллера для проверки. Не использовать этот список, потому что это не будет работать. См. мой вопрос об использовании EditorTemplates с IEnumerable для получения дополнительной информации об этом.
мой ответ, основанный на ответе Махмуда Моравея, включая комментарий Ивана Златева.
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); }изменить: Ответ Мохамуда неверен для вложенного частичного рендеринга. Вам нужно добавить новый префикс к старому префиксу, только если это необходимо. Это не было ясно в последних ответах (:
Это старый вопрос, но для тех, кто приезжает сюда в поисках решения, рассмотрите возможность использования
EditorFor, Как предложено в комментарии в https://stackoverflow.com/a/29809907/456456. чтобы перейти от частичного представления к шаблону редактора, выполните следующие действия.
убедитесь, что ваш частичный вид обязан ComplexType.
переместить частичный вид в подпапку EditorTemplates из текущая папка просмотра или в папку Shared. Теперь это шаблон редактора.
изменить
@Html.Partial("_PartialViewName", Model.ComplexType)to@Html.EditorFor(m => m.ComplexType, "_EditorTemplateName"). Шаблон редактора является необязательным, если это единственный шаблон для сложного типа.элементы ввода Html будут автоматически называться
ComplexType.Fieldname.
PartailFor для asp.net ядро 2 на случай, если кому-то это понадобится.
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); }
Я столкнулся с этой проблемой также, и после большой боли я обнаружил, что было проще перепроектировать мои интерфейсы таким образом, что мне не нужно было отправлять обратно вложенные объекты модели. Это заставило меня изменить мои интерфейсные рабочие процессы: конечно, теперь я требую, чтобы пользователь сделал в два этапа то, что я мечтал сделать на одном, но удобство использования и поддержка кода нового подхода теперь имеет для меня большую ценность.
надеюсь, это поможет некоторым.
вы можете добавить помощник для RenderPartial, который принимает префикс и выводит его в ViewData.
public static void RenderPartial(this HtmlHelper helper,string partialViewName, object model, string prefix) { helper.ViewData["__prefix"] = prefix; helper.RenderPartial(partialViewName, model); }затем еще один помощник, который объединяет значение ViewData
public static void GetName(this HtmlHelper helper, string name) { return string.Concat(helper.ViewData["__prefix"], name); }и так в виде ...
<% Html.RenderPartial("AnotherViewModelControl", Model.Child, "Child.") %>в частичной ...
<%= Html.TextBox(Html.GetName("Name"), Model.Name) %>
Как и вы, я добавляю свойство префикса (строку) в свои ViewModels, которые я добавляю перед своими именами входных данных, связанными с моделью. (ЯГНИ предотвращения ниже)
более элегантным решением может быть базовая модель представления, которая имеет это свойство, и некоторые HtmlHelpers, которые проверяют, является ли модель представления производной от этой базы, и если да, то добавьте префикс к имени ввода.
надеюсь, что это поможет,
Дэн
Как насчет непосредственно перед вызовом RenderPartial вы делаете
<% ViewData["Prefix"] = "Child."; %> <% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>тогда в вашем частичном у вас есть
<%= Html.TextBox(ViewData["Prefix"] + "Name", Model.Name) %>
Comments