WPF进阶技巧和实战03-控件(5-列表、树、网格04)

系列文章链接

  • 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的样式:


    
            
        
        
        
        
        
        
        
        
        
            
                
                    
                        
                            
                        
                    
                
            
        
        
            
                
                    
                    
                
                
                
            
            
                
                    
                    
                    
                
                
                
            
            
                
                    
                    
                    
                
                
            
            
                
                    
                    
                
                
            
            
                
                    
                    
                
                
                
            
        
    
    
    
    
    
    
    
    

你可能感兴趣的:(WPF进阶技巧和实战03-控件(5-列表、树、网格04))