[WPF] 於DataGrid Binding 使用自定標題

利用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" });
        }
    }
}
About C.H. Ling 262 Articles
a .net / Java developer from Hong Kong and currently located in United Kingdom. Thanks for Google because it solve many technical problems so I build this blog as return. Besides coding and trying advance technology, hiking and traveling is other favorite to me, so I will write down something what I see and what I feel during it. Happy reading!!!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.