5

我有一个如下模型:

public class CreateStockcheckJobModel
{
    [Engineer(true)]
    public EngineerModel Engineer { get; set; }
}

我在using中渲染Engineer属性。View<CreateStockcheckJobModel>Html.EditorFor(m => m.Engineer, "EngineerEditor")

如何从部分视图 ( ) 的代码中访问Engineer属性中的值(在这种情况下)?trueEngineerEditor.ascx


下面是我的编辑器代码

<%@ Control Language="C#" Inherits="ViewUserControl<EngineerModel>" %>
<% if (PropertyImRenderingHasAttributeWithTrueBooleanValue) // What goes here?
   { %>
<p>Render one thing</p>
<% }
   else
   { %>
<p>Render another thing</p>
<% } %>

我知道反射,但是我不确定如何使用它,因为属性没有添加到EngineerModel类中,而是添加到类的Engineer属性中CreateStockcheckJobModel。如果我可以PropertyInfo从编辑器代码中获得我正在呈现的内容,那么我将被排序,但我不知道如何获取该信息。如果我沿着枚举CreateStockcheckJobModel类中所有属性的路线走,那么如果我有多个EngineerModel属性(一个可能有属性True,另一个可能有False),我就会遇到问题。

4

2 回答 2

7

这可以在 ASP.NET MVC 3 及更高版本中通过IMetadataAware在您的自定义上实现接口轻松完成EngineerAttribute

public class EngineerAttribute : Attribute, IMetadataAware
{
    public EngineerAttribute(bool isFoo)
    {
        IsFoo = isFoo;
    }

    public bool IsFoo { get; private set; }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["IsFoo"] = IsFoo;
    }
}

然后在模板内:

<%@ Control Language="C#" Inherits="ViewUserControl<EngineerModel>" %>
<%
    var isFoo = (bool)ViewData.ModelMetadata.AdditionalValues["IsFoo"];
%>
<% if (isFoo) { %>
    <p>Render one thing</p>
<% } else { %>
    <p>Render another thing</p>
<% } %>

不幸的是,ASP.NET MVC 2 中不存在此接口。要实现相同的功能,您可以编写自定义元数据提供程序:

public class MyMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(
        IEnumerable<Attribute> attributes, 
        Type containerType, 
        Func<object> modelAccessor, 
        Type modelType, 
        string propertyName
    )
    {
        var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        var engineer = attributes.OfType<EngineerAttribute>().FirstOrDefault();
        if (engineer != null)
        {
            metadata.AdditionalValues["IsFoo"] = engineer.IsFoo;
        }
        return metadata;
    }
}

您将在您Application_Start的注册以替换默认的:

ModelMetadataProviders.Current = new MyMetadataProvider();

现在您可以像我之前展示的那样在模板中访问此元数据,使用ViewData.ModelMetadata.AdditionalValues["IsFoo"]. 显然,您可以在属性中放置一个任意复杂的对象AdditionalValues,而不仅仅是布尔值。

此外,您可能会发现以下有关元数据的文章很有用。

于 2012-09-17T10:50:39.577 回答
1

注意:以下是一种可能的方法,但IMetadataAware按照接受的答案中的描述使用是一种更好的方法。如果可以的话,通常最好避免反思。

你只能通过反射来做到这一点。这是一个很好的例子,说明如何对方法属性执行此操作。

获取EngineerAttributeon 属性值的代码示例Engineer

PropertyInfo pi = Model.GetType().GetProperty("Engineer");
EngineerAttribute a =
    System.Attribute.GetCustomAttribute(pi, typeof(EngineerAttribute));

获取具有属性的所有属性的代码示例[Engineer(true)]

var t = Model.GetType();
var engineerProperties =
    from p in t.GetProperties()
    let ca = System.Attribute.GetCustomAttribute(p, typeof(EngineerAttribute))
    where ca != null && ca.BooleanProperty == true
    select p;

当你拥有这些属性时,你可以使用EditorFor允许你指定额外的视图数据的重载,然后你可以在你的子视图中使用:

Html.EditorFor(m => m.Engineer, new { IsEngineer = isEngineer });
于 2012-09-17T09:31:55.857 回答