覆盖ASP.NET MVC 3中基本视图模型的属性

时间:2012-01-11 20:24:17

标签: asp.net-mvc asp.net-mvc-3

我有一个由两个不同页面共享的视图模型。除了一个属性外,视图模型非常相似:地址。视图模型包含名称和位置字段。但是,客户视图的地址标签应为:客户地址和员工视图的地址标签应为:员工地址。它们还将显示不同的错误消息。

以下是我正在努力完成的简化版本:

public class BaseLocation
{
  [Display(Name="Your Name")]
  public string Name {get;set;}

  public virtual string Address {get;set;}
}

public class CustomerLocation : BaseLocation
{
  [Display(Name="Customer Address")]
  public override string Address {get;set;}
}

public class EmployeeLocation : BaseLocation
{
  [Display(Name="Employee Address")]
  public override string Address {get;set;}
}

然后我为基本位置创建了一个部分,如下所示:

@model BaseLocation
***ASP.NET MVC Helpers here: labels, text, validation, etc.

最后,在Customer和Employee页面中,我将调用partial并将其发送给子类型。

Customer.cshtml
@model CustomerLocation
@Html.Render("_BaseLocation", Model)


Employee.cshtml
@model EmployeeLocation
@Html.Render("_BaseLocation", Model)

结果是我不会看到特定类型的数据属性。例如,在客户页面中,我会得到一个“地址”标签,而不是“客户地址”。

我宁愿不为每种特定类型创建具有相同数据的两个部分,只是因为共享视图模型中的一个属性应该具有不同的标签和错误消息。最好的方法是什么?感谢。

1 个答案:

答案 0 :(得分:1)

由于视图继承的工作方式以及模型的定义方式,传递给LabelForTextBoxFor之类的参数使用类中定义的模型类型。在你的情况下,它总是BaseLocation,这就是它没有被覆盖的原因。

您不一定要为您的班级创建部分内容,但您必须为客户创建一个视图,为员工创建一个视图。由于您已经有两个特定于每种类型的视图,您只需要创建另一个位置视图或将基本位置视图合并到它的父级中。

Customer.cshtml
@model CustomerLocation
@Html.Render("_CustomerBaseLocation", Model)


Employee.cshtml
@model EmployeeLocation
@Html.Render("_EmployeeBaseLocation", Model)

我完全理解您的问题,因为您只想更改一个视图,并且您可能已经使用BaseLocation了几种类似的情况。

可以做这样的事情......

public static IHtmlString LabelTextFor<TModel, TValue>(this HtmlHelper<TModel> html, object model, Expression<Func<TModel, TValue>> expression)
{
    MemberExpression memberExpression = (MemberExpression)expression.Body;
    var propertyName = memberExpression.Member is PropertyInfo ? memberExpression.Member.Name : null;

    //no property name
    if (string.IsNullOrWhiteSpace(propertyName)) return MvcHtmlString.Empty;

    //get display text
    string resolvedLabelText = null;
    var displayattrib = model.GetType().GetProperty(propertyName)
                .GetCustomAttributes(true)
                .SingleOrDefault(f => f is DisplayAttribute) 
                                      as DisplayAttribute;
    if (displayattrib != null) {
        resolvedLabelText = displayattrib.Name;
    }

    if (String.IsNullOrEmpty(resolvedLabelText)) {
        return MvcHtmlString.Empty;
    }

    TagBuilder tag = new TagBuilder("label");
    tag.Attributes.Add("for", TagBuilder.CreateSanitizedId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("")));
    tag.SetInnerText(resolvedLabelText);
    return new HtmlString(tag.ToString());
}

然后在您的_BaseLocation.cshtml中,您可以拨打电话:

@Html.LabelTextFor(Model, m => m.Address)

编写自定义扩展方法来做到这一点是我能想到的全部