利用DataGrid 來列示資料是一件正常事, 然而, 在WPF中若須要列出class property, 若用原廠設定的話, 標題會用property name. 若需要自定標題, 則須要應用DomainNameAttribute 來設置.
在示範中, 會建立一個user control inherit 原廠DataGrid 去設定標題.
CommonDataGrid.xaml
<DataGrid x:Class="WPF.CommonDataGrid.CommonDataGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPF.CommonDataGrid"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
AutoGenerateColumns="True" AutoGeneratingColumn="OnAutoGeneratingColumn" />
CommonDataGrid.xaml.cs
public partial class CommonDataGrid : DataGrid
{
public CommonDataGrid()
{
InitializeComponent();
}
private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
string displayName = GetPropertyDisplayName(e.PropertyDescriptor);
if (!string.IsNullOrEmpty(displayName))
{
e.Column.Header = displayName;
}
}
public static string GetPropertyDisplayName(object descriptor)
{
PropertyDescriptor pd = descriptor as PropertyDescriptor;
if (pd != null)
{
// Check for DisplayName attribute and set the column header accordingly
DisplayNameAttribute displayName = pd.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
if (displayName != null && displayName != DisplayNameAttribute.Default)
{
return displayName.DisplayName;
}
}
else
{
PropertyInfo pi = descriptor as PropertyInfo;
if (pi != null)
{
// Check for DisplayName attribute and set the column header accordingly
Object[] attributes = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true);
for (int i = 0; i < attributes.Length; ++i)
{
DisplayNameAttribute displayName = attributes[i] as DisplayNameAttribute;
if (displayName != null && displayName != DisplayNameAttribute.Default)
{
return displayName.DisplayName;
}
}
}
}
return null;
}
}
在這裡, 應用了MVVM, 為了處理PropertyChanged, 建立了Base class ObservableProperty 去實現 INotifyPropertyChanged.
public class ObservableProperty : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
//if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
為了測試, 建立了一個WPF Window作叫用:
<Window x:Class="WPF.TestUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF.TestUI"
xmlns:Common="clr-namespace:WPF.CommonDataGrid;assembly=WPF.CommonDataGrid"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Common:CommonDataGrid ItemsSource="{Binding TestClasses, Mode=TwoWay}" />
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
namespace WPF.TestUI
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
TestClass.cs
using System.ComponentModel;
namespace WPF.CommonDataGrid
{
public class TestClass : ObservableProperty
{
private int _testID;
[DisplayName("Test ID")]
public int TestID
{
get { return _testID; }
set
{
_testID = value;
SetField(ref _testID, value);
}
}
private string _testStringValue;
[DisplayName("Test string value")]
public string TestStringValue
{
get { return _testStringValue; }
set
{
_testStringValue = value;
SetField(ref _testStringValue, value);
}
}
}
}
MainWindowViewModel.cs
using System.Collections.ObjectModel;
using WPF.CommonDataGrid;
namespace WPF.TestUI
{
public class MainWindowViewModel
{
public ObservableCollection<TestClass> TestClasses { get; set; }
public MainWindowViewModel()
{
TestClasses = new ObservableCollection<TestClass>();
TestClasses.Add(new TestClass() { TestID = 1, TestStringValue = "aaa" });
TestClasses.Add(new TestClass() { TestID = 2, TestStringValue = "bbb" });
}
}
}
Leave a Reply