C# 无法获取实现类的属性

C# 无法获取实现类的属性,c#,.net,wpf,C#,.net,Wpf,我有一个行为,它接受displayname属性,并在自动生成数据网格时设置其列标题。当网格绑定到一个特定类型的集合时,我可以正常工作。如果我有某个基类的集合,它将不起作用,尽管如果我不使用我的行为,它从基类自动生成派生类的列不会有问题 当集合类型是基类时,找到的唯一属性是来自基类的属性,我希望能够显示来自实现集合的属性 想法 问题是: DataGridAutoGeneratingColumnEventArgs.PropertyDescriptor提供集合的声明值类型的属性信息,而不是实际的项类型

我有一个行为,它接受displayname属性,并在自动生成数据网格时设置其列标题。当网格绑定到一个特定类型的集合时,我可以正常工作。如果我有某个基类的集合,它将不起作用,尽管如果我不使用我的行为,它从基类自动生成派生类的列不会有问题

当集合类型是基类时,找到的唯一属性是来自基类的属性,我希望能够显示来自实现集合的属性

想法

问题是:
DataGridAutoGeneratingColumnEventArgs.PropertyDescriptor
提供集合的声明值类型的属性信息,而不是实际的项类型

行为准则:

        #region Setup

    /// <summary>
    /// Called when [attached].
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.AutoGeneratingColumn += HandleAutoGeneratingColumns;
    }

    /// <summary>
    /// Called when [detaching].
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.AutoGeneratingColumn -= HandleAutoGeneratingColumns;
    }

    #endregion

    #region Helpers

    /// <summary>
    /// Handles the automatic generating columns.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="dataGridAutoGeneratingColumnEventArgs">The <see cref="DataGridAutoGeneratingColumnEventArgs"/> instance containing the event data.</param>
    private void HandleAutoGeneratingColumns(object sender, DataGridAutoGeneratingColumnEventArgs dataGridAutoGeneratingColumnEventArgs)
    {
        if (AssociatedObject != null)
        {
            var displayName = GetPropertyDisplayName(dataGridAutoGeneratingColumnEventArgs.PropertyDescriptor);

            if (!string.IsNullOrEmpty(displayName))
            {
                dataGridAutoGeneratingColumnEventArgs.Column.Header = displayName;
                dataGridAutoGeneratingColumnEventArgs.Column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
            }
            else
            {
                dataGridAutoGeneratingColumnEventArgs.Column.Visibility = Visibility.Collapsed;
            }
        }
    }


    /// <summary>
    /// Gets the display name of the property.
    /// </summary>
    /// <param name="descriptor">The descriptor.</param>
    /// <returns></returns>
    [CanBeNull]
    private static string GetPropertyDisplayName(object descriptor)
    {
        string returnValue = null;

        var propertyDescriptor = descriptor as PropertyDescriptor;
        if (propertyDescriptor != null)
        {
            var displayName = propertyDescriptor.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
            if (displayName != null && !Equals(displayName, DisplayNameAttribute.Default))
            {
                returnValue = displayName.DisplayName;
            }
        }
        else
        {
            var propertyInfo = descriptor as PropertyInfo;
            if (propertyInfo != null)
            {
                var attributes = propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true);
                foreach (var attribute in attributes)
                {
                    var displayName = attribute as DisplayNameAttribute;
                    if (displayName != null && !Equals(displayName, DisplayNameAttribute.Default))
                    {
                        returnValue = displayName.DisplayName;
                    }
                }
            }
        }

        return returnValue;
    }
#区域设置
/// 
///在[附加]时调用。
/// 
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.AutoGeneratingColumn+=HandleAutoGeneratingColumns;
}
/// 
///在[分离]时调用。
/// 
附加时受保护的覆盖无效()
{
base.OnDetaching();
AssociatedObject.AutoGeneratingColumn-=HandleAutoGeneratingColumns;
}
#端区
#地区助手
/// 
///处理自动生成列。
/// 
///发送者。
///包含事件数据的实例。
私有void HandleAutoGeneratingColumns(对象发送方、DataGridAutoGeneratingColumnEventArgs DataGridAutoGeneratingColumnEventArgs)
{
if(AssociatedObject!=null)
{
var displayName=GetPropertyDisplayName(dataGridAutoGeneratingColumnEventArgs.PropertyDescriptor);
如果(!string.IsNullOrEmpty(displayName))
{
dataGridAutoGeneratingColumnEventArgs.Column.Header=displayName;
dataGridAutoGeneratingColumnEventArgs.Column.Width=新的DataGridLength(1,DataGridLengthUnitType.Star);
}
其他的
{
dataGridAutoGeneratingColumnEventArgs.Column.Visibility=可见性。已折叠;
}
}
}
/// 
///获取属性的显示名称。
/// 
///描述符。
/// 
[CanBeNull]
私有静态字符串GetPropertyDisplayName(对象描述符)
{
字符串returnValue=null;
var propertyDescriptor=作为propertyDescriptor的描述符;
if(propertyDescriptor!=null)
{
变量displayName=propertyDescriptor.Attributes[typeof(DisplayNameAttribute)]作为DisplayNameAttribute;
if(displayName!=null&&!等于(displayName,DisplayNameAttribute.Default))
{
returnValue=displayName.displayName;
}
}
其他的
{
var propertyInfo=描述符为propertyInfo;
if(propertyInfo!=null)
{
var attributes=propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute),true);
foreach(属性中的var属性)
{
var displayName=作为displayName属性的属性;
if(displayName!=null&&!等于(displayName,DisplayNameAttribute.Default))
{
returnValue=displayName.displayName;
}
}
}
}
返回值;
}
来自一个绑定属性的示例

