[WPF] DataGrid AutoGenerateColumns 多國語

WPF DataGrid 在 AutoGenerateColumns 的狀態產生多國語的欄位標題。

使用 WPF DataGrid 元素時,為了方便有時會採用自動產生欄位的方式,以 DataGrid ItemsSource 來自於 ObservableCollection<T>、List<T> 等等集合物件的狀況,若沒有其他任何設定,欄位的標題(Header)會直接採用該對應屬性的名稱。這個情形下,我們要如何讓標題能夠以多國語的方式呈現呢?我們一步一步的來完成這個需求。

為了方便起見,我們不談太多甚麼 Notify Property Changed 這類的事情,直接使用一個 List<T> 來當作 DataGrid ItemsSource 來源。

測試用的資料類別 : Person class、MainViewModel class
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class MainViewModel
    {
        public List<Person> People { get; set; }

        public MainViewModel()
        {
            People = new List<Person>
            {
                new Person {Name = "Bill" , Age = 25},
                new Person {Name = "David" , Age = 27}
            };
        }
    }
在 MainWindow 建立基本的 xaml code
<Window x:Class="DataGridHeaderLanguage.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:DataGridHeaderLanguage"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext >
        <local:MainViewModel />
    </Window.DataContext>
    <DataGrid  AutoGenerateColumns="True" ItemsSource="{Binding People}" >
      
    </DataGrid>
</Window>

接下來的步驟要為語言建立資源檔案 (resx),一個是預設語系,一個是繁中語系。

AppResource.resx、AppResource.zh-tw.resx

註:因為這個資源檔可能會在 xaml 的其他位置使用 x:Static 來取得,所以要把存取修飾詞改為 public。

DataGrid 具有一個事件稱為 AutoGeneratingColumn Event ,每當 DataGrid 自動產生一個 Coulmn 的時候,就會引發這個事件,這也正是這一篇的重點。

(1) 最簡單直覺的作法:直接為該事件撰寫事件委派函式並且掛上,簡單有效,但就是看起來沒這麼炫。

修改 xaml Code
<Window x:Class="DataGridHeaderLanguage.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:DataGridHeaderLanguage"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext >
        <local:MainViewModel />
    </Window.DataContext>
    <DataGrid  AutoGenerateColumns="True" ItemsSource="{Binding People}" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn">
      
    </DataGrid>
</Window>
在 C# Code 撰寫對應的事件委派函式
   public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            e.Column.Header = AppResource.ResourceManager.GetString(e.Column.Header.ToString());
        }
    }

這樣就完成了,簡單吧。但這樣的寫法遇到極偏好 MVVM 方式的開發者可能就不喜歡了。

(2) 所以來改裝一下,應用 Behavior<T>,這個類別來自於 Blend SDK 裡的System.Windows.Interactivity 組件,得先將此組件加入參考。接著撰寫自訂的 Behavior

ColumnBehavior class
    public class ColumnBehavior : Behavior<DataGrid>
    {
        protected override void OnAttached()
        {
            AssociatedObject.AutoGeneratingColumn += AssociatedObject_AutoGeneratingColumn; 
        }

        private void AssociatedObject_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            e.Column.Header = AppResource.ResourceManager.GetString(e.Column.Header.ToString());
        }

        protected override void OnDetaching()
        {
            AssociatedObject.AutoGeneratingColumn -= AssociatedObject_AutoGeneratingColumn;
        }
    }

 修改 xaml code (此時可以移除之前寫的事件委派函式),掛上 Behavior

xaml Code
<Window x:Class="DataGridHeaderLanguage.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:DataGridHeaderLanguage"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext >
        <local:MainViewModel />
    </Window.DataContext>
    <DataGrid  AutoGenerateColumns="True" ItemsSource="{Binding People}" >
        <i:Interaction.Behaviors >
            <local:ColumnBehavior />
        </i:Interaction.Behaviors>
    </DataGrid>
</Window>

 大功告成,以後任何的 DataGrid 都可以套用這個 ColumnBehavior 自動載入多國語系的 Header 了。

source : https://github.com/billchungiii/DataGridHeaderLanguage