系列文章链接
- WPF进阶技巧和实战01-小技巧
- WPF进阶技巧和实战02-布局
- WPF进阶技巧和实战03-控件(1-控件及内容控件)
- WPF进阶技巧和实战03-控件(2-特殊容器)
- WPF进阶技巧和实战03-控件(5-列表、树、网格01)
- WPF进阶技巧和实战03-控件(5-列表、树、网格02)
- WPF进阶技巧和实战03-控件(5-列表、树、网格03)
- WPF进阶技巧和实战03-控件(5-列表、树、网格04)
- WPF进阶技巧和实战04-资源
- WPF进阶技巧和实战05-样式与行为
- WPF进阶技巧和实战06-控件模板
- WPF进阶技巧和实战07--自定义元素01
- WPF进阶技巧和实战07--自定义元素02
- WPF进阶技巧和实战08-依赖属性与绑定01
- WPF进阶技巧和实战08-依赖属性与绑定02
- WPF进阶技巧和实战08-依赖属性与绑定03
ListView控件
ListView继承自简单的没有特色的ListBox,增加了对基于列显示的支持,并增加了快速切换视图或显示模式的能力,而不需要重新绑定数据以重新构建列表。
ListView类继承自ListBox类,并使用View属性进行扩展(可以创建丰富的列表)。通过两个样式来设置View,一个用于ListView控件,一个用于ListView控件的项。
使用GridView创建列
GridView类继承自ViewBase类,表示具有多列的列表视图,通过GridView.Columns集合添加GridViewColumn对象来定义列。
Head属性提供放在列顶部的文本,DisplayMemberBinding设置每个数据项要显示的信息。
- 改变列的尺寸,可以设置固定宽度,但是会出现过长的数据被截断。没有MaxWidth和MinWidth属性。如果希望完全禁止改变列的尺寸,唯一办法就是为标题提供新模板
- 单元格模板,为了显示数据,可以使用更高级的方式,为每个列设置CellTemplate属性(使用数据模板)
- 自定义列标题,如果希望用自己的内容填充列标题,但又不希望单独给每列指定内容,可以使用GridViewColumn.HeaderTemplate属性定一个数据模板,这个数据模板可以绑定到Header属性中指定内容。如果希望重新定义指定列的标题,可以使用GridViewColumn.HeaderContainerStyle属性提供样式。如果希望以相同的方式重新定义所有列的标题,就需要使用GridView.ColumnHeaderContainerStyle属性。可以使用GridViewColumn.HeaderTemplate和GridView.ColumnHeaderTemplate改变指定列和所有列的外观。
自定义ListView的样式
可以通过改变ListView的样式来实现自定义的样式和模板
TreeView控件
TreeView是层次化容器,这意味着可创建多层数据展示。例如,可创建在第一级中显示类别组,并在每个类别节点中显示相关产品的TreeView控件。
TreeView控件本质上时驻留TreeViewItem对象的特殊ItemsControl控件。每个TreeViewItem对象都是单独的ItemsControl控件,所以可以嵌套的包含更多的TreeViewItem对象。
数据绑定
我们可以通过下面的数据源进行绑定到TreeView的ItemsSrouce。通过创建属性提供另一个集合的集合,是实现数据绑定导航父子关系的诀窍。
public class TreeItem : BindableBase
{
public TreeItem(object Item)
{
this.Item = Item;
}
//父
public TreeItem Parent { get => _parent; set => SetProperty(ref _parent, value); }
private TreeItem _parent;
//子
public ObservableCollection Children { get; set; } = new ObservableCollection();
//级别
public int IndexLevel { get; set; }
//节点的数据
public object Item { get => _item; set => SetProperty(ref _item, value); }
private object _item;
//节点图标路径
public string ItemIcon { get; set; }
//是否展开
public bool IsExpanded { get => _isExpanded; set => SetProperty(ref _isExpanded, value); }
private bool _isExpanded;
//CheckBox是否选中
public bool? IsChecked { get => _isChecked; set => SetIsChecked(value, true, true); }
private bool? _isChecked;
private void SetIsChecked(bool? value, bool checkedChildren, bool checkedParent)
{
if (_isChecked == value) return;
_isChecked = value;
//选中和取消子类
if (checkedChildren && value.HasValue && Children != null)
Children.ToList().ForEach(ch => ch.SetIsChecked(value, true, false));
//选中和取消父类
if (checkedParent && this.Parent != null)
this.Parent.CheckParentCheckState();
//通知更改
this.SetProperty(ref _isChecked, value);
}
//检查父类是否选中(如果父类的子类中有一个和第一个子类的状态不一样父类ischecked为null)
private void CheckParentCheckState()
{
bool? _currentState = this.IsChecked;
bool? _firstState = null;
for (int i = 0; i < this.Children.Count(); i++)
{
bool? childrenState = this.Children[i].IsChecked;
if (i == 0)
{
_firstState = childrenState;
}
else if (_firstState != childrenState)
{
_firstState = null;
}
}
if (_firstState != null) _currentState = _firstState;
SetIsChecked(_firstState, false, true);
}
//选中的行 IsSelected
public bool? IsSelected
{
get => _isSelected;
set
{
_isSelected = value;
this.SetProperty(ref _isSelected, value);
if (value.HasValue && value.Value)
{
SelectedTreeItem = this;
//MessageBox.Show("选中的是" + SelectedTreeItem.Name);
}
else
SelectedTreeItem = null;
}
}
private bool? _isSelected;
//选中的数据
public TreeItem SelectedTreeItem { get; set; }
//创建树
public void CreateTreeWithChildren(TreeItem children, bool? isChecked = null)
{
this.Children.Add(children);
children.Parent = this;
children.IsChecked = isChecked;
}
}
TreeViewItem类继承自HeaderedItemsControl类,添加了Header属性,该属性包含了希望为树中每个项显示的内容(通常是文本)。如果显示非文本内容,最好使用TreeViewItem封装器,并通过TreeViewItem.Header属性提供内容,如果显示非UIElement对象,也可以通过HeaderTemplate属性的数据模板设置格式。
上述代码中,通过HierarchicalDataTemplate来设置TreeView.ItemTemplate属性,而不是DataTemplate对象。前者能够封装第二个模板,然后HierarchicalDataTemplate就可以从第一层数据中提起项的集合,提供给第二层的模板:
更复杂一点的就是:
实际上,上述代码有两个模板,每个模板用于书控件中的每个层次。第二个模板使用从第一个模板中选择的项作为其数据源。
自定义控件的样式和模板:
DataGrid控件
DataGrid是最完备的数据显示工具。他将数据分割到包含行列的网格中,就想ListView控件,但是DataGrid控件具有其他格式化特性(如:冻结列、设置单行样式),并且支持就地编辑数据。DataGrid控件从对象集合获取信息并在具有行和单元格的网络中显示信息。每行和单独的对象相对应,并且每列和对象的某个属性相对应。其选择模型允许选择一行、多行或者一些单元格的组合。
为创建暂时应急的DataGrid控件,可使用自动列生成功能:
AutoGenerateColumns=true
DataGrid的基本显示属性:
名称 | 说明 |
---|---|
RowBackground AlternatingRowBackground |
用于绘制每行北京的画刷,并且决定是否使用不同的背景颜色绘制交替行,从而更容易区分行 |
ColumnHeaderHeight | 位于DataGrid控件顶部的列标题行的高度 |
RowHeaderWidth | 具有行题头的列的宽度。该列在网格的最左边,不显示任何数据。该列使用箭头指示当前选择的行,使用圈住的箭头指示正在编辑的行 |
ColumnWidth | DataGridLength对象,用于设置每列默认宽度的尺寸改变模式 |
RowHeight | 每行的高度。如果准备在DataGrid控件中显示多行文本或者不同的内容(图像等),该设置很有用。与列不同,用户不能改变行的尺寸 |
GridLinesVisibility | 确定是否显示网格线的DataGridGridLines枚举值 |
VerticalGridLinesBrush | 用于绘制列之间网格线的画刷 |
HorizontalGridLinesBrush | 用于绘制行之间网格线的画刷 |
HeadersVisibity | 确定显示哪个题头的DataGrisHeaders枚举值 |
HorizontalScrollBarVisibility VerticalScrollBarVisibility |
去顶是否显示滚动条的枚举值。默认是Auto(当需要时显示) |
改变列的尺寸与重新安排列
当显示自动生成的列时,DataGrid控件尝试根据DataGrid.ColumnWidth属性智能地改变每列的宽度。
为设置ColumnWidth属性,需要提供DataGridLength对象。DataGridLength对象能够指定确切的尺寸或者指定特定的尺寸改变模式,从而让DataGrid控件自动完成。
grid.ColumnWidth=new DataGridLength(150);
使用足够的列宽来适应他们的题头文本:
grid.ColumnWidth=DataGridLength.SizeToHeader;
加宽每一列以适应当前视图中最宽的值:
grid.ColumnWidth=DataGridLength.SizeToCells;
加宽每一列以适应最大的显示值或者题头文本,使用其中的最大值:
grid.ColumnWidth=DataGridLength.Auto;
通常,用户能够通过将列边缘拖动到任意位置来改变列的尺寸。可通过将CanUserResizeColumns属性设置为false来阻止这一行为。也可以将列的CanUserResize属性设置为false,阻止用户改变特定列的尺寸。通过CanUserReorderColumns属性或者特定列的CanUserReorder属性设置为false来阻止用户改变列的位置。
定义列
将AutoGenerateColumns属性设置为false以关闭自动列生成功能。然后可以使用希望的设置和指定的顺序,明确地定义希望使用的列。使用合适的列对象来填充DataGrid.Columns集合。
- DataGridTextColumn:这种列对于大部分数据类型时标准选择,值转换成文本
- DataGridCheckBoxColumn:列显示复选框。通常是只读的,当编辑行时,会成为普通的复选框
- DataGridHyperlinkColumn:显示单击的链接
- DataGridComboBox:这种列最初和DataGridTextColumn类似,在编辑模式下,就编程可以下拉的ComboBox控件
- DataGridTemplateColumn:这种列允许显示值定义数据模板。
设置列的格式和样式
可使用设置TextBlock格式相同的方式设置DataGridTextColumn格式,但是无法设置多行显示,需要使用ElementStyle属性了设置,使用具有多行显示的TextBlock样式即可。
属性 | 说明 |
---|---|
ColumnHeaderStyle | 位于网格顶部的列题头的TextBlock |
RowHeaderStyle | 行题头的TextBlock。一般用复选框做控件模板 |
DragIndicatorStyle | 当用户正在将列题头拖动到新位置时用于列题头的TextBlock |
RowStyle | 用于普通行的TextBlock(没有通过列的ElementStyle属性明确定制过的行) |
设置行的格式
DataGrid.LoadingRow事件:当每一行出现在屏幕上时,都会触发LoadingRow事件。当用户在网格中滚动是,会连续触发事件,所以不能在事件中进行耗时的处理。
显示行细节
DataGrid支持行细节(row details),一块可选的独立显示区域,在行的列值下面显示。
- 能够跨越DataGrid控件的整个宽度,并且不会切入到独立的列中,从而提供了更过可供使用的空间
- 可配置行细节区域,从而只为选择的行显示该区域,当不需要时,允许用户折叠额外的细节
可以通过设置属性DataGrid.RowDetailsTemplate属性,来定义行细节区域显示的内容。
可以通过设置DataGrid.0RowDetailsVisibilityMode属性来设置行细节区域的显示行为,默认是VisibleWhenSelected。
冻结列
冻结列位于DataGrid 控件的左边,甚至当向右滚动时,冻结列任然在左边。对于非常宽的网格,冻结列非常的有用,可以保持某些信息始终可见。通过属性FrozenColumnCount属性设置大于0的数。
冻结列必须总是位于网格的左侧,如果是1列,则就是最左边的那列,如果是2列,那就是最左边的两列。
选择
和普通的列表控件类似,DataGrid允许用户选择单个项,并且响应SelectionChanged事件。可以使用SelectedItem属性来找到当前选中的项。可以通过SelectionMode属性来设置单选还是多选。为了选择多行,用户必须按下Shift或者Ctrl键。通常我们可以在RowHeader中放置CheckBox来显示哪行被选中,也可以通过CheckBox直接选中某行或者多行。
排序
可以通过单击列题头来实现列的排序,可以通过设置SortMemberPath属性从绑定的数据对象中选择不同的属性来排序。可以通过CanUserSortColumns属性或者特定列的CanUserSort属性设置为false来禁止排序功能
编辑
一般情况下,DataGrid多数用于数据展示,编辑的话比较少用,可以通过属性DataGrid.IsReadOnly或者DataGridColumn.IsReadOnly属性设置为false来禁用编辑功能。
列举一个DataGrid的样式: