一、集合控件概述
很多时候,我们需要显示大量的数据,这些数据虽然众多,但是数据类型结构相同的,由于内容控件只能显示单个元素,要显示或操作多个元素组成的集合,那么,集合控件就派上用场了。WPF中的集合控件种类丰富,有类似表格的DataGrid,有单列表的ListBox,也有介于两者之前的ListView,还有,软件的菜单通常也是一个集合控件,以及软件下方的状态栏,同样也是一个集合控件。
这些集合控件都有一个共同的基类控件,那就是ItemsControl类,下面我们以表格的形式展示一下即将要学习的集合控件。
控件名 | 说明 |
ItemsControl | 集合控件的基类,本身也是一个可以实例化的控件 |
ListBox | 一个列表集合控件 |
ListView | 表示用于显示数据项列表的控件,它可以有列头标题 |
DataGrid | 表示可自定义的网格中显示数据的控件。 |
ComboBox | 表示带有下拉列表的选择控件,通过单击控件上的箭头可显示或隐藏下拉列表。 |
TabControl | 表示包含多个共享相同的空间在屏幕上的项的控件。 |
TreeView | 用树结构(其中的项可以展开和折叠)中显示分层数据的控件 |
Menu | 表示一个 Windows 菜单控件,该控件可用于按层次组织与命令和事件处理程序关联的元素。 |
ContextMenu | 表示使控件能够公开特定于控件的上下文的功能的弹出菜单。 |
StatusBar | 表示应用程序窗口中的水平栏中显示项和信息的控件。 |
二、ItemsControl类定义
public class ItemsControl : Control, IAddChild, IGeneratorHost, IContainItemStorage
{
public static readonly DependencyProperty ItemsSourceProperty;
public static readonly DependencyProperty HasItemsProperty;
public static readonly DependencyProperty DisplayMemberPathProperty;
public static readonly DependencyProperty ItemTemplateProperty;
public static readonly DependencyProperty ItemTemplateSelectorProperty;
public static readonly DependencyProperty ItemStringFormatProperty;
public static readonly DependencyProperty ItemBindingGroupProperty;
public static readonly DependencyProperty ItemContainerStyleProperty;
public static readonly DependencyProperty ItemContainerStyleSelectorProperty;
public static readonly DependencyProperty ItemsPanelProperty;
public static readonly DependencyProperty IsGroupingProperty;
public static readonly DependencyProperty GroupStyleSelectorProperty;
public static readonly DependencyProperty AlternationCountProperty;
public static readonly DependencyProperty AlternationIndexProperty;
public static readonly DependencyProperty IsTextSearchEnabledProperty;
public static readonly DependencyProperty IsTextSearchCaseSensitiveProperty;
public ItemsControl();
public int AlternationCount { get; set; }
public GroupStyleSelector GroupStyleSelector { get; set; }
public ObservableCollection<GroupStyle> GroupStyle { get; }
public bool IsGrouping { get; }
public ItemsPanelTemplate ItemsPanel { get; set; }
public StyleSelector ItemContainerStyleSelector { get; set; }
public Style ItemContainerStyle { get; set; }
public BindingGroup ItemBindingGroup { get; set; }
public string ItemStringFormat { get; set; }
public DataTemplateSelector ItemTemplateSelector { get; set; }
public DataTemplate ItemTemplate { get; set; }
public string DisplayMemberPath { get; set; }
public bool HasItems { get; }
public ItemContainerGenerator ItemContainerGenerator { get; }
public IEnumerable ItemsSource { get; set; }
public ItemCollection Items { get; }
public bool IsTextSearchCaseSensitive { get; set; }
public bool IsTextSearchEnabled { get; set; }
protected internal override IEnumerator LogicalChildren { get; }
public static DependencyObject ContainerFromElement(ItemsControl itemsControl, DependencyObject element);
public static int GetAlternationIndex(DependencyObject element);
public static ItemsControl GetItemsOwner(DependencyObject element);
public static ItemsControl ItemsControlFromItemContainer(DependencyObject container);
public override void BeginInit();
public DependencyObject ContainerFromElement(DependencyObject element);
public override void EndInit();
public bool IsItemItsOwnContainer(object item);
public bool ShouldSerializeGroupStyle();
public bool ShouldSerializeItems();
public override string ToString();
protected virtual void AddChild(object value);
protected virtual void AddText(string text);
protected virtual void ClearContainerForItemOverride(DependencyObject element, object item);
protected virtual DependencyObject GetContainerForItemOverride();
protected virtual bool IsItemItsOwnContainerOverride(object item);
protected virtual void OnAlternationCountChanged(int oldAlternationCount, int newAlternationCount);
protected virtual void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath);
protected virtual void OnGroupStyleSelectorChanged(GroupStyleSelector oldGroupStyleSelector, GroupStyleSelector newGroupStyleSelector);
protected virtual void OnItemBindingGroupChanged(BindingGroup oldItemBindingGroup, BindingGroup newItemBindingGroup);
protected virtual void OnItemContainerStyleChanged(Style oldItemContainerStyle, Style newItemContainerStyle);
protected virtual void OnItemContainerStyleSelectorChanged(StyleSelector oldItemContainerStyleSelector, StyleSelector newItemContainerStyleSelector);
protected virtual void OnItemsChanged(NotifyCollectionChangedEventArgs e);
protected virtual void OnItemsPanelChanged(ItemsPanelTemplate oldItemsPanel, ItemsPanelTemplate newItemsPanel);
protected virtual void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue);
protected virtual void OnItemStringFormatChanged(string oldItemStringFormat, string newItemStringFormat);
protected virtual void OnItemTemplateChanged(DataTemplate oldItemTemplate, DataTemplate newItemTemplate);
protected virtual void OnItemTemplateSelectorChanged(DataTemplateSelector oldItemTemplateSelector, DataTemplateSelector newItemTemplateSelector);
protected override void OnKeyDown(KeyEventArgs e);
protected override void OnTextInput(TextCompositionEventArgs e);
protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item);
protected virtual bool ShouldApplyItemContainerStyle(DependencyObject container, object item);
}
二、ItemsControl类分析
由于我们还没有讲模板、样式、数据绑定等内容,所以关于ItemsControl类的分析,我们先关注一些与模板样式和数据绑定无关的内容,先讲讲ItemsControl最基础的内容。
2.Items属性
ItemsControl类作为集合控件的基类,它提供了一个非常重要的属性,那就是Items属性。这个属性的类型是ItemCollection,也就是一个集合列表,那么这个列表的元素内容是什么呢?
答案是object。
说明我们可以在集合控件中放任意引用类型的元素。
2.2DisplayMemberPath属性
这个属性用来获取或设置要显示的内容,它通常指某个数据源的某个属性名称,所以它是string类型。
2.3HasItems属性
这个属性用来判断当前集合控件是否有元素。
24.IsTextSearchCaseSensitive属性
这个属性如果为true,则搜索元素时区分大小写。
2.5 IsTextSearchEnabled属性
表示是否启用文字搜索。
好,接下来的几个属性将在后续进行学习,不过,我们先在这里了解一下它们的用途。
2.6 ItemsPanel属性[重要]
由于一个集合控件里面会显示多个数据项(一个数据代表一个家),那么这些数据项怎么排版?是像StackPanel一样水平或垂直排列,还是像WrapPanel瀑布流一样排例?这个ItemsPanel属性来决定。
2.7 ItemTemplate属性[重要]
在集合控件里,数据项有可能是一个复杂的实体,那么这些数据以什么样的UI布局界面呈现?也就是说,数据本身穿什么衣服?ItemTemplate属性就是来决定数据的外观的。如果把每个Item元素看成一个家,那么前面的ItemsPanel属性就是来决定邻里之间的实际距离以及房子和房子的排例走势。
2.8 ItemContainerStyle属性[重要]
ItemTemplate属性只能决定数据的外观,相当于这个家的内部装修以及家电家具的样式,而这个家外墙的装饰,则必须由ItemContainerStyle属性来承包。
2.9 ItemContainerStyleSelector属性[重要]
当我们选中这个集合控件中的某一项,并希望突出这一项,那就可以在ItemTemplateSelector属性中进行定义,也就是说,选择了某一项,某一项的外墙装饰发生改变。那同时要改变内部的样式呢?
2.10 ItemTemplateSelector属性[重要]
如果选中了某一项,并希望它的数据模块被重新定义,以突出这一项被选中,可以设置ItemTemplateSelector属性
2.11 Template属性[重要]
还记得吗?ItemsControl类继承于Control类,而Control类中有一个叫Template的属性,所以ItemsControl类自然也就拥有了这个属性,这是一个什么属性?它是ControlTemplate类,也就是控件模板,所以,如果我们希望把ItemsControl类本身的外观进行重定义,那就需要去设置Template属性
重庆教主友情提示
上面我们一口气讲了这么多的模板概念,虽然看起来是在学习ItemsControl类的属性,但是别忘记了,将来要学习的那些集合子控件全都继承于ItemsControl类,意味着它们也都有这些模板属性可以使用呢,是不是有一种事半功倍的感觉呢!
接下来,我们来举个例子
三、ItemsControl示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<ItemsControl>
<Button Content="content" Margin="0,5"/>
<Border Height="30" Background="LightPink" Margin="0,5"/>
<TextBlock Text="WPF中文网 www.wpfsoft.com" Background="LightGray" Margin="0,5"/>
<ItemsControl Height="35" Background="AliceBlue"/>
<CheckBox Content="CheckBox元素"/>
<StackPanel Orientation="Horizontal" Margin="0,5">
<RadioButton Content="初级"/>
<RadioButton Content="中级"/>
<RadioButton Content="高级"/>
</StackPanel>
这是一串字符串
<Label Content="这是Label控件" Margin="0,5"/>
<Control Background="Red" Height="30"/>
<ProgressBar Value="50" Height="20" Maximum="100" />
</ItemsControl>
</Grid>
</Window>
首先,我们在XMAL中实例化了一个ItemsControl控件,然后在ItemsControl里面实例化了一系列子控件,它们分别是Button、Border、TextBlock、ItemsControl、CheckBox、StackPanel、RadioButton、字符串、Label、Control和ProgressBar。
除了Control没有显示出来,其它全部都呈现在ItemsControl控件之中,因为这些子控件全部都在ItemsControl类的Items集合里面,那么,Control虽然能实例化,为什么没有显示出来呢?就连没有控件的字符串都能显示出来,这里面肯定有原因。
是的,这里我们引出一个知识点,那就是控件模板,因为Control基类虽然有Background属性,但是我们并没有给Control基类的Template属性设置一个控件模板,所以Control能实例化,但是不能显示。只能看到一个高度为30的空白区域。
而Border在设置Background属性后,为什么能显示?因为Border是一个装饰器,它继承于Decorator基类。
为什么单纯的字符串也能显示呢?因为实际上这个字符串外面被包裹了一层ContentPresenter实例,这个字符串是被赋值到了ContentPresenter的Content属性上,而ContentPresenter的ContentTemplate有一个默认模板。
四、总结
ItemsControl集合基类可以显示绝大多数控件,也就意味着,ListBox,ListView,DataGrid,ComboBox,TabControl,TreeView,Menu,ContextMenu,StatusBar这些子控件在显示集合元素时,每一个元素的外观可以呈现出更复杂、更漂亮的UI效果,从而可以设计出更友好的交互界面。
有了这样一个基调,那接下来我们来一一细说各个子控件的基础功能,待学习模板和样式章节后,进一步探索这些子控件的强大功能。另外,ListBox,ListView,DataGrid,ComboBox,TabControl这5个控件又都有一个共同的基类——Selector类,Selector继承于ItemsControl基类。Selector基类又是一个怎样的类?它会给我们提供哪些功能呢?
下一节,我们先从Selector基类说起。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:038-《ItemsControl集合控件基类》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月1日
Selector继承于ItemsControl,但它是一个抽象类,所以不能被实例化。从命名上看,它是一个选择器。
一、Selector类定义
public abstract class Selector : ItemsControl
{
public static readonly RoutedEvent SelectionChangedEvent;
public static readonly RoutedEvent SelectedEvent;
public static readonly RoutedEvent UnselectedEvent;
public static readonly DependencyProperty IsSelectionActiveProperty;
public static readonly DependencyProperty IsSelectedProperty;
public static readonly DependencyProperty IsSynchronizedWithCurrentItemProperty;
public static readonly DependencyProperty SelectedIndexProperty;
public static readonly DependencyProperty SelectedItemProperty;
public static readonly DependencyProperty SelectedValueProperty;
public static readonly DependencyProperty SelectedValuePathProperty;
protected Selector();
public object SelectedValue { get; set; }
public object SelectedItem { get; set; }
public int SelectedIndex { get; set; }
public bool? IsSynchronizedWithCurrentItem { get; set; }
public string SelectedValuePath { get; set; }
public event SelectionChangedEventHandler SelectionChanged;
public static void AddSelectedHandler(DependencyObject element, RoutedEventHandler handler);
public static void AddUnselectedHandler(DependencyObject element, RoutedEventHandler handler);
public static bool GetIsSelected(DependencyObject element);
public static bool GetIsSelectionActive(DependencyObject element);
public static void RemoveSelectedHandler(DependencyObject element, RoutedEventHandler handler);
public static void RemoveUnselectedHandler(DependencyObject element, RoutedEventHandler handler);
public static void SetIsSelected(DependencyObject element, bool isSelected);
protected override void ClearContainerForItemOverride(DependencyObject element, object item);
protected override void OnInitialized(EventArgs e);
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e);
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e);
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue);
protected virtual void OnSelectionChanged(SelectionChangedEventArgs e);
protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
}
接下来,我们来看看它提供了哪些可用的属性。
二、Selector类的属性
属性名称 | 说明 |
SelectedValue | 获取或设置SelectedValuePath属性指定的元素的属性值 |
SelectedItem | 获取或设置当前所选内容中的第一项或如果所选内容为空则返回 null |
SelectedIndex | 获取或设置当前所选内容或返回的第一项的索引为负一 (-1) 如果所选内容为空。 |
SelectedValuePath | 获取或设置SelectedItem当前元素的某个属性名,这个元素属性名将决定SelectedValue的值 |
IsSynchronizedWithCurrentItem | 是否同步当前项。 |
SelectedItem和SelectedValue有点类似,都是object类型。但是,他们俩不一定指同一个内容。比如,我们将有这样一个数据实体类。
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
}
然后我们实例化多个Person组成一个集合绑定到Items属性中,这个时候选中某一个元素,SelectedItem便等于这个Person元素,但是SelectedValue是什么,要看SelectedValuePath的值,如果SelectedValuePath的值指向的是Person.Name,那么SelectedValue就是一个字符串,如果SelectedValuePath指向的是Person的Age ,那么SelectedValue就是一个int整数,只有不设置SelectedValuePath时,SelectedValue和SelectedItem两者才相等,即Person实例。
具体关于这一个重点,我们在下一节讨论ListBox控件时进行演示和讲解。
重庆教主说:
SelectedItem、SelectedValue、SelectedValuePath非常重要,一定要理解透彻哦!另外,还有一个属性叫DisplayMemberPath,它在ItemsControl基类中,意思是设置要显示的属性名,而SelectedValuePath是设置要选择的属性名。
——重庆教主 2023年9月1日
ListBox是一个列表控件,用于显示条目类的数据,默认每行只能显示一个内容项,当然,我们可以通过修改它的数据模板,来自定义每一行(元素)的数据外观,达到显示更多数据的目的。
一、ListBox的定义
public class ListBox : Selector
{
public static readonly DependencyProperty SelectionModeProperty;
public static readonly DependencyProperty SelectedItemsProperty;
public ListBox();
public IList SelectedItems { get; }
public SelectionMode SelectionMode { get; set; }
protected object AnchorItem { get; set; }
protected internal override bool HandlesScrolling { get; }
public void ScrollIntoView(object item);
public void SelectAll();
public void UnselectAll();
protected override DependencyObject GetContainerForItemOverride();
protected override bool IsItemItsOwnContainerOverride(object item);
protected override AutomationPeer OnCreateAutomationPeer();
protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e);
protected override void OnKeyDown(KeyEventArgs e);
protected override void OnMouseMove(MouseEventArgs e);
protected override void OnSelectionChanged(SelectionChangedEventArgs e);
protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
protected bool SetSelectedItems(IEnumerable selectedItems);
}
二、属性分析
ListBox自身的属性比较少,SelectionMode 属性比较重要,它可以决定当前的ListBox控件是单选还是多选,它的值为Extended时,表示用户需要按下shift键才能多选。如果SelectionMode为多选状态,那么多选的结果保存在哪去了?
答案是SelectedItems 属性。
另外,ListBox还自带了滚动条,如果内容超出显示区域,这时滚动条便起作用。
我们在上一章节提过DisplayMemberPath、SelectedValuePath、SelectedItem和SelectedValue,那么,我们以一个实际的例子来说明这几个属性的用途。
三、ListBox示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<StackPanel>
<ListBox x:Name="listbox" MinHeight="100"
DisplayMemberPath="Name"
SelectedValuePath="Age"/>
<Button Content="查看结果" Click="Button_Click"/>
<TextBlock x:Name="_TextBlock"/>
</StackPanel>
</Window>
后端代码
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace HelloWorld
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
listbox.Items.Add(new Person { Name = "张三", Age = 22, Address = "广东省廉江市车板镇大坝村" });
listbox.Items.Add(new Person { Name = "李四", Age = 23, Address = "江西省景德镇市市辖区" });
listbox.Items.Add(new Person { Name = "王五", Age = 24, Address = "上海市虹口区" });
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var selectedItem = listbox.SelectedItem;
var selectedValue = listbox.SelectedValue;
_TextBlock.Text = $"{selectedItem},{selectedValue}";
}
}
}
代码分析
在前端代码中,我们设置了DisplayMemberPath属性值为“Name”,而SelectedValuePath属性值为“Age",这两个值实际上是Person类的两个属性,F5启动调试后,我们可以在界面上看到张三、李四和王五的名字,但是看不到他们的年龄和地址,这是因为ListBox默认每行只能显示一个内容项,而且这里我们设置了DisplayMemberPath属性,只能显示名字。
我们选中ListBox中的李四,然后单点查看结果按钮,SelectedItem属性得到了一个Person类,所以输出的值为HelloWorld.Person,而SelectedValue属性得到了李四的年龄,所以输出的结果是23。
重庆教主说
如果把SelectionMode属性设为多选Multiple或Extended,试试看,会发生什么效果呢?
Items属性是一个只读属性,所以我们只能能过Items的Add方法向集合增加元素。
四、ListBoxItem子项
其实,ListBox还有它专门配合业务开发的子项控件——ListBoxItem。ListBoxItem继承于ContentControl内容控件,仔细想,这意味着什么?还记得我们在分享ContentControl提过”它有一个叫Content属性“一嘴吗?Content属性可以容纳任意引用类型,也就是说,ListBoxItem也可以容纳任意引用类型,也就是说,ListBox的子项也可以容纳任意的引用类型。
这么一说,感觉ListBoxr还蛮强大的呢!
所以,ListBoxItem可以这样使用
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<StackPanel>
<ListBox x:Name="listbox">
<ListBoxItem>
<Button Content="这是一个按钮"/>
</ListBoxItem>
<ListBoxItem>
<Border Height="30" Background="Red"/>
</ListBoxItem>
<ListBoxItem Content="这是一个字符串"/>
<ListBoxItem>
<ProgressBar Maximum="100" Value="50" Height="25" Width="450"/>
</ListBoxItem>
这里直接写字符串
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<CheckBox Content="复选框"/>
<RadioButton Content="单选框 "/>
</StackPanel>
</ListBoxItem>
</ListBox>
<Button Content="查看结果" Click="Button_Click"/>
<TextBlock x:Name="textblock" TextWrapping="Wrap"/>
</StackPanel>
</Window>
后台代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
var selectedItem = listbox.SelectedItem;
var content = ((ContentControl)selectedItem).Content;
textblock.Text = $"selectedItem={selectedItem}\r\ncontent={content}";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
如上所示,我们在ListBoxj控件里面实例化了好几个ListBoxItem,但是每个ListBoxItem的Content属性都不一样,有Button,Border ,ProgressBar ,字符串,最后,我们来获取这些选中项的内容。
除了直接写的字符串不能转换之外,其它项的结果,SelectedItem属性总是ListBoxItem,而Content可以是我们设置的其它控制。
要全面了解ListBoxItem,不能不看看它的定义。
public class ListBoxItem : ContentControl
{
public static readonly DependencyProperty IsSelectedProperty;
public static readonly RoutedEvent SelectedEvent;
public static readonly RoutedEvent UnselectedEvent;
public ListBoxItem();
public bool IsSelected { get; set; }
public event RoutedEventHandler Selected;
public event RoutedEventHandler Unselected;
protected override AutomationPeer OnCreateAutomationPeer();
protected override void OnMouseEnter(MouseEventArgs e);
protected override void OnMouseLeave(MouseEventArgs e);
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e);
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e);
protected virtual void OnSelected(RoutedEventArgs e);
protected virtual void OnUnselected(RoutedEventArgs e);
protected internal override void OnVisualParentChanged(DependencyObject oldParent);
}
如上所示,可以看到ListBoxItem有一个叫IsSelected属性,表示该项是否被选中,同时,它还有两个事件,分别是Selected选中和Unselected未选中,我们可以去订阅这两个事件,以此来做一些业务。
关于ListBox以及ListBoxItem,我们就先介绍这么多,实际上它的用法远不止这些,如果加上模板、样式、数据绑定、触发器,它还可以实现许多意想不到的效果。关于这部分的内容,请参阅模板样式章节关于ListBox控件的用法。
所以,ListBox列表控件默认情况下,只能显示一个数据项,那如果我想把Person类的Name、Age、Address三个属性值都显示出来呢?有办法——ListView控件可以做到。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:039-《ListBox列表控件》-源代码-1,039-《ListBox列表控件》-源代码-2
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月1日
ListView继承于ListBox,在ListBox控件的基础上增加了数据视图。从而让我们可以很轻松的设置每一列的标题,以显示某个数据表结构及内容。
一、ListView定义
public class ListView : ListBox
{
public static readonly DependencyProperty ViewProperty;
public ListView();
public ViewBase View { get; set; }
protected override void ClearContainerForItemOverride(DependencyObject element, object item);
protected override DependencyObject GetContainerForItemOverride();
protected override bool IsItemItsOwnContainerOverride(object item);
protected override AutomationPeer OnCreateAutomationPeer();
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e);
protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
}
ListView类增加了一个叫View的属性,这个属性用来定义控件的数据样式,决定数据怎样显示。View属性的类型是ViewBase,但是,我们真正在使用View属性时,实际上实例化的是GridView类,因为GridView类是ViewBase的子类。所以,我们要看了解一下GridView的定义。
public class GridView : ViewBase, IAddChild
{
public static readonly DependencyProperty ColumnCollectionProperty;
public static readonly DependencyProperty ColumnHeaderContainerStyleProperty;
public static readonly DependencyProperty ColumnHeaderTemplateProperty;
public static readonly DependencyProperty ColumnHeaderTemplateSelectorProperty;
public static readonly DependencyProperty ColumnHeaderStringFormatProperty;
public static readonly DependencyProperty AllowsColumnReorderProperty;
public static readonly DependencyProperty ColumnHeaderContextMenuProperty;
public static readonly DependencyProperty ColumnHeaderToolTipProperty;
public GridView();
public static ResourceKey GridViewItemContainerStyleKey { get; }
public static ResourceKey GridViewStyleKey { get; }
public static ResourceKey GridViewScrollViewerStyleKey { get; }
public string ColumnHeaderStringFormat { get; set; }
public DataTemplateSelector ColumnHeaderTemplateSelector { get; set; }
public DataTemplate ColumnHeaderTemplate { get; set; }
public Style ColumnHeaderContainerStyle { get; set; }
public GridViewColumnCollection Columns { get; }
public object ColumnHeaderToolTip { get; set; }
public bool AllowsColumnReorder { get; set; }
public ContextMenu ColumnHeaderContextMenu { get; set; }
protected internal override object ItemContainerDefaultStyleKey { get; }
protected internal override object DefaultStyleKey { get; }
public static GridViewColumnCollection GetColumnCollection(DependencyObject element);
public static void SetColumnCollection(DependencyObject element, GridViewColumnCollection collection);
public static bool ShouldSerializeColumnCollection(DependencyObject obj);
public override string ToString();
protected virtual void AddChild(object column);
protected virtual void AddText(string text);
protected internal override void ClearItem(ListViewItem item);
protected internal override IViewAutomationPeer GetAutomationPeer(ListView parent);
protected internal override void PrepareItem(ListViewItem item);
}
GridView提供了一些可供设置的模板和样式属性,这些我们先放一边,在WPF基础章节的内容学习中,我们先学习它的Columns 属性,它是一个集合属性,而集合中元素的类型是GridViewColumn。
GridViewColumn最关键的只有两个属性,分别是标题和要显示的成员(指向了Person实体的某个属性名)。
好了,我们以上一节中的Person实体为例。
二、ListView示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<ListView Grid.Column="0" x:Name="listview" SelectionChanged="listview_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="年龄" DisplayMemberBinding="{Binding Age}"/>
<GridViewColumn Header="地址" DisplayMemberBinding="{Binding Address}"/>
</GridView>
</ListView.View>
</ListView>
<StackPanel Grid.Column="1">
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="姓名:"/>
<TextBlock x:Name="_TextBlockName"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="年龄:"/>
<TextBlock x:Name="_TextBlockAge"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="地址:"/>
<TextBlock x:Name="_TextBlockAddress"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
后端代码
namespace HelloWorld
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
listview.Items.Add(new Person { Name = "张三", Age = 22, Address = "广东省廉江市车板镇大坝村" });
listview.Items.Add(new Person { Name = "李四", Age = 23, Address = "江西省景德镇市市辖区" });
listview.Items.Add(new Person { Name = "王五", Age = 24, Address = "上海市虹口区" });
}
private void listview_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView listView = sender as ListView;
if (listView == null) return;
var person = listView.SelectedItem as Person;
if (person == null) return;
_TextBlockName.Text = person.Name;
_TextBlockAge.Text = person.Age + "岁";
_TextBlockAddress.Text = person.Address;
}
}
}
三、代码分析
首先,我们在前端实例化了一个ListView控件,并为View属性实例化了一个GridView对象(注意xaml语法的写法),最后为GridView对象实例化了3列GridViewColumn ,分别设置为姓名年龄和地址,特别需要注意的是DisplayMemberBinding属性的写法,这里采用了数据绑定的写法,意思是将ListView控件的数据源的Name属性显示在姓名那一列,Age属性显示在年龄那一列,Address属性显示在地址那一列(我们明确知道ListView数据源的类型就是Person的实例集合)。
事件处理
在ListView控件的SelectionChanged事件中,我们先将sender转成ListView ,再从中获取当前选中项(即person),最后显示详细信息在界面上即可。这样就演示了数据怎么加载显示到ListView,又怎么样从ListView上获取的过程。
而类似于ListView的效果效果,还有一个专门用来显示数据的控件,它叫DataGrid,从某种意义上来说,它甚至可以开发类似Excel表格的效果。不过,我们在下一节,还是以学习它的基础功能先。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:040-《ListView数据列表控件》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月6日
DataGrid是一个可以多选的数据表格控件。所以,它继承一个支持多选的父类——MultiSelector。
public abstract class MultiSelector : Selector
{
protected MultiSelector();
public IList SelectedItems { get; }
protected bool CanSelectMultipleItems { get; set; }
protected bool IsUpdatingSelectedItems { get; }
public void SelectAll();
public void UnselectAll();
protected void BeginUpdateSelectedItems();
protected void EndUpdateSelectedItems();
}
从上面的定义来看,DataGrid多选的结果会保存在SelectedItems 只读属性中,CanSelectMultipleItems 属性用来设置是否开启多选。好,然后我们来看看DataGrid控件的定义,虽然它的属性众多,在学习模板样式之后,我们还会进一步学习这个控件的用法。
一、DataGrid定义
public class DataGrid : MultiSelector
{
public static readonly DependencyProperty CanUserResizeColumnsProperty;
public static readonly DependencyProperty CurrentItemProperty;
public static readonly DependencyProperty CurrentColumnProperty;
public static readonly DependencyProperty CurrentCellProperty;
public static readonly DependencyProperty CanUserAddRowsProperty;
public static readonly DependencyProperty CanUserDeleteRowsProperty;
public static readonly DependencyProperty RowDetailsVisibilityModeProperty;
public static readonly DependencyProperty AreRowDetailsFrozenProperty;
public static readonly DependencyProperty RowDetailsTemplateProperty;
public static readonly DependencyProperty RowDetailsTemplateSelectorProperty;
public static readonly DependencyProperty CanUserResizeRowsProperty;
public static readonly DependencyProperty NewItemMarginProperty;
public static readonly DependencyProperty SelectionModeProperty;
public static readonly DependencyProperty SelectionUnitProperty;
public static readonly DependencyProperty CanUserSortColumnsProperty;
public static readonly DependencyProperty AutoGenerateColumnsProperty;
public static readonly DependencyProperty FrozenColumnCountProperty;
public static readonly DependencyProperty NonFrozenColumnsViewportHorizontalOffsetProperty;
public static readonly DependencyProperty EnableColumnVirtualizationProperty;
public static readonly DependencyProperty CanUserReorderColumnsProperty;
public static readonly DependencyProperty DragIndicatorStyleProperty;
public static readonly DependencyProperty DropLocationIndicatorStyleProperty;
public static readonly DependencyProperty ClipboardCopyModeProperty;
public static readonly DependencyProperty CellsPanelHorizontalOffsetProperty;
public static readonly DependencyProperty IsReadOnlyProperty;
public static readonly RoutedCommand CancelEditCommand;
public static readonly DependencyProperty EnableRowVirtualizationProperty;
public static readonly RoutedCommand BeginEditCommand;
public static readonly RoutedCommand CommitEditCommand;
public static readonly DependencyProperty ColumnWidthProperty;
public static readonly DependencyProperty MinColumnWidthProperty;
public static readonly DependencyProperty MaxColumnWidthProperty;
public static readonly DependencyProperty HorizontalGridLinesBrushProperty;
public static readonly DependencyProperty VerticalGridLinesBrushProperty;
public static readonly DependencyProperty RowStyleProperty;
public static readonly DependencyProperty RowValidationErrorTemplateProperty;
public static readonly DependencyProperty RowStyleSelectorProperty;
public static readonly DependencyProperty RowBackgroundProperty;
public static readonly DependencyProperty AlternatingRowBackgroundProperty;
public static readonly DependencyProperty RowHeightProperty;
public static readonly DependencyProperty GridLinesVisibilityProperty;
public static readonly DependencyProperty RowHeaderWidthProperty;
public static readonly DependencyProperty VerticalScrollBarVisibilityProperty;
public static readonly DependencyProperty MinRowHeightProperty;
public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty;
public static readonly DependencyProperty RowHeaderTemplateProperty;
public static readonly DependencyProperty RowHeaderStyleProperty;
public static readonly DependencyProperty RowHeaderTemplateSelectorProperty;
public static readonly DependencyProperty CellStyleProperty;
public static readonly DependencyProperty HeadersVisibilityProperty;
public static readonly DependencyProperty ColumnHeaderHeightProperty;
public static readonly DependencyProperty RowHeaderActualWidthProperty;
public static readonly DependencyProperty ColumnHeaderStyleProperty;
public DataGrid();
public static ComponentResourceKey FocusBorderBrushKey { get; }
public static RoutedUICommand SelectAllCommand { get; }
public static IValueConverter HeadersVisibilityConverter { get; }
public static IValueConverter RowDetailsScrollingConverter { get; }
public static RoutedUICommand DeleteCommand { get; }
public DataTemplate RowHeaderTemplate { get; set; }
public DataTemplateSelector RowHeaderTemplateSelector { get; set; }
public ScrollBarVisibility VerticalScrollBarVisibility { get; set; }
public ScrollBarVisibility HorizontalScrollBarVisibility { get; set; }
public bool CanUserAddRows { get; set; }
public object CurrentItem { get; set; }
public DataGridColumn CurrentColumn { get; set; }
public DataGridCellInfo CurrentCell { get; set; }
public bool CanUserDeleteRows { get; set; }
public Style RowHeaderStyle { get; set; }
public DataGridRowDetailsVisibilityMode RowDetailsVisibilityMode { get; set; }
public bool IsReadOnly { get; set; }
public Style ColumnHeaderStyle { get; set; }
public Style RowStyle { get; set; }
public DataGridHeadersVisibility HeadersVisibility { get; set; }
public bool AreRowDetailsFrozen { get; set; }
public Brush AlternatingRowBackground { get; set; }
public Brush RowBackground { get; set; }
public StyleSelector RowStyleSelector { get; set; }
public ObservableCollection<ValidationRule> RowValidationRules { get; }
public ControlTemplate RowValidationErrorTemplate { get; set; }
public Brush VerticalGridLinesBrush { get; set; }
public Brush HorizontalGridLinesBrush { get; set; }
public DataGridGridLinesVisibility GridLinesVisibility { get; set; }
public double MaxColumnWidth { get; set; }
public double MinColumnWidth { get; set; }
public DataGridLength ColumnWidth { get; set; }
public bool CanUserResizeColumns { get; set; }
public ObservableCollection<DataGridColumn> Columns { get; }
public double RowHeaderWidth { get; set; }
public double RowHeaderActualWidth { get; }
public double ColumnHeaderHeight { get; set; }
public Style CellStyle { get; set; }
public DataTemplate RowDetailsTemplate { get; set; }
public double MinRowHeight { get; set; }
public bool CanUserResizeRows { get; set; }
public double RowHeight { get; set; }
public DataTemplateSelector RowDetailsTemplateSelector { get; set; }
public double CellsPanelHorizontalOffset { get; }
public DataGridClipboardCopyMode ClipboardCopyMode { get; set; }
public Style DropLocationIndicatorStyle { get; set; }
public bool CanUserReorderColumns { get; set; }
public bool EnableColumnVirtualization { get; set; }
public bool EnableRowVirtualization { get; set; }
public Style DragIndicatorStyle { get; set; }
public double NonFrozenColumnsViewportHorizontalOffset { get; }
public int FrozenColumnCount { get; set; }
public bool AutoGenerateColumns { get; set; }
public Thickness NewItemMargin { get; }
public bool CanUserSortColumns { get; set; }
public DataGridSelectionUnit SelectionUnit { get; set; }
public DataGridSelectionMode SelectionMode { get; set; }
public IList<DataGridCellInfo> SelectedCells { get; }
protected internal override bool HandlesScrolling { get; }
public event DataGridSortingEventHandler Sorting;
public event EventHandler AutoGeneratedColumns;
public event EventHandler<DataGridAutoGeneratingColumnEventArgs> AutoGeneratingColumn;
public event EventHandler<DragDeltaEventArgs> ColumnHeaderDragDelta;
public event EventHandler<DragStartedEventArgs> ColumnHeaderDragStarted;
public event EventHandler<DragCompletedEventArgs> ColumnHeaderDragCompleted;
public event SelectedCellsChangedEventHandler SelectedCellsChanged;
public event EventHandler<DataGridColumnReorderingEventArgs> ColumnReordering;
public event EventHandler<DataGridRowDetailsEventArgs> RowDetailsVisibilityChanged;
public event EventHandler<DataGridRowEventArgs> UnloadingRow;
public event EventHandler<DataGridRowDetailsEventArgs> LoadingRowDetails;
public event InitializingNewItemEventHandler InitializingNewItem;
public event EventHandler<DataGridPreparingCellForEditEventArgs> PreparingCellForEdit;
public event EventHandler<DataGridBeginningEditEventArgs> BeginningEdit;
public event EventHandler<EventArgs> CurrentCellChanged;
public event EventHandler<DataGridCellEditEndingEventArgs> CellEditEnding;
public event EventHandler<DataGridRowEditEndingEventArgs> RowEditEnding;
public event EventHandler<DataGridRowEventArgs> LoadingRow;
public event EventHandler<DataGridColumnEventArgs> ColumnDisplayIndexChanged;
public event EventHandler<DataGridRowDetailsEventArgs> UnloadingRowDetails;
public event EventHandler<AddingNewItemEventArgs> AddingNewItem;
public event EventHandler<DataGridRowClipboardEventArgs> CopyingRowClipboardContent;
public event EventHandler<DataGridColumnEventArgs> ColumnReordered;
public static Collection<DataGridColumn> GenerateColumns(IItemProperties itemProperties);
public bool BeginEdit();
public bool BeginEdit(RoutedEventArgs editingEventArgs);
public bool CancelEdit();
public bool CancelEdit(DataGridEditingUnit editingUnit);
public void ClearDetailsVisibilityForItem(object item);
public DataGridColumn ColumnFromDisplayIndex(int displayIndex);
public bool CommitEdit();
public bool CommitEdit(DataGridEditingUnit editingUnit, bool exitEditingMode);
public Visibility GetDetailsVisibilityForItem(object item);
public override void OnApplyTemplate();
public void ScrollIntoView(object item);
public void ScrollIntoView(object item, DataGridColumn column);
public void SelectAllCells();
public void SetDetailsVisibilityForItem(object item, Visibility detailsVisibility);
public void UnselectAllCells();
protected override void ClearContainerForItemOverride(DependencyObject element, object item);
protected override DependencyObject GetContainerForItemOverride();
protected override bool IsItemItsOwnContainerOverride(object item);
protected override Size MeasureOverride(Size availableSize);
protected virtual void OnAddingNewItem(AddingNewItemEventArgs e);
protected virtual void OnAutoGeneratedColumns(EventArgs e);
protected virtual void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e);
protected virtual void OnBeginningEdit(DataGridBeginningEditEventArgs e);
protected virtual void OnCanExecuteBeginEdit(CanExecuteRoutedEventArgs e);
protected virtual void OnCanExecuteCancelEdit(CanExecuteRoutedEventArgs e);
protected virtual void OnCanExecuteCommitEdit(CanExecuteRoutedEventArgs e);
protected virtual void OnCanExecuteCopy(CanExecuteRoutedEventArgs args);
protected virtual void OnCanExecuteDelete(CanExecuteRoutedEventArgs e);
protected virtual void OnCellEditEnding(DataGridCellEditEndingEventArgs e);
protected override void OnContextMenuOpening(ContextMenuEventArgs e);
protected virtual void OnCopyingRowClipboardContent(DataGridRowClipboardEventArgs args);
protected override AutomationPeer OnCreateAutomationPeer();
protected virtual void OnCurrentCellChanged(EventArgs e);
protected virtual void OnExecutedBeginEdit(ExecutedRoutedEventArgs e);
protected virtual void OnExecutedCancelEdit(ExecutedRoutedEventArgs e);
protected virtual void OnExecutedCommitEdit(ExecutedRoutedEventArgs e);
protected virtual void OnExecutedCopy(ExecutedRoutedEventArgs args);
protected virtual void OnExecutedDelete(ExecutedRoutedEventArgs e);
protected virtual void OnInitializingNewItem(InitializingNewItemEventArgs e);
protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e);
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e);
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue);
protected override void OnKeyDown(KeyEventArgs e);
protected virtual void OnLoadingRow(DataGridRowEventArgs e);
protected virtual void OnLoadingRowDetails(DataGridRowDetailsEventArgs e);
protected override void OnMouseMove(MouseEventArgs e);
protected virtual void OnRowEditEnding(DataGridRowEditEndingEventArgs e);
protected virtual void OnSelectedCellsChanged(SelectedCellsChangedEventArgs e);
protected override void OnSelectionChanged(SelectionChangedEventArgs e);
protected virtual void OnSorting(DataGridSortingEventArgs eventArgs);
protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate);
protected override void OnTextInput(TextCompositionEventArgs e);
protected virtual void OnUnloadingRow(DataGridRowEventArgs e);
protected virtual void OnUnloadingRowDetails(DataGridRowDetailsEventArgs e);
protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
protected internal virtual void OnColumnDisplayIndexChanged(DataGridColumnEventArgs e);
protected internal virtual void OnColumnHeaderDragCompleted(DragCompletedEventArgs e);
protected internal virtual void OnColumnHeaderDragDelta(DragDeltaEventArgs e);
protected internal virtual void OnColumnHeaderDragStarted(DragStartedEventArgs e);
protected internal virtual void OnColumnReordered(DataGridColumnEventArgs e);
protected internal virtual void OnColumnReordering(DataGridColumnReorderingEventArgs e);
protected internal virtual void OnPreparingCellForEdit(DataGridPreparingCellForEditEventArgs e);
protected internal virtual void OnRowDetailsVisibilityChanged(DataGridRowDetailsEventArgs e);
}
二、属性分析
DataGrid提供了大量的依赖属性,合理充分利用这些属性,在开发ERP、CMS、报表等软件时可达到事半功倍的效果。下面我们以表格的形式,先了解一下各属性的功能,然后在本节中学习一些基础属性,以掌握该控件的基本用法,剩下的属性放到模板样式的章节中学习。
属性名称 | 说明 | 备注 |
FocusBorderBrushKey | 获取引用焦点的单元格的默认边框画笔的键。 | |
SelectAllCommand | 表示指示想要选择的所有单元格的命令 | |
HeadersVisibilityConverter | 获取标题显示隐藏的转换器,即HeadersVisibility属性的转换器 | |
RowDetailsScrollingConverter | 获取将转换为一个布尔值转换器 | |
DeleteCommand | 表示指示想要删除当前行的命令。 | |
RowHeaderTemplate | 获取或设置行标题的模板。 | 重要 |
RowHeaderTemplateSelector | 获取或设置行标题的模板选择器。 | |
VerticalScrollBarVisibility | 是否显示垂直滚动条 | |
HorizontalScrollBarVisibility | 是否显示水平滚动条 | |
CanUserAddRows | 是否可以添加新行 | 重要 |
CurrentItem | 当前选中行(一般指绑定的数据源的某一个元素) | 常用 |
CurrentColumn | 获取或设置包含当前单元格的列。 | |
CurrentCell | 获取或设置具有焦点的单元格。 | |
CanUserDeleteRows | 是否可以删除行 | 重要 |
RowHeaderStyle | 获取或设置应用于所有行标题的样式。 | 重要 |
RowDetailsVisibilityMode | 获取或设置一个值,该值指示何时显示某行的详细信息部分。 | |
IsReadOnly | 当前控件是否只读 | 常用 |
ColumnHeaderStyle | 获取或设置所有列标题的样式 | 重要 |
RowStyle | 获取或设置应用到的所有行的样式。 | 重要 |
HeadersVisibility | 获取或设置用于指定行和列标题的可见性的值。 | |
AreRowDetailsFrozen | 获取或设置一个值,该值指示是否可水平滚动行详细信息。 | |
AlternatingRowBackground | 获取或设置交替行上使用的背景画笔。 | 重要 |
RowBackground | 获取或设置用于行背景的默认画笔。 | |
RowStyleSelector | 获取或设置行的样式选择器。 | |
RowValidationRules | 获取用于验证每个行中的数据的规则。 | |
RowValidationErrorTemplate | 获取或设置用于以可视方式指示行验证中的错误的模板。 | |
VerticalGridLinesBrush | 获取或设置用于绘制垂直网格线的画笔。 | 常用 |
HorizontalGridLinesBrush | 获取或设置用于绘制水平网格线的画笔。 | |
GridLinesVisibility | 获取或设置一个值,该值指示显示哪些网格线。 | |
MaxColumnWidth | 获取或设置列和标头中的最大宽度约束 | |
MinColumnWidth | 获取或设置列和标头中的最小宽度约束 | |
ColumnWidth | 获取或设置标准宽度和列和中的标头的大小调整模式 | |
CanUserResizeColumns | 获取或设置用户是否可以通过使用鼠标调整列的宽度。 | |
Columns | 获取一个集合中的所有列 | 常用 |
RowHeaderWidth | 获取或设置行标题列的宽度。 | |
RowHeaderActualWidth | 获取呈现的行标题列的宽度。 | |
ColumnHeaderHeight | 获取或设置列标题行的高度。 | |
CellStyle | 获取或设置所有单元格的样式 | 常用 |
RowDetailsTemplate | 获取或设置用于显示行详细信息的模板。 | |
MinRowHeight | 获取或设置行和中的标头的最小高度约束 | |
CanUserResizeRows | 获取或设置用户是否可以通过使用鼠标调整行的高度。 | |
RowHeight | 获取或设置的所有行的建议的高度。 | |
RowDetailsTemplateSelector | 获取或设置用于行详细信息的模板选择器。 | |
CellsPanelHorizontalOffset | 获取DataGridCellsPanel的水平偏移量 | |
ClipboardCopyMode | 获取或设置一个值,指示如何将内容复制到剪贴板。 | |
NonFrozenColumns ViewportHorizontalOffset | 获取在视区的可滚动列的水平偏移量。 | |
FrozenColumnCount | 获取或设置非滚动列的数量。 | 常用 |
AutoGenerateColumns | 获取或设置一个值,该值指示是否自动创建列。 | 常用 |
NewItemMargin | 获取或设置新的项目行的边距。 | |
CanUserSortColumns | 是否可以单击列标题来对列排序。 | 常用 |
SelectionUnit | 选择行的模式 | |
SelectionMode | 是否支持多选 | 重要 |
SelectedCells | 获取当前选定的单元格的列表。 | |
HandlesScrolling | 是否支持自定义键盘滚动。 |
在上述表格中,Columns属性是DataGrid最基本的一个属性。它是一个ObservableCollection<DataGridColumn>类型的集合,表示DataGrid的列的集合。其实DataGridColumn只是一个抽象基类,我们真正在实例化时,是实例化DataGridColumn的子类,然后放到Columns属性中。
那么DataGridColumn有哪些子类呢?
- DataGridTextColumn 表示文本内容的列
- DataGridCheckBoxColumn 表示复选框的列
- DataGridComboBoxColumn 表示下拉框的列
- DataGridTemplateColumn 表示模板的列(万金油)
在本列中,我们将以最简单的DataGridTextColumn 为例。
三、事件成员
DataGrid一共有23个事件成员,它们分别如下所示
事件名称 | 说明 |
Sorting | 对列进行排序时发生。 |
AutoGeneratedColumns | 所有列的自动生成完成后发生。 |
AutoGeneratingColumn | 自动生成单独的列时出现。 |
ColumnHeaderDragDelta | 每次鼠标位置发生更改时在用户拖动列标题时发生。 |
ColumnHeaderDragStarted | 当用户开始使用鼠标拖动列标题时发生。 |
ColumnHeaderDragCompleted | 当用户使用鼠标拖动后释放列标题时发生。 |
SelectedCellsChanged | 发生时 DataGrid.SelectedCells 集合更改。 |
ColumnReordering | 在列移至的显示顺序中的新位置之前发生。 |
RowDetailsVisibilityChanged | 当某一行的可见性详细信息元素更改时发生。 |
UnloadingRow | 发生时 DataGridRow 对象将成为可供重用。 |
LoadingRowDetails | 新的行的详细信息模板应用于行时发生。 |
InitializingNewItem | 创建一个新项时出现。 |
PreparingCellForEdit | 在单元格进入编辑模式时发生。 |
BeginningEdit | 发生行或单元格进入编辑模式之前。 |
CurrentCellChanged | 在 DataGrid.CurrentCell 属性的值更改后发生。 |
CellEditEnding | 在单元格的编辑将在提交或取消前发生。 |
RowEditEnding | 在提交或取消行编辑之前发生。 |
LoadingRow | 加载row时 |
ColumnDisplayIndexChanged | 其中一个列更改属性时 |
UnloadingRowDetails | 行详细信息元素成为可供重用时发生。 |
AddingNewItem | 新项添加到DataGrid之前发生 |
CopyingRowClipboardContent | 默认行内容准备好之后发生。 |
ColumnReordered | 在列移至的显示顺序中的新位置时发生。 |
四、基本示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<DataGrid x:Name="datagrid"
SelectionMode="Extended"
IsReadOnly="True"
SelectionChanged="datagrid_Selected">
<DataGrid.Columns>
<DataGridTextColumn Header="姓名" Binding="{Binding Name}" />
<DataGridTextColumn Header="年龄" Binding="{Binding Age}" />
<DataGridTextColumn Header="地址" Binding="{Binding Address}" />
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Column="1">
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="姓名:"/>
<TextBlock x:Name="_TextBlockName"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="年龄:"/>
<TextBlock x:Name="_TextBlockAge"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="地址:"/>
<TextBlock x:Name="_TextBlockAddress"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
后端代码
namespace HelloWorld
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
datagrid.Items.Add(new Person { Name = "张三", Age = 22, Address = "广东省廉江市车板镇大坝村" });
datagrid.Items.Add(new Person { Name = "李四", Age = 23, Address = "江西省景德镇市市辖区" });
datagrid.Items.Add(new Person { Name = "王五", Age = 24, Address = "上海市虹口区" });
}
private void datagrid_Selected(object sender, RoutedEventArgs e)
{
DataGrid datagrid = sender as DataGrid;
if (datagrid == null) return;
var person = datagrid.SelectedItem as Person;
if (person == null) return;
_TextBlockName.Text = person.Name;
_TextBlockAge.Text = person.Age + "岁";
_TextBlockAddress.Text = person.Address;
}
}
}
在这个例子中,我们尽量还原了与ListView控件一致的功能, 需要注意的细节是:我们将DataGrid的IsReadOnly="True",这是因为我们直接将数据元素一条一条的加入到DataGrid的Items属性中,而Items属性本身是一个只读属性,不支持写入。这样的话,当鼠标双击时会报错。错误提示为:
如何解决这个问题呢?这就要用到ItemsControl基类中的ItemsSource数据源属性。
我们需要采用DataGrid另外一种赋值方式——数据源赋值。即把一个集合绑定到该属性上,这样在前端就可以编辑数据源,从而不会引发报错。
只需要改动一点点代码。
List<Person> list = new List<Person>();
list.Add(new Person { Name = "张三", Age = 22, Address = "广东省廉江市车板镇大坝村" });
list.Add(new Person { Name = "李四", Age = 23, Address = "江西省景德镇市市辖区" });
list.Add(new Person { Name = "王五", Age = 24, Address = "上海市虹口区" });
datagrid.ItemsSource = list;
前端代码也可以修改如下,AutoGenerateColumns属性设为不可自动创建列。
<DataGrid x:Name="datagrid"
SelectionMode="Extended"
IsReadOnly="False"
AutoGenerateColumns="False"
SelectionChanged="datagrid_Selected">
<DataGrid.Columns>
<DataGridTextColumn Header="姓名" Binding="{Binding Name}" />
<DataGridTextColumn Header="年龄" Binding="{Binding Age}" />
<DataGridTextColumn Header="地址" Binding="{Binding Address}" />
</DataGrid.Columns>
</DataGrid>
如此,我们便可以在DataGrid中新增一行,并输入新的数据。
本节内容我们用了两个例子来说明datagrid最基本的数据加载、显示与获取的功能,请在下面的地址中下载示例。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:041-《DataGrid数据表格控件》-源代码 -1,041-《DataGrid数据表格控件》-源代码 -2
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月6日
ComboBox表示带有下拉列表的控件,实际上您可以把它看成两个部分组成,一个类似TextBox文本输入框,所以它有一个Text文本属性,用于获取ComboBox框的文本值,另一个是类似ListBox的列表框,用于显示ComboBox绑定的所有数据源。
ComboBox继承于Selector,所以,它只能是单选操作。由于这个控件由两个部分构成,所以在用法上,我们也可以有两种主要用法——类似TextBox用法和类似ListBox用法。
我们在使用这个控件之前,先熟悉一下它的定义
一、ComboBox定义
[Localizability(LocalizationCategory.ComboBox)]
[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(ComboBoxItem))]
[TemplatePart(Name = "PART_EditableTextBox", Type = typeof(TextBox))]
[TemplatePart(Name = "PART_Popup", Type = typeof(Popup))]
public class ComboBox : Selector
{
public static readonly DependencyProperty MaxDropDownHeightProperty;
public static readonly DependencyProperty IsDropDownOpenProperty;
public static readonly DependencyProperty ShouldPreserveUserEnteredPrefixProperty;
public static readonly DependencyProperty IsEditableProperty;
public static readonly DependencyProperty TextProperty;
public static readonly DependencyProperty IsReadOnlyProperty;
public static readonly DependencyProperty SelectionBoxItemProperty;
public static readonly DependencyProperty SelectionBoxItemTemplateProperty;
public static readonly DependencyProperty SelectionBoxItemStringFormatProperty;
public static readonly DependencyProperty StaysOpenOnEditProperty;
public ComboBox();
public bool ShouldPreserveUserEnteredPrefix { get; set; }
public bool IsEditable { get; set; }
public string Text { get; set; }
public bool IsReadOnly { get; set; }
public object SelectionBoxItem { get; }
public double MaxDropDownHeight { get; set; }
public string SelectionBoxItemStringFormat { get; }
public bool StaysOpenOnEdit { get; set; }
public bool IsSelectionBoxHighlighted { get; }
public bool IsDropDownOpen { get; set; }
public DataTemplate SelectionBoxItemTemplate { get; }
protected internal override bool HandlesScrolling { get; }
protected internal override bool HasEffectiveKeyboardFocus { get; }
public event EventHandler DropDownClosed;
public event EventHandler DropDownOpened;
public override void OnApplyTemplate();
protected override DependencyObject GetContainerForItemOverride();
protected override bool IsItemItsOwnContainerOverride(object item);
protected override AutomationPeer OnCreateAutomationPeer();
protected virtual void OnDropDownClosed(EventArgs e);
protected virtual void OnDropDownOpened(EventArgs e);
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e);
protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e);
protected override void OnKeyDown(KeyEventArgs e);
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e);
protected override void OnPreviewKeyDown(KeyEventArgs e);
protected override void OnSelectionChanged(SelectionChangedEventArgs e);
protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
}
二、属性成员
属性名称 | 说明 |
ShouldPreserveUserEnteredPrefix | 是否保留用户的输入,或者输入替换匹配项。 |
IsEditable | 是否启用或禁用编辑文本框中文本 |
Text | 获取或设置当前选定项的文本。 |
IsReadOnly | 文本内容是否只读 |
SelectionBoxItem | 获取在选择框中显示的项。 |
MaxDropDownHeight | 获取或设置一个组合框下拉列表的最大高度。 |
SelectionBoxItemStringFormat | 指定选择框中文本的显示格式 |
StaysOpenOnEdit | 在编辑输入框文本时,希望下拉框保持打开,则为true |
IsSelectionBoxHighlighted | 是否突出显示SelectionBoxItem |
IsDropDownOpen | 是否打开组合框下拉列表。 |
SelectionBoxItemTemplate | 获取选择框内容的项模板。 |
接下来,我们还是一个实际的例子来说明combobox控件的用法。
三、ComboBox示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<StackPanel>
<ComboBox x:Name="combobox1" IsEditable="True" Height="30" Margin="20,10"
TextBoxBase.TextChanged="combobox1_TextChanged"/>
<ComboBox x:Name="combobox2" StaysOpenOnEdit="True" VerticalAlignment="Top"
SelectionChanged="combobox2_SelectionChanged"
Height="30" Margin="20,10" DisplayMemberPath="Name">
</ComboBox>
</StackPanel>
<StackPanel Grid.Column="1">
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="电话:"/>
<TextBlock x:Name="_TextBlockTel"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="姓名:"/>
<TextBlock x:Name="_TextBlockName"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="年龄:"/>
<TextBlock x:Name="_TextBlockAge"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="地址:"/>
<TextBlock x:Name="_TextBlockAddress"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
后端代码
namespace HelloWorld
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Person> list = new List<Person>();
list.Add(new Person { Name = "张三", Age = 22, Address = "广东省廉江市车板镇大坝村" });
list.Add(new Person { Name = "李四", Age = 23, Address = "江西省景德镇市市辖区" });
list.Add(new Person { Name = "王五", Age = 24, Address = "上海市虹口区" });
combobox2.ItemsSource = list;
}
private void combobox1_TextChanged(object sender, TextChangedEventArgs e)
{
_TextBlockTel.Text = combobox1.Text;
}
private void combobox2_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox combobox = sender as ComboBox;
if (combobox == null) return;
var person = combobox.SelectedItem as Person;
if (person == null) return;
_TextBlockName.Text = person.Name;
_TextBlockAge.Text = person.Age + "岁";
_TextBlockAddress.Text = person.Address;
}
}
}
我们在xaml中实例化了两个ComboBox,第一个直接当成了TextBox来使用;第二个则绑定了一个数据源,并在Xaml中指定了DisplayMemberPath属性显示Person的Name,最后在后端代码中,依然使用SelectedItem 属性获取当前选中项,转化成Person,以获取实际的选中数据。
这些就是该控件的基本用法。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:042-《ComboBox下拉框控件》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月6日
TabControl表示包含多个共享相同的空间在屏幕上的项的控件。它也是继承于Selector基类,所以TabControl也只支持单选操作。另外,TabControl的元素只能是TabItem,这个TabItem继承于HeaderedContentControl类,所以TabControl的元素实际上是一个带标题的ContentControl内容控件。
我们曾经在聊GroupBox控件和Expander折叠控件时都曾提到过这个HeaderedContentControl类,原来大家都用了这个带标题的内容控件。所以TabControl控件看起来就像是多个GroupBox组合而来。
一、TabControl的定义
public class TabControl : Selector
{
public static readonly DependencyProperty TabStripPlacementProperty;
public static readonly DependencyProperty SelectedContentProperty;
public static readonly DependencyProperty SelectedContentTemplateProperty;
public static readonly DependencyProperty SelectedContentTemplateSelectorProperty;
public static readonly DependencyProperty SelectedContentStringFormatProperty;
public static readonly DependencyProperty ContentTemplateProperty;
public static readonly DependencyProperty ContentTemplateSelectorProperty;
public static readonly DependencyProperty ContentStringFormatProperty;
public TabControl();
public DataTemplate ContentTemplate { get; set; }
public string SelectedContentStringFormat { get; }
public DataTemplateSelector SelectedContentTemplateSelector { get; }
public DataTemplate SelectedContentTemplate { get; }
public object SelectedContent { get; }
public Dock TabStripPlacement { get; set; }
public string ContentStringFormat { get; set; }
public DataTemplateSelector ContentTemplateSelector { get; set; }
public override void OnApplyTemplate();
protected override DependencyObject GetContainerForItemOverride();
protected override bool IsItemItsOwnContainerOverride(object item);
protected override AutomationPeer OnCreateAutomationPeer();
protected override void OnInitialized(EventArgs e);
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e);
protected override void OnKeyDown(KeyEventArgs e);
protected override void OnSelectionChanged(SelectionChangedEventArgs e);
}
二、属性成员
属性名称 | 说明 |
ContentTemplate | 表示TabItem元素的内容模板 |
SelectedContentStringFormat | 当前所选内容的格式 |
SelectedContentTemplateSelector | 获取当前选定的TabItem项的模板选择器 |
SelectedContentTemplate | 当前选定的TabItem项的模板 |
SelectedContent | 当前选定的TabItem项里面的内容(也是一些控件) |
TabStripPlacement | 获取或设置选项卡标题相对于选项卡上内容的对齐方式。 |
ContentStringFormat | 指定如何设置内容的格式 |
ContentTemplateSelector | 获取或设置内容模板选择器 |
TabControl的SelectedContent可能是我们比较常用的一个属性,事实上,TabControl通常被当成布局控件来使用。
三、TabControl示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TabControl x:Name="_tabControl" Grid.Row="0" SelectionChanged="_tabControl_SelectionChanged">
<TabItem Header="首页">
<Border Background="LightBlue">
<TextBlock Text="首页的界面" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</TabItem>
<TabItem Header="WPF目录">
<Border Background="LightCoral">
<TextBlock Text="WPF目录的界面" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</TabItem>
<TabItem Header="官方文档">
<Border Background="LightCyan">
<TextBlock Text="官方文档的界面" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</TabItem>
<TabItem Header="付费课程">
<Border Background="LightGoldenrodYellow">
<TextBlock Text="付费课程的界面" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</TabItem>
<TabItem Header="统计">
<Border Background="LightGreen">
<TextBlock Text="统计的界面" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</TabItem>
</TabControl>
<TextBlock x:Name="_textBlock" TextWrapping="Wrap" Grid.Row="1"/>
</Grid>
</Window>
后端代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void _tabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var tab = sender as TabControl;
var item = tab.SelectedItem as TabItem;
var content = tab.SelectedContent;
_textBlock.Text = "标题:" + item.Header.ToString() + " 内容:" + content;
}
}
我们订阅了TabControl控件的SelectionChanged事件,并在回调函数中获取了当前选中的TabItem对象以及它里面的内容。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:043-《TabControl控件》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月6日
TreeView其实是一个比较复杂的控件,像操作系统的资源管理器就是一个TreeView。所以它常用于显示文件夹、目录等具有层级结构的数据。TreeView由节点和分支构成,每个节点可以包含零个或多个子节点,分支表示父子关系。在TreeView中,每个节点表示为TreeViewItem对象,可以通过TreeView的Items属性来获取或设置TreeViewItem对象集合。
在使用TreeView加载节点时,需要掌握一些递归思想。
一、TreeViewItem元素简介
TreeViewItem作为TreeView唯一的元素类型,它继承于HeaderedItemsControl(带标题),而HeaderedItemsControl又继承于ItemsControl,由此可见,TreeViewItem元素本身也是一个集合控件。
TreeViewItem有两个常用的属性,分别是IsSelected属性和IsExpanded属性,IsSelected表示当前元素是否选中,IsExpanded表示当前元素是否展开。
二、TreeView类的定义
public class TreeView : ItemsControl
{
public static readonly DependencyProperty SelectedItemProperty;
public static readonly DependencyProperty SelectedValueProperty;
public static readonly DependencyProperty SelectedValuePathProperty;
public static readonly RoutedEvent SelectedItemChangedEvent;
public TreeView();
public string SelectedValuePath { get; set; }
public object SelectedValue { get; }
public object SelectedItem { get; }
protected internal override bool HandlesScrolling { get; }
public event RoutedPropertyChangedEventHandler<object> SelectedItemChanged;
protected virtual bool ExpandSubtree(TreeViewItem container);
protected override DependencyObject GetContainerForItemOverride();
protected override bool IsItemItsOwnContainerOverride(object item);
protected override AutomationPeer OnCreateAutomationPeer();
protected override void OnGotFocus(RoutedEventArgs e);
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e);
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e);
protected override void OnKeyDown(KeyEventArgs e);
protected virtual void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e);
}
SelectedValuePath属性:获取或设置SelectedItem或SelectedValue的路径。
SelectedValue属性:获取SelectedItem的值
SelectedItem属性:获取当前选中的项
三、TreeView示例
接下来,我们以一个简单的示例,模仿操作系统的资源管理器的目录加载。
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="根目录" VerticalAlignment="Center" Margin="3"/>
<TextBox x:Name="_TextBox" Width="380" Height="25" Margin="3"/>
<Button Content="选择..." MinWidth="45" Margin="3" Click="Button_Click"/>
</StackPanel>
<TreeView x:Name="_TreeView" Grid.Row="1" SelectedItemChanged="_TreeView_SelectedItemChanged"/>
</Grid>
</Window>
后端代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
_TextBox.Text = dialog.SelectedPath;
LoadTreeView(dialog.SelectedPath);
}
}
private void LoadTreeView(string rootPath)
{
// 设置根节点
TreeViewItem rootNode = new TreeViewItem();
rootNode.Header = "根目录";
// 加载子文件夹和文件
LoadSubDirectory(rootNode, rootPath);
// 将根节点添加到TreeView中
_TreeView.Items.Add(rootNode);
}
private void LoadSubDirectory(TreeViewItem node, string path)
{
try
{
DirectoryInfo dirInfo = new DirectoryInfo(path);
// 加载子文件夹
foreach (DirectoryInfo subDirInfo in dirInfo.GetDirectories())
{
TreeViewItem subNode = new TreeViewItem();
subNode.Header = subDirInfo.Name;
LoadSubDirectory(subNode, subDirInfo.FullName);
node.Items.Add(subNode);
}
// 加载文件
foreach (FileInfo fileInfo in dirInfo.GetFiles())
{
TreeViewItem subNode = new TreeViewItem();
subNode.Header = fileInfo.Name;
node.Items.Add(subNode);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void _TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
// 获取选中的节点
TreeViewItem selectedNode = _TreeView.SelectedItem as TreeViewItem;
// 显示选中节点的Header
if (selectedNode != null)
{
MessageBox.Show(selectedNode.Header.ToString());
}
}
}
首先,通过鼠标操作,选择TreeView的根目录,然后,利用DirectoryInfo获取当前所有目录,再利用递归调用,一层一层的获取所有子目录,最后以TreeViewItem元素一层层加载到控件中。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:044-《TreeView树控件》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月8日
Menu控件继承于MenuBase,而MenuBase继承于ItemsControl。所以学习Menu之前,要先了解一下MenuBase基类。它是一个抽象类,拥有一个ItemContainerTemplateSelector模板选择器,并重写了一些关于键盘和鼠标的方法。
Menu的子项必须为MenuItem。这个MenuItem和前面的TreeViewItem类似,拥有共同的HeaderedItemsControl父类,也就是说,MenuItem本身也是一个集合控件,若要以代码形式加载Menu的内容,也必须要掌握递归的加载思路。
在本节中,我们将以两种方式加载Menu的数据。但是在学习之前,先熟悉一下MenuItem元素,因为,实际上,我们主要是操作MenuItem元素。
一、MenuItem元素
public class MenuItem : HeaderedItemsControl, ICommandSource
{
public static readonly RoutedEvent ClickEvent;
public static readonly DependencyProperty UsesItemContainerTemplateProperty;
public static readonly DependencyProperty ItemContainerTemplateSelectorProperty;
public static readonly DependencyProperty IsSuspendingPopupAnimationProperty;
public static readonly DependencyProperty IconProperty;
public static readonly DependencyProperty InputGestureTextProperty;
public static readonly DependencyProperty StaysOpenOnClickProperty;
public static readonly DependencyProperty IsCheckedProperty;
public static readonly DependencyProperty IsHighlightedProperty;
public static readonly DependencyProperty IsCheckableProperty;
public static readonly DependencyProperty IsPressedProperty;
public static readonly DependencyProperty IsSubmenuOpenProperty;
public static readonly DependencyProperty CommandTargetProperty;
public static readonly DependencyProperty CommandParameterProperty;
public static readonly DependencyProperty CommandProperty;
public static readonly RoutedEvent SubmenuClosedEvent;
public static readonly RoutedEvent SubmenuOpenedEvent;
public static readonly RoutedEvent UncheckedEvent;
public static readonly RoutedEvent CheckedEvent;
public static readonly DependencyProperty RoleProperty;
public MenuItem();
public static ResourceKey SubmenuHeaderTemplateKey { get; }
public static ResourceKey SubmenuItemTemplateKey { get; }
public static ResourceKey SeparatorStyleKey { get; }
public static ResourceKey TopLevelItemTemplateKey { get; }
public static ResourceKey TopLevelHeaderTemplateKey { get; }
public bool IsCheckable { get; set; }
public object CommandParameter { get; set; }
public IInputElement CommandTarget { get; set; }
public bool IsSubmenuOpen { get; set; }
public MenuItemRole Role { get; }
public bool IsPressed { get; protected set; }
public bool IsHighlighted { get; protected set; }
public bool StaysOpenOnClick { get; set; }
public string InputGestureText { get; set; }
public object Icon { get; set; }
public bool IsSuspendingPopupAnimation { get; }
public ItemContainerTemplateSelector ItemContainerTemplateSelector { get; set; }
public bool UsesItemContainerTemplate { get; set; }
public bool IsChecked { get; set; }
public ICommand Command { get; set; }
protected override bool IsEnabledCore { get; }
protected internal override bool HandlesScrolling { get; }
public event RoutedEventHandler Unchecked;
public event RoutedEventHandler Click;
public event RoutedEventHandler Checked;
public event RoutedEventHandler SubmenuClosed;
public event RoutedEventHandler SubmenuOpened;
public override void OnApplyTemplate();
protected override DependencyObject GetContainerForItemOverride();
protected override bool IsItemItsOwnContainerOverride(object item);
protected override void OnAccessKey(AccessKeyEventArgs e);
protected virtual void OnChecked(RoutedEventArgs e);
protected virtual void OnClick();
protected override AutomationPeer OnCreateAutomationPeer();
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e);
protected override void OnInitialized(EventArgs e);
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e);
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e);
protected override void OnKeyDown(KeyEventArgs e);
protected override void OnMouseEnter(MouseEventArgs e);
protected override void OnMouseLeave(MouseEventArgs e);
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e);
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e);
protected override void OnMouseMove(MouseEventArgs e);
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e);
protected override void OnMouseRightButtonUp(MouseButtonEventArgs e);
protected virtual void OnSubmenuClosed(RoutedEventArgs e);
protected virtual void OnSubmenuOpened(RoutedEventArgs e);
protected virtual void OnUnchecked(RoutedEventArgs e);
protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item);
protected internal override void OnVisualParentChanged(DependencyObject oldParent);
}
MenuItem从鼠标的交互上,提供了两种方式。第一种是提供了Click事件,开发者可以订阅该事件以编写相应的业务逻辑。第二种是提供了ICommand接口属性和CommandParameter命令参数,以WPF命令的形式开发业务逻辑。
下面,我们以一种交互方式为例。
二、Menu示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Menu x:Name="_Menu">
<MenuItem Header="文件">
<MenuItem Header="新建" Click="MenuItem_Click"/>
<MenuItem Header="打开" Click="MenuItem_Click">
<MenuItem.Icon>
<Image Source="/Images/logo.png"/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="编辑"/>
<MenuItem Header="视图"/>
<MenuItem Header="项目"/>
<MenuItem Header="调试"/>
<MenuItem Header="测试"/>
<MenuItem Header="分析"/>
<MenuItem Header="工具"/>
<MenuItem Header="帮助"/>
</Menu>
<TextBlock x:Name="_TextBlock" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</Window>
后端代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuItem;
_TextBlock.Text = $"你单击了 {item.Header}";
}
}
上面演示了Menu最基本的用法,如果希望采用数据绑定的方式加载菜单,则可以参考下面的作法。
三、Menu数据绑定
我们需要创建一个实体类,来代表Menu的每一个子项。
/// <summary>
/// 主菜单的实体
/// </summary>
public class MenuModel
{
public string Name { get; set; }
public List<MenuModel> Children { get; set; } = new List<MenuModel>();
public string View { get; set; }
}
在前端代码中,需要设置Menu的ItemTemplate元素模板。
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Menu x:Name="_Menu">
<Menu.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
</Grid>
</Window>
因为MenuModel实体中有Children集合,所以在前端将Children作为HierarchicalDataTemplate的ItemsSource。并将Name显示出来。
最后,实例化一些子项数据,形成一个数据源,将这个数据源绑定到Menu的ItemsSource即可
来看看后端代码
public partial class MainWindow : Window
{
public List<MenuModel> Menus { get; set; } = new List<MenuModel>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 5; i++)
{
MenuModel parent = new MenuModel();
parent.Name = $"一级菜单 ";
for (int j = 0; j < 5; j++)
{
MenuModel child = new MenuModel();
child.Name = $"二级菜单 ";
parent.Children.Add(child);
}
Menus.Add(parent);
}
_Menu.ItemsSource = Menus;
}
}
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:045-《Menu菜单控件》-源代码 -1,045-《Menu菜单控件》-源代码 -2
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月8日
ContextMenu上下文菜单必须要依附于一个“宿主控件”。由于FrameworkElement基类有一个叫ContextMenu的属性,代表了鼠标右键时弹出一个菜单,所以大多数控件都可以设置“上下文菜单”。
ContextMenu继承于MenuBase,而MenuBase继承于ItemsControl。所以,ContextMenu本质上也是一个集合控件。而它的元素则是MenuItem。在用法上,与Menu控件差不多。
一、ContextMenu的定义
public class ContextMenu : MenuBase
{
public static readonly DependencyProperty HorizontalOffsetProperty;
public static readonly RoutedEvent OpenedEvent;
public static readonly DependencyProperty StaysOpenProperty;
public static readonly DependencyProperty CustomPopupPlacementCallbackProperty;
public static readonly DependencyProperty HasDropShadowProperty;
public static readonly RoutedEvent ClosedEvent;
public static readonly DependencyProperty PlacementRectangleProperty;
public static readonly DependencyProperty PlacementTargetProperty;
public static readonly DependencyProperty IsOpenProperty;
public static readonly DependencyProperty VerticalOffsetProperty;
public static readonly DependencyProperty PlacementProperty;
public ContextMenu();
public double HorizontalOffset { get; set; }
public bool StaysOpen { get; set; }
public CustomPopupPlacementCallback CustomPopupPlacementCallback { get; set; }
public bool HasDropShadow { get; set; }
public PlacementMode Placement { get; set; }
public Rect PlacementRectangle { get; set; }
public UIElement PlacementTarget { get; set; }
public bool IsOpen { get; set; }
public double VerticalOffset { get; set; }
protected internal override bool HandlesScrolling { get; }
public event RoutedEventHandler Closed;
public event RoutedEventHandler Opened;
protected virtual void OnClosed(RoutedEventArgs e);
protected override AutomationPeer OnCreateAutomationPeer();
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e);
protected override void OnKeyDown(KeyEventArgs e);
protected override void OnKeyUp(KeyEventArgs e);
protected virtual void OnOpened(RoutedEventArgs e);
protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
protected internal override void OnVisualParentChanged(DependencyObject oldParent);
}
二、属性成员
属性名称 | 说明 |
HorizontalOffset | 获取或设置目标原点和弹出项对齐之间的水平距离点。 |
StaysOpen | 是否保持打开状态 |
CustomPopupPlacementCallback | 获取或设置ContextMenu指示在屏幕位置的回调 |
HasDropShadow | 是否有投影出现的上下文菜单。 |
Placement | 获取或设置ContextMenu显示的相对位置 |
PlacementRectangle | 获取或设置相对于其上下文菜单位于在打开时的区域。 |
PlacementTarget | 获取或设置ContextMenu打开时的相对控件 |
IsOpen | 是否打开 |
VerticalOffset | 获取或设置目标原点和弹出项对齐之间的垂直距离点。 |
三、ContextMenu示例
<Grid>
<Border Background="LightBlue" Width="200" Height="100" CornerRadius="15">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="复制"/>
<MenuItem Header="粘贴"/>
<MenuItem Header="删除"/>
<MenuItem Header="关于"/>
</ContextMenu>
</Border.ContextMenu>
</Border>
</Grid>
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:046-《ContextMenu上下文菜单》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月8日