如何确保模型绑定能够按预期工作

本文关键字:工作 绑定 模型 何确保 确保 | 更新日期: 2023-09-27 18:24:53

我正在C#ASP.NET MVC4(Razor引擎)中编程。我需要创建一个局部视图,并在多个地方重用它。问题是视图是一个表单,在某些情况下,我需要将它与ViewModel一起使用。我的问题是模型绑定将如何工作,因为在ViewModel中,它将是属性的属性。示例:

public class PersonModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
public class OfficeViewModel
{
    public PersonModel Person { get; set; }
    // other properties
}

PersonModel的部分视图是:

@model SomeNameSpace.PersonModel
@Html.TextBoxFor(m => m.FirstName)
@Html.TextBoxFor(m => m.LastName)

当这个视图被渲染时,它看起来像这样:

<input type="textbox" id="FirstName" name="FirstName" />
<input type="textbox" id="LastName" name="LastName" />

现在,我想在OfficeViewModel中使用相同的视图。在这种情况下,我会在我的办公室视图中这样做:

@{ Html.RenderPartial("Person", Model.Person); }

渲染此局部视图时,将按上面所示进行渲染。如果我不重复使用该视图,我的Office视图将是这样的:

@model SomeNameSpace.OfficeViewModel
@Html.TextBoxFor(m => m.Person.FirstName)
@Html.TextBoxFor(m => m.Person.LastName)

这将被呈现为:

<input type="textbox" id="Person_FirstName" name="Person.FirstName" />
<input type="textbox" id="Person_LastName" name="Person.LastName" />

请注意name属性如何具有Person前缀属性。因此,如果我使用RenderPartial选项并传入Model.Person,模型绑定器会知道在OfficeViewModel中绑定FirstNameLastName

如果模型绑定器足够聪明,可以检查属性的属性,那么当我在OfficeViewModel中有一个ManagerModelEmployeeModel,并且它们都有名为FirstName和LastName的属性时,会发生什么?

我希望我已经清楚了,并提前表示感谢。

如何确保模型绑定能够按预期工作

不幸的是,在这种情况下,Html.RenderPartial没有携带得出正确字段名所需的信息。

如果您想以这种方式重用局部视图,请考虑将编辑器模板与Html.EditorFor一起使用。与其他*For帮助程序一样,EditorFor采用lambda表达式,该表达式允许它继承传递到模板的属性的名称。

@Gerald是对的。默认的RenderPartial无法解决。尽管你可以编写一个自定义的助手来处理这个问题:

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(x => x.Person, "Person")

在这里找到答案:https://stackoverflow.com/a/4807655/78739

基本上我需要设置ViewData.TemplateInfo.HtmlFieldPrefix.

因此,我向PersonModel添加了一个属性,并将其命名为HtmlFieldPrefix。示例:

public class PersonModel
{
    public string HtmlFieldPrefix { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

然后在我的部分观点中,我这样做:

@model SomeNameSpace.PersonModel
@{
    ViewData.TemplateInfo.HtmlFieldPrefix = Model.HtmlFieldPrefix;
}
@Html.TextBoxFor(m => m.FirstName)
@Html.TextBoxFor(m => m.LastName)

在我的控制器操作中,我可以这样做:

model.HtmlFieldPrefix = "Person";
return View("_Person", model);

现在我的渲染视图将如下所示:

<input type="textbox" id="Person_FirstName" name="Person.FirstName" />
<input type="textbox" id="Person_LastName" name="Person.LastName" />

如果我离开模特。HtmlFieldPrefix为null,视图将呈现为:

<input type="textbox" id="FirstName" name="FirstName" />
<input type="textbox" id="LastName" name="LastName" />

因此,这修复了我的问题,并允许我将部分视图与ViewModels一起使用。