public class DefaultMatchedItems : ILookupItem
{
    #region Properties

    /// <summary>
    /// Gets or sets the first column value.
    /// </summary>
    [DisplayName("Long Name")]
    [CanBeNull]
    public string FirstColumnValue { get; set; }

    /// <summary>
    /// Gets or sets the second column value.
    /// </summary>
    [DisplayName("Short Name")]
    [CanBeNull]
    public string SecondColumnValue { get; set; }

    /// <summary>
    /// Gets or sets the third column value.
    /// </summary>
    [DisplayName("Abbreviation")]
    [CanBeNull]
    public string ThirdColumnValue { get; set; }

    /// <summary>
    /// Gets or sets the identifier.
    /// </summary>
    [Browsable(false)]
    [NotNull]
    public string Identifier { get; set; }


    public interface ILookupItem
{

    /// <summary>
    /// Determines whether [contains] [the specified value].
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
    /// <returns>
    ///   <c>true</c> if [contains] [the specified value]; otherwise, <c>false</c>.
    /// </returns>
    bool Contains(string value, bool ignoreCase = true);

    /// <summary>
    /// Gets the display value.
    /// </summary>
    /// <param name="identifier">The identifier.</param>
    /// <returns>The first non blank section of the matching value</returns>
    string GetDisplayValue(string identifier);

}
公共类DefaultMatchedItems:ILookupItem { #区域属性 /// ///获取或设置第一列值。 /// [显示名称(“长名称”)] [CanBeNull] 公共字符串FirstColumnValue{get;set;} /// ///获取或设置第二列值。 /// [显示名称(“短名称”)] [CanBeNull] 公共字符串SecondColumnValue{get;set;} /// ///获取或设置第三列的值。 /// [显示名称(“缩写”)] [CanBeNull] 公共字符串ThirdColumnValue{get;set;} /// ///获取或设置标识符。 /// [可浏览(错误)] [非空] 公共字符串标识符{get;set;} 公共接口ILookupItem { /// ///确定[是否包含][指定的值]。 /// ///价值。 ///如果设置为true[忽略大小写]。 /// ///如果[包含][指定值],则为true;否则为false。 /// bool Contains(字符串值,bool ignoreCase=true); /// ///获取显示值。 /// ///标识符。 ///匹配值的第一个非空部分 字符串GetDisplayValue(字符串标识符); }
DataGridAutoGeneratingColumnEventArgs.PropertyDescriptor
为您提供绑定到
AssociatedObject.ItemsSource的集合的声明项类型的属性信息

如果我绑定一个类型为
ObservableCollection
(当然也可以是
List
)的集合,并用
ItemSub
的实例填充它,我可以使用以下类重新创建它

public class ItemBase
{
    [DisplayName("Base Foo")]
    public virtual String Foo { get; set; }
    [DisplayName("All Bar")]
    public virtual String Bar { get; set; }
}

public class ItemSub : Item
{
    [DisplayName("Sub Foo")]
    public override String Foo { get; set; }
}
对于
Foo
e.PropertyDescriptor.DisplayName
是“基本Foo”

如果我将集合类型更改为
ObservableCollection
(仅用于测试目的--
object
的集合通常不是好的实践),
e.PropertyDescriptor.DisplayName
是“Sub Foo”。如果我随后将集合中第一个项的类型更改为
itembease
,我将得到“Base Foo”


因此,您最好的做法可能是从事件参数中获取属性名称,但请转到
AssociatedObject.Items
以获取集合中实际项的运行时类型,并使用该类型的属性。

DataGridAutoGeneratingColumnEventArgs.PropertyDescriptor
将为您提供声明项的属性信息集合的项目类型