4

我正在用 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 中使用相同的视图。在这种情况下,我会在我的 Office 视图中执行此操作:

@{ 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 的属性时会发生什么?

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

4

3 回答 3

4

不幸的是,在这种情况下,Html.RenderPartial 没有传递必要的信息来提出正确的字段名称。

如果您想以这种方式重用局部视图,请考虑使用带有 Html.EditorFor 的编辑器模板。与其他 *For 帮助器一样,EditorFor 采用 lambda 表达式,它允许它携带传入模板的属性名称。

于 2013-07-25T20:26:54.907 回答
2

@杰拉德是对的。默认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")
于 2013-07-25T21:54:59.113 回答
0

在这里找到答案: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" />

如果我将 model.HtmlFieldPrefix 保留为 null,则视图将呈现为:

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

所以这解决了我的问题,并允许我使用 ViewModels 的局部视图。

于 2013-07-25T20:38:19.973 回答