ListView
ListView专门针对显示相同数据的不同视图而设计的,常用于显示每个数据项几部分信息的多列视图。ListView继承自ListBox类,并使用View属性进行扩展。
从技术角度看,View指向继承自ViewBase类的任意实例。ViewBase是一个将两个样式捆绑在一起的包,其中一个样式应用到ListView控件(通过DefaultStyleKey属性),而另一个应用到ListView控件中的项(通过ItemContainerDefaultStyleKey属性)。
事实上,为创建能够自定义的具有多列的列表,不需要使用具有View属性的ListView类。通过ListBox控件使用模板和样式也可获得相同的效果。但View属性是一个很有用的抽象概念,其优点有:
- 可重用的视图
- 多视图
- 更好的组织
使用GridView创建列
<ListView Name="lstProducts">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding Path=ModelName}"/>
<GridViewColumn Header="Model"
DisplayMemberBinding="{Binding Path=ModelNumber}"/>
<GridViewColumn Header="Price"
DisplayMemberBinding="{Binding Path=UnitCost, StringFormat={}{0:C}}"/>
</GridView.Columns>
<GridView>
</ListView.View>
</ListView>
为了在单元格中显示数据,DisplayMemberBinding属性不是唯一的方式,通过设置 CellTemplate 属性也可以。
<GridViewColumn Header="Price" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Description}" TextWrapping="Wrap"/>
<!--<Image Source="{Binding Path=ProductImagePath, Converter={StaticResource ImagePathConverter}}>-->
</DataTemplate>
<GridViewColumn.CellTemplate>
</GridViewColumn>
因为要绑定到具体的字段,所以不同列没办法重用模板。
如果同时设置了 DisplayMember 和 CellTemplate 属性,会使用前者为单元格设置内容并忽略模板。
TreeView
TreeView控件在本质上是驻留 TreeViewItem 对象的特殊ItemsControl控件。每个TreeViewItem对象都是单独的ItemsControl 控件,可以包含更多的 TreeViewItem 对象。
从技术角度看,TreeViewItem类继承自HeaderedItemsControl类,该类又继承自ItemsControl类。WPF还提供了另外两个HeaderedItems类:MenuItem和ToolBar.
创建数据绑定的TreeView控件
public class Category : INotifyPropertyChanged
{
private string categoryName;
public string CategoryName
{
get { reutrn categoryName; }
set {
categoryName = value;
OnPropertyChanged(new PropertyChangedEventArgs("CategoryName"));
}
}
private ObservableCollection<Product> products;
public ObservableCollection<Product> Products
{
get { reutrn products; }
set {
products = value;
OnPropertyChanged(new PropertyChangedEventArgs("Products"));
}
}
}
为了显示CategoryName属性,需要提供能处理绑定对象的 TreeView.ItemTemplate.
<TreeView>
<TreeView.ItemTemplate>
<!--HierarchicalDataTemplate能够封装第二个模板-->
<!--两个模板分别用于两个层次,第二个模板使用从第一个模板中选择的项作为数据源-->
<HierarchicalDataTemplate ItemsSource="{Bindign Path=Products}">
<TextBlock Text="{Binding Path=CategoryName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ModelName}"/>
</DataTemplate>
<HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
上面的方式是同时设置了两层模板,但分解每个数据模板并通过数据类型(而不是位置)将之应用到数据对象的情况更加普遍。
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Category}"
ItemsSource="{Binding Path=Products}">
<TextBlock Text="{Binding Path=ModelName}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Product}">
<TextBlock Text="{Binding Path=ModelName}"/>
</HierarchicalDataTemplate>
</Widnow.Resources>
<!--TreeView没有显示设置ItemTemplate,而是根据绑定对象的数据类型匹配-->
<TreeView />
DataGrid
DataGrid控件的基本显示属性如下:
属性名 | 说明 |
---|---|
RowBackground | 绘制每行背景的画刷 |
AlternatingRowBackground | 绘制交替行,默认奇数白色背景,偶数灰色背景 |
ColumnHeaderHight | 顶部的列标题行的高度 |
RowHeaderWidth | 行头的宽度 |
ColumnWidth | 每列默认宽度 |
RowHeight | 每行的高度 |
GridLinesVisibility | 是否显示网格线的 DataGridGridlines枚举值 |
VerticalGridLinesBrush | 绘制列之间网格线的画刷 |
HorizontalGridLinesBrush | 绘制行之间网格线的画刷 |
HeadersVisibility | 是否显示行头和列头 |
HorizontalScrollBarVisibility | 是否显示水平滚动条 |
VerticalScrollBarVisibility | 是否显示垂直滚动条 |
CanUserReorderColumns | 是否允许拖动列来改变显示顺序 |
CanUserResizeColumns | 是否允许调整列的宽度 |
AutoGenerateColumns | 是否自动根据公共属性生成列 |
自定义列
DataGrid控件支持集中类型的列,通过继承自DataGridColumn的不同类来表示:
- DataGridTextColumn - 值被转换为文本,并在TextBlock中显示;当编辑行时,TextBlcok元素被替换为标准的文本框
- DataGridCheckBoxColumn - 列显示复选框,为Boolean值自动使用这种类型。通常,复选框是只读的;当编辑行时,会变成普通的复选框
- DataGridHyperlinkColumn - 列显示可单击的链接
- DataGridComboBox - 编辑模式下会变成下拉的 ComboBox控件
- DataGridTemplateColumn - 允许为显示列值定义数据模板
设置列的格式和样式
可使用与设置TextBlock元素格式相同的方式设置 DataGridTextureColumn 元素的格式,但并没有提供TextBlock的所有属性,这种情况可使用 ElementStyle 属性。ElementStyle属性用于创建应用于 DataGrid 单元格内部的元素的样式。
<DataGridTextColumn>
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
DataGrid提供了少部分用于设置网格其他部分格式的额外属性:
属性 | 样式的使用范围 |
---|---|
ColumnHeaderStyle | 位于网格顶部的列题头的 TextBlock |
RowHeaderStyle | 行题头的 TextBlock |
DragIndicatorStyle | 当用户正在将列题头拖动到新位置时用于列题头的 textBlock |
RowStyle | 用于普通行(没设置ElementStyle属性)的 textBlock |
ElementStyle | 用于创建应用于DataGrid单元格内部元素的样式 |
设置行的格式
对于设置行格式,LoadingRow事件是个强大的工具,允许开发者对当前行数据进行简单的范围检查、比较以及更复杂的操作。
当每一行出现在屏幕上时,会立即引发 LoadingRow 事件,这样不会格式化整个网格。为降低内存开销,在数据中滚动时DataGird控件为显示新数据而重用相同的DataGridRow对象(这也是为什么叫LoadingRow而不是CreatingRow的原因)。如果不慎,DataGrid控件能够将数据加载到已经格式化了的DataGridRow对象中。
// 为价格较高的项提供明亮的橙色背景
private void gridProducts_LoadingRow(object sender, DataGridRowEventArgs e)
{
// 获取行数据对象
Product product = (Product)e.Row.DataContext;
// 条件
if (product.UnitCost > 100)
{
e.Row.Background = highlightBrush;
}
else
{
e.Row.Background = normalBrush;
}
}
显示行细节
行细节是一块可选的独立显示区域,在行的列值的下面显示:
- 能够跨越DataGrid控件的整个宽度,并且不会切入到独立的列中,从而提供了更多可供使用的空间
- 可配置行细节区域,从而只为选择的行显示该区域,当不需要时允许用户折叠额外的细节
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Border BorderBrush="SteelBlue" CornerRadius="5">
<TextBlock Text="{Binding Path=Description}" TextWrapping="Wrap" />
</Border>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
冻结列
冻结列必须位于网格的左侧,通过设置 ForzenColumnCount 属性来决定冻结的列数量。
<DataGrid ForzenColumnCount="1"/>
排序
DataGrid 控件内置了排序功能,只要绑定到实现了 IList 接口的集合(List
用户单击列头,可以根据此列进行排序;按住Shift键可以根据多列进行排序。
编辑
DataGrid控件以几种方式限制编辑功能:
- DataGrid.IsReadOnly - 值为true时不能编辑
- DataGridColumn.IsReadOnly - 值为true时,不能编辑该列
- 只读属性 - 如果数据对象的属性没有 set 方法,不能编辑该列
当单元格切换到编辑模式时发生的变化取决于列的类型。DataGridTextColumn显示文本框,DataGridCheckBox 列显示复选框,下面显示 DataPicker控件:
<DataGridTemplateColumn Header="Date Added">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=DateAdded, Converter={StaticResource DateOnlyConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Path=DateAdded, Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
DataGrid支持基本验证系统,当数据绑定中出问题和属性设置器抛出异常会显示红色外边框。可以通过 ValidationRules 对数据的合法性进行验证。
除此之外,也可以通过其他几种方法进行验证:
方法名 | 说明 |
---|---|
BeginningEdit | 当单元格进入编辑模式时发生 |
PreparingCellForEdit | 用于模板列 |
CellEditEnding | 当单元格正退出编辑模式时发生 |
RowEnditEnding | 当用户在编辑完当前行之后导航到新行时发生 |