利用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