WPF DataGrid常用属性记录
组件常用方法:
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 [email protected]}" /> 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 [email protected]}" /> 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接口的实现,但有些不提供自定义排序,所以在使用起来要注意。尤