显示名称未显示

问题描述:

先决条件:.Net框架4.5.1显示名称未显示

我使用ITypedListICustomTypeDescriptor使DataGrid动态生成列。为了提供用户友好的列名,我创建了属性描述符,如下面的例子所示,为它的构造函数提供DisplayNameAttribute。虽然调试器显示PropertyDescriptor.DisplayName属性获取我在属性DataGrid中提供的属性并没有考虑到该值,仍然显示属性名称而不是属性display name。任何想法我做错了什么?

例WDataGridTest.xaml

<Window x:Class="Local.WGridViewTest" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:l="clr-namespace:Local" 
     Title="WGridViewTest" Height="300" Width="300"> 
    <Window.Resources> 
     <l:DataTable x:Key="DataTable"/> 
    </Window.Resources> 
    <Grid> 
     <DataGrid ItemsSource="{StaticResource ResourceKey=DataTable}"/> 
    </Grid> 
</Window> 

背后WDataGridTest.xaml.cs

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Windows; 
using System.ComponentModel; 

namespace Local { 
    /// <summary>Interaction logic for WGridViewTest.xaml</summary> 
    public partial class WGridViewTest : Window { 
     public WGridViewTest() { 
      InitializeComponent(); 
     } 
    } 

    public class DataTable : BindingList<DataRow>, ITypedList { 
     private PropertyDescriptorCollection _PropertyDescriptors; 

     public DataTable() : 
      base() { 
      AllowNew = false; 
      AllowRemove = false; 
      AllowEdit = true; 
      _PropertyDescriptors = new PropertyDescriptorCollection(new PropertyDescriptor[0], false); 
      _PropertyDescriptors.Add(new DataValuePropertyDescriptor("Column1")); 
      _PropertyDescriptors.Add(new DataValuePropertyDescriptor("Column2")); 
      _PropertyDescriptors.Add(new DataValuePropertyDescriptor("Column3")); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
     } 

     #region ITypedList implementation 
     public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] ListAccessors) { 
      return _PropertyDescriptors; 
     } 
     public string GetListName(PropertyDescriptor[] ListAccessors) { 
      return "Data Table"; 
     } 
     #endregion ITypedList implementation 
    } 

    public class DataRow : ICustomTypeDescriptor { 
     public DataRow(DataTable DataTable) { 
      this.DataTable = DataTable; 
     } 

     public DataTable DataTable { 
      get; 
      private set; 
     } 

     public object GetValue(string ColumnName) { 
      return String.Concat(ColumnName, "@", GetHashCode()); 
     } 

     public void SetValue(string ColumnName, object Value) { 
     } 

     #region ICustomTypeDescriptor implementation 
     public AttributeCollection GetAttributes() { return AttributeCollection.Empty; } 
     public string GetClassName() { return GetType().FullName; } 
     public string GetComponentName() { return GetType().Name; } 
     public TypeConverter GetConverter() { return null; } 
     public EventDescriptor GetDefaultEvent() { return null; } 
     public PropertyDescriptor GetDefaultProperty() { return null; } 
     public object GetEditor(Type EditorBaseType) { return null; } 
     public EventDescriptorCollection GetEvents(Attribute[] Attributes) { return EventDescriptorCollection.Empty; } 
     public EventDescriptorCollection GetEvents() { return EventDescriptorCollection.Empty; } 
     public PropertyDescriptorCollection GetProperties(Attribute[] Attributes) { return DataTable.GetItemProperties(null); } 
     public PropertyDescriptorCollection GetProperties() { return DataTable.GetItemProperties(null); } 
     public object GetPropertyOwner(PropertyDescriptor PropertyDescriptor) { return this; } 
     #endregion Property value tracking 
    } 

    public class DataValuePropertyDescriptor : PropertyDescriptor { 
     public DataValuePropertyDescriptor(string Name) : 
      base(Name, new Attribute[] { new DisplayNameAttribute(String.Concat("Display: ", Name)) }) { 
     } 

     #region PropertyDescriptor implementation 
     public override Type ComponentType { get { return typeof(DataRow); } } 
     public override Type PropertyType { get { return typeof(string); } } 
     public override bool IsReadOnly { get { return false; } } 
     public override bool CanResetValue(object DataRow) { return true; } 
     public override object GetValue(object DataRow) { return ((DataRow)DataRow).GetValue(Name); } 
     public override void ResetValue(object DataRow) { ((DataRow)DataRow).SetValue(Name, null); } 
     public override void SetValue(object DataRow, object Value) { ((DataRow)DataRow).SetValue(Name, Value); } 
     public override bool ShouldSerializeValue(object DataRow) { return false; } 
     #endregion PropertyDescriptor implementation 
    } 
} 

