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”이 필요하다는 것입니다. 또는 동일한 부분보기를 사용하여 두 번째 속성을 렌더링 할 때 name = “Child2.Name”입니다.
부분보기가 필요한 접두사를 자동으로 인식하도록하려면 어떻게합니까? 매개 변수로 전달할 수 있지만 너무 불편합니다. 예를 들어 재귀 적으로 렌더링하고 싶을 때 더 나쁩니다. 접두사를 사용하여 부분 뷰를 렌더링하는 방법이 있습니까? 아니면 호출하는 람다 식의 자동 재구성을 사용하여
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
올바른 “자식”을 자동으로 추가합니다. 생성 된 이름 / ID 문자열의 접두사?
타사 뷰 엔진 및 라이브러리를 포함한 모든 솔루션을 수락 할 수 있습니다. 실제로 Spark View Engine (매크로를 사용하여 문제를 “해결”) 및 MvcContrib을 사용하지만 거기에서 솔루션을 찾지 못했습니다. XForms, InputBuilder, MVC v2-이 기능을 제공하는 모든 도구 / 인사이트는 훌륭합니다.
현재 직접 코딩을 생각하고 있지만 시간 낭비 인 것 같습니다.이 사소한 것들이 이미 구현되지 않았다는 것이 믿기지 않습니다.
많은 수동 솔루션이 존재할 수 있으며 모두 환영합니다. 예를 들어, IPartialViewModel <T> {public string Prefix; T 모델; }. 하지만 기존 / 승인 된 솔루션을 선호합니다.
답변
다음과 같이 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" }
})
%>
답변
Ivan Zlatev의 의견을 포함하여 Mahmoud Moravej의 답변을 기반으로 한 내 대답입니다.
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);
}
편집 : Mohamoud의 대답은 중첩 부분 렌더링에 대해 올바르지 않습니다. 필요한 경우에만 이전 접두사에 새 접두사를 추가해야합니다. 이것은 최신 답변에서 명확하지 않았습니다 (:
답변
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>
이제 완료되었습니다. Create Post 컨트롤러 작업에서 중단 점을 설정하여 확인합니다. 그러나 작동하지 않기 때문에 목록과 함께 사용하지 마십시오. 이에 대한 자세한 내용은 IEnumerable과 함께 EditorTemplates 사용에 대한 내 질문을 참조하십시오.
답변
이것은 오래된 질문이지만 해결책을 찾기 위해 여기에 도착하는 사람 EditorFor
은 https://stackoverflow.com/a/29809907/456456 의 의견에 제안 된대로를 사용 하는 것이 좋습니다 . 부분보기에서 편집기 템플릿으로 이동하려면 다음 단계를 따르세요.
-
부분보기가 ComplexType에 바인딩되어 있는지 확인하십시오 .
-
부분보기를 현재보기 폴더 의 하위 폴더 EditorTemplates 또는 Shared 폴더로 이동합니다 . 이제 편집기 템플릿입니다.
-
변경
@Html.Partial("_PartialViewName", Model.ComplexType)
에@Html.EditorFor(m => m.ComplexType, "_EditorTemplateName")
. 복합 유형에 대한 유일한 템플릿 인 경우 편집기 템플릿은 선택 사항입니다.
Html 입력 요소는 자동으로 ComplexType.Fieldname
.
답변
누군가가 그것을 필요로 할 경우를 대비하여 asp.net Core 2에 대한 PartailFor .
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);
}
답변
나는 또한이 문제를 발견했고 많은 고통 끝에 중첩 된 모델 객체를 다시 게시 할 필요가 없도록 인터페이스를 재 설계하는 것이 더 쉽다는 것을 알았습니다. 이로 인해 인터페이스 워크 플로를 변경해야했습니다. 이제 사용자가 하나에서 꿈꾸던 작업을 두 단계로 수행해야하지만 새로운 접근 방식의 유용성과 코드 유지 관리 가능성은 이제 더 큰 가치가 있습니다.
이것이 도움이되기를 바랍니다.