組件常用方法:
BeginEdit:使DataGrid進入編輯狀態。
CancelEdit:取消DataGrid的編輯狀態。
CollapseRowGroup:閉合DataGrid的行分組。
CommitEdit:確認DataGrid的編輯完成。
ExpandRowGroup:展開DataGrid的行分組。
GetGroupFromItem:從具體Item中得到分組。
ScrollIntoView:滾動DataGrid視圖。
組件常用屬性:
AlternatingRowBackground:獲取或設置一個筆刷用來描繪DataGrid奇數行的背景。
AreRowDetailsFrozen:獲取或設置一個值用來判斷是否凍結每行內容的詳細信息。
AreRowGroupHeadersFrozen:獲取或設置一個值用來判斷是否凍結分組行的頭部。
AutoGenerateColumns:獲取或設置一個值用來判斷是否允許自動生成表列。
CanUserReorderColumns:獲取或設置一個值用來判斷是否允許用戶重新排列表列的位置。
CanUserSortColumns:獲取或設置一個值用來判斷是否允許用戶按列對表中內容進行排序。
CellStyle:獲取或設置單元格的樣式。
ColumnHeaderHeight:獲取或設置列頭的高度。
ColumnHeaderStyle:獲取或設置列頭的樣式。
Columns:獲取組件中包含所有列的集合。
ColumnWidth:獲取或設置列寬。
CurrentColumn:獲取或設置包含當前單元格的列。
CurrentItem:獲取包含當前單元格且與行綁定的數據項。
DragIndicatorStyle:獲取或設置當拖曳列頭時的樣式。
DropLocationIndicatorStyle:獲取或設置呈現列頭時的樣式。
FrozenColumnCount:獲取或設置凍結列的個數。
GridLinesVisibility:獲取或設置網格線的顯示形式。
HeadersVisibility:獲取或設置行頭及列頭的顯示形式。
HorizontalGridLinesBrush:獲取或設置水平網格線的筆刷。
HorizontalScrollBarVisibility:獲取或設置水平滾動條的顯示樣式。
IsReadOnly:獲取或設置DataGrid是否為只讀。
MaxColumnWidth:獲取或設置DataGrid的最大列寬。
MinColumnWidth:獲取或設置DataGrid的最小列寬。
RowBackground:獲取或設置用於填充行背景的筆刷。
RowDetailsTemplate:獲取或設置被用於顯示行詳細部分的內容的模板。
RowDetailsVisibilityMode:獲取或設置一個值用以判定行詳細部分是否顯示。
RowGroupHeaderStyles:獲取呈現行分組頭部的樣式。
RowHeaderStyle:獲取或設置呈現行頭的樣式。
RowHeaderWidth:獲取或設置行頭的寬度。
RowHeight:獲取或設置每行的高度。
RowStyle:獲取或設置呈現行時的樣式。
SelectedIndex:獲取或設置當前選中部分的索引值。
SelectedItem:獲取或設置與當前被選中行綁定的數據項。
SelectedItems:獲取與當前被選中的各行綁定的數據項們的列表(List)。
SelectionMode:獲取或設置DataGrid的選取模式。
VerticalGridLinesBrush:獲取或設置垂直網格線的筆刷。
VerticalScrollBarVisibility:獲取或設置垂直滾動條的顯示樣式。
組件常用事件:
BeginningEdit:發生於一個單元格或行進入編輯模式之前。
CellEditEnded:發生於一個單元格編輯已被確認或取消。
CellEditEnding:發生於一個單元格正在結束編輯時。
CurrentCellChanged:發生於一個單元格成為當前單元格時。
PreparingCellForEdit:發生於在DataGridTemplateColumn下的單元格進入編輯模式時。
SelectionChanged:發生於當SelectedItem或SelectedItems屬性值改變時。
1.DataGrid隔行變色
RowBackground和AlternatingRowBackground設置一排交替行的背景。AlternationCount是將用於行的樣式或顏色的總數
1 <DataGrid Name="dg" RowHeaderWidth="50" AlternationCount="2" AlternatingRowBackground="#F4F4F4" AutoGenerateColumns="False" Grid.Row="1" HeadersVisibility="All" Margin="4" > 2 <DataGrid.Columns> 3 <DataGridTextColumn Binding="{Binding Name}" Header="Name"/> 4 </DataGrid.Columns> 5 </DataGrid>
如果設置AlternatingRowBackground刷,將被分配到行,其中(rownumber%AlternationIdex)== 1
1 <Style x:Key="DataGridDemoRowStyle" 2 TargetType="{x:Type Custom:DataGridRow}"> 3 <Style.Triggers> 4 <Trigger Property="AlternationIndex" Value="2" > 5 <Setter Property="Background" Value="{StaticResource RowBackgroundAlternationIndex2Brush}" /> 6 </Trigger> 7 <Trigger Property="AlternationIndex" Value="3"> 8 <Setter Property="Background" Value="{StaticResource RowBackgroundAlternationIndex3Brush}" /> 9 </Trigger> 10 </Style.Triggers> 11 </Style>
請注意對於上面的樣式,有目的的,我只覆蓋AlternationIndex= 2,3。對於AlternationIndex= 0時,它使用RowBackground。
對於AlternationIndex= 1,它使用從DataGrid中AlternatingRowBackground的。
2.DataGrid的ErrorTemplate屬性
1 <Style x:Key="{x:Type DataGridRow}" TargetType="{x:Type DataGridRow}"> 2 <Setter Property="Background" Value="Transparent" /> 3 <Setter Property="SnapsToDevicePixels" Value="true"/> 4 <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" /> 5 <Setter Property="ValidationErrorTemplate"> 6 <Setter.Value> 7 <ControlTemplate> 8 <TextBlock Margin="2,0,0,0" VerticalAlignment="Center" Foreground="#FFdc000c" Text="!" /> 9 </ControlTemplate> 10 </Setter.Value> 11 </Setter> 12 </Style>
上面這段XAML設置了DataGridRow的ValidationErrorTemplate為RowHeader通過模板
1 <Style x:Key="{x:Type DataGridRowHeader}" TargetType="{x:Type DataGridRowHeader}"> 2 <Setter Property="Background" Value="{DynamicResource DataGridHeaderBackground}" /> 3 <Setter Property="Foreground" Value="{DynamicResource DataGridHeaderForeground}" /> 4 <Setter Property="BorderBrush" Value="{DynamicResource DataGridGridLines}" /> 5 <Setter Property="BorderThickness" Value="0,0,0,1" /> 6 <Setter Property="Width" Value="16"/> 7 <Setter Property="Template"> 8 <Setter.Value> 9 <ControlTemplate TargetType="{x:Type DataGridRowHeader}"> 10 <Grid> 11 <Border Background="{TemplateBinding Background}" 12 BorderBrush="{TemplateBinding BorderBrush}" 13 BorderThickness="{TemplateBinding BorderThickness}" 14 Padding ="{TemplateBinding Padding}"> 15 16 <StackPanel Orientation="Horizontal"> 17 <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/> 18 <Control SnapsToDevicePixels="false" 19 Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=(Validation.HasError), Converter={StaticResource BooleanToVisibilityConverter}}" 20 Template="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=ValidationErrorTemplate}" /> 21 </StackPanel> 22 </Border> 23 <Thumb x:Name="PART_TopHeaderGripper" 24 VerticalAlignment="Top" 25 Style="{StaticResource RowHeaderGripperStyle}"/> 26 <Thumb x:Name="PART_BottomHeaderGripper" 27 VerticalAlignment="Bottom" 28 Style="{StaticResource RowHeaderGripperStyle}"/> 29 </Grid> 30 </ControlTemplate> 31 </Setter.Value> 32 </Setter> 33 34 <Style.Triggers> 35 <Trigger Property="IsMouseOver" Value="True"> 36 <Setter Property="Background" Value="{DynamicResource DataGridHeaderBackgroundHover}" /> 37 <Setter Property="Foreground" Value="{DynamicResource DataGridHeaderForegroundHover}" /> 38 </Trigger> 39 <Trigger Property="IsPressed" Value="True"> 40 <Setter Property="Background" Value="{DynamicResource DataGridHeaderBackgroundPressed}" /> 41 <Setter Property="Foreground" Value="{DynamicResource DataGridHeaderForegroundPressed}" /> 42 </Trigger> 43 <Trigger Property="IsRowSelected" Value="True"> 44 <Setter Property="Background" Value="{DynamicResource DataGridHeaderBackgroundSelected}" /> 45 <Setter Property="Foreground" Value="{DynamicResource DataGridHeaderForegroundSelected}" /> 46 </Trigger> 47 </Style.Triggers> 48 </Style>
主對於錯誤驗證主要是 當有錯誤的時候Control顯示,並獲取上面設置的DataGridRow的錯誤驗證模板為Control的模板,當沒有錯誤時就隱藏作為驗證顯示的Control
3.DataGrid 視圖(排序、過濾、分組)
CollectionView介紹
事實上當你將后台數據列表綁定到一個列表控件時,WPF為了默默地在數據列表和列表控件之間增加了層稱為CollectionView(列表視圖)的東西,其支持很多高級操作,比如排序,分組,過濾等.這樣我們就可以將這個過程分成3個部分來看:數據列表(維持着后台數據),列表視圖(維持着一些附加狀態,比如"當前項","排序"等),列表控件(負責對CollectionView的呈現,而不是對Collection)
1 CollectionView cv = new CollectionView(myList); 2 3 this.listBox.ItemsSource = cv;
CollectionViewSource介紹
CollectionViewSource是CollectionView的一個XAML代理,意思就是說CollectionView不能在XAML中使用,如果希望在XML將CollectionView綁定到某個列表控件,那么請使用CollectionViewSource.它與CollectionView的基本關系是"HAS A". CollectionViewSource擁有一個CollectionView類型的View屬性來指定其對應的CollectionView對象,與之對應的,其還有一個Source屬性,來指明數據來源.一個簡單的流程是:將數據列表綁定到CollectionViewSource的Source屬性,然后將列表控件的ItemsSource屬性綁定到CollectionViewSource的View屬性.為什么不直接將列表控件的ItemSource屬性綁定到數據列表呢,這取決於你是否需要查找到該CollectionViewSource進而查找到其View來進行視圖操作(比如排序,導航等).這可能說得有些混亂了.看看下面的例子:
1 <Window.Resources> 2 3 <XmlDataProvider x:Key="Employees" XPath="/Employees/*"> 4 <x:XData> 5 <Employees xmlns=""> 6 <Employee Name="Terry Adams" Type="FTE" EmployeeNumber="1" /> 7 <Employee Name="Claire O'Donnell" Type="FTE" EmployeeNumber="12345" /> 8 <Employee Name="Palle Peterson" Type="FTE" EmployeeNumber="5678" /> 9 <Employee Name="Amy E. Alberts" Type="CSG" EmployeeNumber="99222" /> 10 <Employee Name="Stefan Hesse" Type="Vendor" EmployeeNumber="-" /> 11 </Employees> 12 </x:XData> 13 </XmlDataProvider> 14 15 <DataTemplate DataType="Employee"> 16 <TextBlock Text="{Binding XPath=@Name}" /> 17 </DataTemplate> 18 19 </Window.Resources> 20 21 <StackPanel> 22 <ListBox ItemsSource="{Binding Source={StaticResource Employees}}"/> 23 </StackPanel>
上面的例子中,我們按照傳統的方式,將ListBox的ItemsSource綁定到一個XMLDataProvider上,工作得很好,后來我們發現WPF中可以利用CollectionView來實現列表排序,當然這種排序我們希望僅僅是在表現層,所以我們決定我XAML來做.當在實際改造這段代碼的過程中,我們傷透了腦子,因為要在XAML中為我們的數據找到CollectionView對象並非易事.
事實上,我們僅僅需要改變一下數據綁定的流程就可以了.我們將數據與CollectionViewSource關聯,然后CollectionViewSource與列表控件相關聯,然后我們就可以在CollectionViewSource插入我們任何想要的排序方式了.
1 <Window.Resources> 2 3 <XmlDataProvider x:Key="Employees" XPath="/Employees/*"> 4 <x:XData> 5 <Employees xmlns=""> 6 <Employee Name="Terry Adams" Type="FTE" EmployeeNumber="1" /> 7 <Employee Name="Claire O'Donnell" Type="FTE" EmployeeNumber="12345" /> 8 <Employee Name="Palle Peterson" Type="FTE" EmployeeNumber="5678" /> 9 <Employee Name="Amy E. Alberts" Type="CSG" EmployeeNumber="99222" /> 10 <Employee Name="Stefan Hesse" Type="Vendor" EmployeeNumber="-" /> 11 </Employees> 12 </x:XData> 13 </XmlDataProvider> 14 15 <CollectionViewSource x:Key="cvs" Source="{Binding Source={StaticResource Employees}, XPath=/Employees/*}"> 16 <CollectionViewSource.SortDescriptions> 17 <!--在這里插入排序描述--> 18 </CollectionViewSource.SortDescriptions> 19 <CollectionViewSource.GroupDescriptions> 20 <!--在這里插入分組描述--> 21 </CollectionViewSource.GroupDescriptions> 22 </CollectionViewSource> 23 24 <DataTemplate DataType="Employee"> 25 <TextBlock Text="{Binding XPath=@Name}" /> 26 </DataTemplate> 27 28 </Window.Resources> 29 30 <StackPanel> 31 <ListBox ItemsSource="{Binding Source={StaticResource cvs}}" x:Name="lb"/> 32 </StackPanel>
默認的數據集視圖供參考:
集合數據 | 默認視圖 | 注釋 |
IEnumerable |
CollectionView | 無法對項進行分組。 |
IList |
ListCollectionView |
最快。 |
IBindingList |
BindingListCollectionView |
public partial class Window1 : Window { private void buttonPrevious_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView(); view.MoveCurrentToPrevious(); } private void buttonNext_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView(); view.MoveCurrentToNext(); } ICollectionView GetFamilyView() { People people = this.FindResource("Family") as People; return CollectionViewSource.GetDefaultView(people); } }
- 過濾篩選
同時為該排序按鈕提供點擊事件如下:
1 private void buttonFilter_Click(object sender, RoutedEventArgs e) 2 { 3 ICollectionView view = GetFamilyView(); 4 view.Filter = delegate(object target) 5 { 6 return ((Person)target).Age > 25; 7 }; 8 //view.Filter = new Predicate<object>(delegate(object target) 9 // { 10 // return ((Person)target).Age > 25; 11 // }); 12 }
過濾比較簡單,不在贅述。在這里只要理解Predicate<object>型別這個委托變量Filter就行了。視圖里面的每一項滿足條件的返回出來
- 分組
獲取數據源視圖,在分組描述里加上需要分組的屬性分組描述,這里需要分組的是Age
1 private void buttonGroup_Click(object sender, RoutedEventArgs e) 2 { 3 ICollectionView view = GetFamilyView(); 4 view.GroupDescriptions.Add(new PropertyGroupDescription("Age")); 5 }
接下來是開啟GroupStyle,並設置GroupStyle的樣式就可以了
注意:在GroupStyle中綁定的Name不是指Person中的Name,而是view.GroupDescriptions.Add(new PropertyGroupDescription("Age"));中指定的這個Age。
上文也說了,這是一種最簡單的分組,在實際應用中,分組往往要復雜的多。比如以年齡分組來說,就不可能像上文中一樣,以一歲做為一組。現在,我們來實現如下的分組要求:
0-30:年輕;
30-60:中年;
>60:老年;
所有的自定義分組器都需要實現接口IValueConverter,如下:
1 class AgeToRangeConver: IValueConverter 2 { 3 4 #region IValueConverter 成員 5 6 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 7 { 8 int iValue = (int)value; 9 if (0 < iValue && iValue <= 30) 10 { 11 return "年輕"; 12 } 13 else if (30 < iValue && iValue <= 60) 14 { 15 return "中年"; 16 } 17 else 18 { 19 return "老年"; 20 } 21 } 22 23 public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 24 { 25 throw new NotImplementedException(); 26 } 27 28 #endregion 29 }
然后,點擊事件修改為:
1 private void buttonGroup_Click(object sender, RoutedEventArgs e) 2 { 3 ICollectionView view = GetFamilyView(); 4 view.GroupDescriptions.Add(new PropertyGroupDescription("Age", new AgeToRangeConver())); 5 }
可以看到,分組已經按我們的要求實現了。
- 排序
基本實現排序
1 private void buttonSort_Click(object sender, RoutedEventArgs e) 2 { 3 ICollectionView view = GetFamilyView(); 4 view.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Ascending)); 5 }
有時候默認的比較器不能滿足我們排序的需求,我們會用到自定義排序
1 class PersonAgeSort: IComparer 2 { 3 4 #region IComparer 成員 5 6 public int Compare(object x, object y) 7 { 8 Person personx = x as Person; 9 Person persony = y as Person; 10 if (personx.Age > persony.Age) 11 { 12 return 1; 13 } 14 else if (personx.Age == persony.Age) 15 { 16 return 0; 17 } 18 else 19 { 20 return -1; 21 } 22 //return personx.Age.CompareTo(persony.Age); 23 } 24 25 #endregion 26 } 27 28 然后,按鈕事件改為: 29 30 private void buttonSort_Click(object sender, RoutedEventArgs e) 31 { 32 ListCollectionView view = GetFamilyView() as ListCollectionView; 33 view.CustomSort = new PersonAgeSort(); 34 }
注意按鈕事件中,我們將GetFamilyView方法返回值轉型為了ListCollectionView。因為他在WPF時用來包裝IList接口並提供視圖功能的類。在WPF中還有一些ICollectionView接口的實現,但有些不提供自定義排序,所以在使用起來要注意。尤