而结果代码如下所示。
enter image description here

+0

代码工作正常,我用4.0 – jHilscher

+0

@jHilscher,试图4.0,看到同样的结果,没有显示名称。你尝试过我的示例,还是你的代码有用? –

+0

我只是复制/粘贴你的样本。 – jHilscher

在几个其他配置上尝试这个例子并得到相同的结果后,我最终覆盖了默认的列模板,如下所示。以防万一,如果有人也会看到这个问题,这是解决方法,但应该记住,它结合到航空主题,因为在Windows 7上没有aero2。如果你不需要支持Windows 7,只需将aero替换为aero2在您的项目中引用适当的程序集。

WDataGridTest.xaml

<Window x:Class="Local.WDataGridTest" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:Local" 
     xmlns:data="clr-namespace:System.Data;assembly=System.Data" 
     xmlns:themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" 
     Title="WGridViewTest" Height="300" Width="300"> 
    <Window.Resources> 
     <local:DataTable x:Key="DataTable"/> 
     <local:DataColumnDisplayNameConverter x:Key="DataColumnDisplayNameConverter"/> 
     <Style x:Key="DataGridColumnHeaderGripperStyle" TargetType="{x:Type Thumb}"> 
      <Setter Property="Width" Value="8"/> 
      <Setter Property="Background" Value="Transparent"/> 
      <Setter Property="Cursor" Value="SizeWE"/> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type Thumb}"> 
         <Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"/> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
     <Style x:Key="DataGridColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}"> 
      <Setter Property="VerticalContentAlignment" Value="Center"/> 
      <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type DataGridColumnHeader}"> 
         <Grid> 
          <themes:DataGridHeaderBorder BorderBrush="{TemplateBinding BorderBrush}" 
                 BorderThickness="{TemplateBinding BorderThickness}" 
                 Background="{TemplateBinding Background}" 
                 IsClickable="{TemplateBinding CanUserSort}" 
                 IsPressed="{TemplateBinding IsPressed}" 
                 IsHovered="{TemplateBinding IsMouseOver}" 
                 Padding="{TemplateBinding Padding}" 
                 SortDirection="{TemplateBinding SortDirection}" 
                 SeparatorBrush="{TemplateBinding SeparatorBrush}" 
                 SeparatorVisibility="{TemplateBinding SeparatorVisibility}"> 
           <TextBlock HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
              TextAlignment="Center" 
              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
              Text="{Binding Converter={StaticResource ResourceKey=DataColumnDisplayNameConverter}, ConverterParameter={StaticResource ResourceKey=DataTable}}" 
              TextWrapping="Wrap"/> 
          </themes:DataGridHeaderBorder> 
          <Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource DataGridColumnHeaderGripperStyle}"/> 
          <Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource DataGridColumnHeaderGripperStyle}"/> 
         </Grid> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </Window.Resources> 
    <Grid> 
     <DataGrid ItemsSource="{Binding Source={StaticResource ResourceKey=DataTable}}" ColumnHeaderStyle="{StaticResource ResourceKey=DataGridColumnHeaderStyle}"/> 
    </Grid> 
</Window> 

背后WDataGridTest.xaml.cs

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Data; 
using System.Globalization; 
using System.ComponentModel; 

namespace Local { 
    /// <summary>Interaction logic for WDataGridTest.xaml</summary> 
    public partial class WDataGridTest : Window { 
     public WDataGridTest() { 
      InitializeComponent(); 
     } 
    } 

