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

Mik*_*ike 7 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;}
}
Run Code Online (Sandbox Code Playgroud)

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

@model BaseLocation
***ASP.NET MVC Helpers here: labels, text, validation, etc.
Run Code Online (Sandbox Code Playgroud)

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

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


Employee.cshtml
@model EmployeeLocation
@Html.Render("_BaseLocation", Model)
Run Code Online (Sandbox Code Playgroud)

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

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

Bui*_*ted 1

由于视图继承的工作方式以及模型的定义方式,参数传递给类似的东西LabelForTextBoxFor使用类中定义的模型类型。在你的情况下,它总是如此,BaseLocation这就是为什么它不会被覆盖。

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

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


Employee.cshtml
@model EmployeeLocation
@Html.Render("_EmployeeBaseLocation", Model)
Run Code Online (Sandbox Code Playgroud)

我绝对理解您的问题,因为您只想更改一个视图,并且 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());
}
Run Code Online (Sandbox Code Playgroud)

然后在您的 _BaseLocation.cshtml 中您将进行如下调用:

@Html.LabelTextFor(Model, m => m.Address)
Run Code Online (Sandbox Code Playgroud)

我能想到的就是编写一个自定义扩展方法来执行此操作