問題提出:
這是今天被問到的一個問題。情況是這樣的:
我們都知道WPF中有一個用來顯示列表數據的DataGrid控件,而且該控件具有一個AutoGenerateColumns 屬性(默認為true),它可以根據給定的數據,自動地設置列的標題,也就是說,我們可以根據需要讀取不同的實體數據,然后綁定到控件上去,它自己知道該如何創建列,以及顯示數據。
這里的問題在於,我們的實體類定義通常都是英文的,例如下面是一個最簡單的例子
public class Employee { public string FirstName { get; set; } public string LastName { get; set; } }
DataGrid會自動為每個屬性建立一個列,並且列標題設置為屬性名稱。例如下面這樣:
但是,美中不足的是,我們的用戶更喜歡中文的標題。那么,我們是否能夠以最小的代價,讓這些標題能顯示中文呢?
解決方案:
首先,我聯想到了MVC中的一個做法,就是需要給實體類添加屬性描述,因為無論如何,我們需要有一個地方可以定義這些中文標題。幸運的是,我們可以直接使用內置的DataAnnotation的功能來實現,例如:
public class Employee { [Display(Name="姓氏")] public string FirstName { get; set; } [Display(Name="名字")] public string LastName { get; set; } }
備注:這里要先引用System.ComponentModel.DataAnnotations 這個程序集。
接下來,我們的問題就是,如何將這里定義好的Display的屬性,讀取到DataGrid的列標題處。我首先想到的是,能否通過定制ColumnHeaderStyle來實現,但經過一些努力,沒有成功。如果有朋友對這個方案有補充,請不吝賜教。
我最后采用的方法是這樣的,DataGrid有一個事件叫:AutoGeneratingColumn ,顧名思義,這個事件就是在列被創建出來之前觸發的。我通過下面的代碼實現了我們想要的功能。
private void DataGrid_AutoGeneratingColumn_1(object sender, DataGridAutoGeneratingColumnEventArgs e) { var result = e.PropertyName; var p = (e.PropertyDescriptor as PropertyDescriptor).ComponentType.GetProperties().FirstOrDefault(x => x.Name == e.PropertyName); if (p != null) { var found = p.GetCustomAttribute<DisplayAttribute>(); if (found != null) result = found.Name; } e.Column.Header = result; }
這樣一來,我們看到的界面就是下面這樣的啦
而且重要的,這個功能是完全通用的,不管日后想要換成什么樣的實體類型,都可以通過定義Display這個Attributel來改變標題。
最后,我還這個功能封裝了一下,以便更加好的使用.我做了一個擴展控件,如下所示
using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using System.Windows.Controls; namespace WpfApplication1 { class xGrid:DataGrid { public xGrid() { AutoGeneratingColumn += (o, e) => { var result = e.PropertyName; var p = (e.PropertyDescriptor as PropertyDescriptor).ComponentType.GetProperties().FirstOrDefault(x => x.Name == e.PropertyName); if (p != null) { var found = p.GetCustomAttribute<DisplayAttribute>(); if (found != null) result = found.Name; } e.Column.Header = result; }; } } }
這樣的話,在項目中任何頁面上我都可以直接像下面這樣使用這個控件了。
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" xmlns:controls="clr-namespace:WpfApplication1" Height="350" Width="525"> <Grid> <controls:xGrid ItemsSource="{Binding}"></controls:xGrid> </Grid> </Window>