ASP.NET MVC的部分观点:输入名称前缀(ASP.NET MVC partial views:

2019-07-19 23:00发布

假设我有类似视图模型

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”为了让模型绑定才能正常工作。 或者,名称=“Child2.Name”当我渲染使用相同的局部视图的第二属性。

如何让我的局部视图自动识别所需要的前缀? 我可以把它作为一个参数,但这是太不方便了。 当我想例如递归使其这更是雪上加霜。 有没有一种方法来呈现一个前缀,或者甚至更好的局部视图,与调用lambda表达式,这样的自动reconition

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

会自动添加正确的“孩子”。 前缀生成的名称/ ID字符串?

我可以接受任何的解决方案,其中包括3-第三方视图引擎和库 - 实际上我用星火视图引擎(我“解决”使用其宏问题)MvcContrib和,但没有找到一个解决方案在那里。 XForms的,InputBuilder,MVC V2 - 任何工具/洞察力提供此功能的将是巨大的。

目前,我认为这个编码自己,但它似乎是在浪费时间,我无法相信这个小东西是不是已经实现。

很多手册可能解决方案的存在,所有的人都欢迎。 例如,我可以强制我的泛音是基于离IPartialViewModel <T> {公共前缀串; T型车; }。 但我宁愿更喜欢一些现有/认可的解决方案。

更新:有没有回答类似的问题在这里 。

Answer 1:

您可以通过此扩展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") %>

你会看到一切正常!



Answer 2:

到目前为止,我正在寻找我发现这个最近的文章同样的事情:

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" }
})
%>


Answer 3:

我的回答的基础上,马哈茂德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);
    }

编辑:马哈茂德的答案是不正确的嵌套部分呈现。 您需要将新的前缀追加到旧的前缀,只有当它是必要的。 这不是在最新的答案(明确:



Answer 4:

使用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的更多关于我的问题。



Answer 5:

这是一个老问题,但任何人到达此地寻找一个解决方案,可以考虑使用EditorFor ,如在评论建议https://stackoverflow.com/a/29809907/456456 。 从局部视图移动到编辑模板,请按照下列步骤。

  1. 验证您的局部视图势必的ComplexType。

  2. 移动您的局部视图到子文件夹EditorTemplates当前视图文件夹,或者为共享的文件夹。 现在,它是一个编辑模板。

  3. 改变@Html.Partial("_PartialViewName", Model.ComplexType)@Html.EditorFor(m => m.ComplexType, "_EditorTemplateName") 编辑模板是可选的,如果它是复杂类型的唯一模板。

HTML输入元素将自动被命名为ComplexType.Fieldname



Answer 6:

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


Answer 7:

我碰到这个问题也和许多痛苦后,我发现它更容易重新设计我的接口,这样我也没必要回发嵌套模型对象。 这迫使我改变接口的工作流程:确定我现在要求用户在两个步骤我梦想做一个的事,但这种新方法的实用性和代码的可维护性现在是更大的价值给我。

希望这有助于一些。



Answer 8:

你可以添加一个助手的需要前缀并弹出它的ViewData的的的RenderPartial。

    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) %>


Answer 9:

和你一样,我加前缀属性(字符串)我的ViewModels,我在我的模型的约束输入名称追加。 (YAGNI防止下面)

一个更优雅的解决方案可能是拥有该物业的基本视图模型和一些HtmlHelpers是检查视图模型在这个基础派生,如果是追加前缀的输入名称。

希望帮助,



Answer 10:

如何调用之前的RenderPartial你做

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

然后在你的部分你有

<%= Html.TextBox(ViewData["Prefix"] + "Name", Model.Name) %>


文章来源: ASP.NET MVC partial views: input name prefixes