    public class DataTable : BindingList<DataRow>, ITypedList { 
     private PropertyDescriptorCollection _PropertyDescriptors; 

     public DataTable() : 
      base() { 
      AllowNew = false; 
      AllowRemove = false; 
      AllowEdit = true; 
      _PropertyDescriptors = new PropertyDescriptorCollection(new PropertyDescriptor[0], false); 
      _PropertyDescriptors.Add(new DataValuePropertyDescriptor("Column1")); 
      _PropertyDescriptors.Add(new DataValuePropertyDescriptor("Column1")); 
      _PropertyDescriptors.Add(new DataValuePropertyDescriptor("Column1")); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
      Items.Add(new DataRow(this)); 
     } 

     #region ITypedList implementation 
     public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] ListAccessors) { 
      return _PropertyDescriptors; 
     } 
     public string GetListName(PropertyDescriptor[] ListAccessors) { 
      return "Data Table"; 
     } 
     #endregion ITypedList implementation 
    } 

    public class DataRow : ICustomTypeDescriptor { 
     public DataRow(DataTable DataTable) { 
      this.DataTable = DataTable; 
     } 

     public DataTable DataTable { 
      get; 
      private set; 
     } 

     public object GetValue(string ColumnName) { 
      return string.Concat(ColumnName, "@", GetHashCode()); 
     } 

     public void SetValue(string ColumnName, object Value) { 
     } 

     #region ICustomTypeDescriptor implementation 
     public AttributeCollection GetAttributes() { return AttributeCollection.Empty; } 
     public string GetClassName() { return GetType().FullName; } 
     public string GetComponentName() { return GetType().Name; } 
     public TypeConverter GetConverter() { return null; } 
     public EventDescriptor GetDefaultEvent() { return null; } 
     public PropertyDescriptor GetDefaultProperty() { return null; } 
     public object GetEditor(Type EditorBaseType) { return null; } 
     public EventDescriptorCollection GetEvents(Attribute[] Attributes) { return EventDescriptorCollection.Empty; } 
     public EventDescriptorCollection GetEvents() { return EventDescriptorCollection.Empty; } 
     public PropertyDescriptorCollection GetProperties(Attribute[] Attributes) { return DataTable.GetItemProperties(null); } 
     public PropertyDescriptorCollection GetProperties() { return DataTable.GetItemProperties(null); } 
     public object GetPropertyOwner(PropertyDescriptor PropertyDescriptor) { return this; } 
     #endregion Property value tracking 
    } 

    public class DataValuePropertyDescriptor : PropertyDescriptor { 
     public DataValuePropertyDescriptor(string Name) : 
      base(Name, new Attribute[] { new DisplayNameAttribute(string.Concat("Display: ", Name)) }) { 
     } 

     #region PropertyDescriptor implementation 
     public override Type ComponentType { get { return typeof(DataRow); } } 
     public override Type PropertyType { get { return typeof(string); } } 
     public override bool IsReadOnly { get { return false; } } 
     public override bool CanResetValue(object DataRow) { return true; } 
     public override object GetValue(object DataRow) { return ((DataRow)DataRow).GetValue(Name); } 
     public override void ResetValue(object DataRow) { ((DataRow)DataRow).SetValue(Name, null); } 
     public override void SetValue(object DataRow, object Value) { ((DataRow)DataRow).SetValue(Name, Value); } 
     public override bool ShouldSerializeValue(object DataRow) { return false; } 
     #endregion PropertyDescriptor implementation 
    } 

    public class DataColumnDisplayNameConverter : IValueConverter { 
     public DataColumnDisplayNameConverter() 
      : base() { 
     } 

     public object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture) { 
      DataTable table = (DataTable)Parameter; 
      string property = (string)Value; 
      foreach (PropertyDescriptor descriptor in table.GetItemProperties(null)) { 
       if (property == descriptor.Name) { 
        return descriptor.DisplayName; 
       } 
      } 
      return DependencyProperty.UnsetValue; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { 
      throw new NotImplementedException(); 
     } 
    } 
}