私のような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 = "Child.Name"が必要なのに、両方がname = "Name"をレンダリングすることです。または、同じ部分ビューを使用して2番目のプロパティをレンダリングする場合、name = "Child2.Name"。
必要なプレフィックスを部分ビューに自動的に認識させるにはどうすればよいですか?パラメータとして渡すことができますが、これはあまりにも不便です。これは、たとえば再帰的にレンダリングしたい場合はさらに悪化します。プレフィックス付きの部分ビューをレンダリングする方法はありますか、さらに良いことに、呼び出しているラムダ式を自動的に調整して、
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
正しい「子」が自動的に追加されます。生成された名前/ ID文字列のプレフィックス?
サードパーティのビューエンジンやライブラリなど、あらゆるソリューションを受け入れることができます。実際にはSpark= View Engine(マクロを使用して問題を「解決」)し、MvcContribを使用しましたが、 XForms、InputBuilder、MVC v2-この機能を提供するすべてのツール/洞察は素晴らしいでしょう。
現在、私は自分でこれをコーディングすることを考えていますが、時間の無駄のようです。この些細なことはまだ実装されていないとは信じられません。
多くの手動の解決策が存在する可能性があり、それらはすべて歓迎されます。たとえば、パーシャルをIPartialViewModel <T> {public string Prefix;に基づいて強制することができます。 Tモデル; }。ただし、既存のソリューションまたは承認済みのソリューションを希望します。
更新:答えのない同様の質問があります here 。
これにより、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>
これで完了です。検証するポストコントローラーの作成アクションにブレークポイントを設定します。ただし、機能しないため、リストでこれを使用しないでください。詳細については、IEnumerableでEditorTemplatesを使用することに関する私の質問を参照してください。
これは古い質問ですが、解決策を探してここに到着した人は、 https://stackoverflow.com/a/29809907/456456 のコメントで示唆されているように、EditorFor
の使用を検討してください。 =。部分ビューからエディターテンプレートに移動するには、次の手順を実行します。
部分ビューがComplexTypeにバインドされていることを確認します。
部分ビューを現在のビューフォルダーのサブフォルダーEditorTemplates、またはフォルダーShared。現在、これはエディターテンプレートです。
@Html.Partial("_PartialViewName", Model.ComplexType)
を@Html.EditorFor(m => m.ComplexType, "_EditorTemplateName")
に変更します。複合テンプレートの唯一のテンプレートである場合、エディターテンプレートはオプションです。
Html入力要素には、自動的にComplexType.Fieldname
という名前が付けられます。
PartailFor誰かがそれを必要とする場合のasp.net Core 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);
}
私もこの問題に遭遇し、多くの苦痛の後、ネストされたモデルオブジェクトをポストバックする必要がないようにインターフェイスを再設計する方が簡単であることがわかりました。これにより、インターフェイスワークフローを変更せざるを得なくなりました。ユーザーに1つのステップで夢見ていたことを2つのステップで実行するように要求するようになりましたが、新しいアプローチの使いやすさとコードの保守性は今では大きな価値があります。
これが助けになることを願っています。
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) %>
あなたのように、Prefixプロパティ(文字列)をViewModelに追加し、モデルにバインドされた入力名の前に追加します。 (YAGNIは以下を防止します)
よりエレガントなソリューションは、このプロパティを持つベースビューモデルと、ビューモデルがこのベースから派生するかどうかを確認し、入力名にプレフィックスを追加するHtmlHelpersがある場合があります。
お役に立てば幸いです
ダン
RenderPartialを呼び出す直前はどうですか
<% ViewData["Prefix"] = "Child."; %>
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
次に、あなたのパーシャルにあなたが持っています
<%= Html.TextBox(ViewData["Prefix"] + "Name", Model.Name) %>