- 示例工程
【免费下载链接】WPF-Samples
Repository for WPF related samples
本篇技术指南以 WPF-Samples 仓库中的 CollectionBinding 示例 为主体,系统讲解 WPF 数据绑定中"绑定到集合(Bind to a Collection)"以及"依据当前选中项显示对应信息(Display Information Based on Selection)"这一经典主从联动模式的完整实现。读完本文,你将掌握如何使用ObservableCollection<T>封装数据源、如何在 XAML 中声明集合资源、如何通过IsSynchronizedWithCurrentItem同步选中项,以及如何用DataTemplate将集合当前项渲染为详细信息视图——这套组合正是 WPF 中列表-详情(Master/Detail)界面最基础也最常用的实现手法。
示例定位与功能概述
本示例对应微软官方文档主题 "How to: Bind to a Collection and Display Information Based on Selection",其核心演示目标非常聚焦:
- 绑定到集合:将一个内存中的"朋友"(
Person)集合直接绑定到ListBox作为列表数据源; - 依据选择显示信息:在窗口下方,用
ContentControl展示当前在列表中选中的人物的详细资料(名、姓、家乡)。
整个示例的界面布局非常简洁:上方是一个"My Friends:" 标签下的ListBox列表,下方是 "Information:" 标签下的详情区域。当用户在列表中切换选中项时,详情区域的内容会实时跟随变化。
该示例属于仓库的 Data Binding 分类,并被收录进根级解决方案文件 WPFSamples.sln(项目条目为CollectionBinding,对应 CollectionBinding.csproj),可以通过打开解决方案或直接dotnet build该工程来构建。
项目结构:一个最小的集合绑定示例
CollectionBinding示例的文件结构非常精简,恰好构成一个完整的、可独立运行的 WPF 应用:
| 文件 | 职责 |
|---|---|
| App.xaml | 应用入口,通过StartupUri="MainWindow.xaml"启动主窗口 |
| App.cs | App类代码隐藏,仅调用InitializeComponent |
| MainWindow.xaml | 声明集合资源、定义DataTemplate、完成所有绑定(核心文件) |
| MainWindow.cs | 主窗口代码隐藏,标准空实现 |
| People.cs | 集合数据源,继承ObservableCollection<Person>并预置 4 条数据 |
| Person.cs | 数据项模型,实现INotifyPropertyChanged |
| CollectionBinding.csproj | 项目文件,目标框架为net10.0-windows并启用UseWpf |
从源码结构看,这个示例刻意保持了"零业务逻辑"——主窗口代码隐藏 MainWindow.cs 中只有构造函数和InitializeComponent(),所有数据准备与界面联动全部在 XAML 和模型类中完成,非常适合作为集合绑定的入门教学样本。
数据模型层:Person 与 People
数据项:实现INotifyPropertyChanged的 Person
Person.cs 定义了每一个列表项的数据形状,包含三个字符串属性:FirstName(名)、LastName(姓)、HomeTown(家乡)。该模型实现了System.ComponentModel.INotifyPropertyChanged接口:
public class Person : INotifyPropertyChanged { private string _firstname; private string _hometown; private string _lastname; public Person() { } public Person(string first, string last, string town) { _firstname = first; _lastname = last; _hometown = town; } public string FirstName { get { return _firstname; } set { _firstname = value; OnPropertyChanged("FirstName"); } } // LastName、HomeTown 的结构与此相同…… public event PropertyChangedEventHandler PropertyChanged; public override string ToString() => _firstname; protected void OnPropertyChanged(string info) { var handler = PropertyChanged; handler?.Invoke(this, new PropertyChangedEventArgs(info)); } }关键点在于:凡是需要被 WPF 绑定并在运行期动态刷新的属性,其 setter 中都必须触发PropertyChanged事件。在本示例中该通知机制保证的是"属性级"的 UI 更新(例如属性值被外部修改时详情区域同步刷新);而"集合级"的增删更新则由下一节的ObservableCollection<T>负责。
集合:继承ObservableCollection<Person>的 People
People.cs 是本次绑定的集合数据源:
public class People : ObservableCollection<Person> { public People() { Add(new Person("Michael", "Alexander", "Bellevue")); Add(new Person("Jeff", "Hay", "Redmond")); Add(new Person("Christina", "Lee", "Kirkland")); Add(new Person("Samantha", "Smith", "Seattle")); } }选择继承System.Collections.ObjectModel.ObservableCollection<T>而非普通List<T>,是因为 WPF 的绑定引擎需要监听集合的CollectionChanged事件:当集合被Add/Remove/Clear等操作修改时,绑定到它的ListBox等控件才会自动获知并刷新。这正是 WPF 中"集合绑定 + 自动更新"的内置契约——只要集合实现INotifyCollectionChanged(ObservableCollection<T>的默认实现),UI 就能与数据保持同步,无需手工刷新。
XAML 核心:三步完成"列表 + 详情"联动
核心绑定逻辑全部集中在 MainWindow.xaml,可以拆解为三个关键步骤。
第一步:把集合声明为窗口资源
<Window.Resources> <local:People x:Key="MyFriends"/> ... </Window.Resources>通过xmlns:local="clr-namespace:CollectionBinding"引入命名空间后,XAML 直接实例化People类(其构造函数会预填 4 条Person数据),并以资源键MyFriends供全窗口引用。这种"资源 +StaticResource"的方式避免了在代码中手工构造数据源,是纯 XAML 声明式绑定的典型写法。
第二步:ListBox 绑定集合并同步当前项
<ListBox Width="200" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource MyFriends}}"/>这里有两个关键属性:
ItemsSource="{Binding Source={StaticResource MyFriends}}":将集合资源MyFriends直接作为列表项的数据源。WPF 会为集合绑定自动创建"视图(View)"——即CollectionView——它维护一个**当前项(CurrentItem)**指针;IsSynchronizedWithCurrentItem="True":让ListBox的选中项与该集合视图的当前项保持同步。默认情况下ListBox/ListView等选择型控件会自动维持这种同步,但显式设置为True可以让行为一目了然,也是本示例实现"选中哪个,就显示哪个"的关键开关。
第三步:用 DataTemplate + ContentControl 渲染当前项
窗口资源中定义了一个名为DetailTemplate的DataTemplate,内部用Border+Grid组织了一个两列三行的信息面板,逐行显示FirstName、LastName、HomeTown:
<DataTemplate x:Key="DetailTemplate"> <Border Width="300" Height="100" Margin="20" BorderBrush="Aqua" BorderThickness="1" Padding="8"> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="First Name:"/> <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=FirstName}"/> <TextBlock Grid.Row="1" Grid.Column="0" Text="Last Name:"/> <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=LastName}"/> <TextBlock Grid.Row="2" Grid.Column="0" Text="Home Town:"/> <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=HomeTown}"/> </Grid> </Border> </DataTemplate>随后详情区域通过ContentControl把整个集合作为内容、同时指定模板来渲染:
<ContentControl Content="{Binding Source={StaticResource MyFriends}}" ContentTemplate="{StaticResource DetailTemplate}"/>这里的巧妙之处在于:ContentControl绑定的是集合本身,但当ContentTemplate对集合进行渲染时,WPF 绑定引擎会自动把**集合视图的当前项(CurrentItem)**作为数据上下文交给DataTemplate,因此模板内的{Binding Path=FirstName}实际取的是列表当前选中人物的属性。用户切换 ListBox 选中项 → 集合视图当前项变化 →ContentControl重新应用模板并刷新三个TextBlock,从而完成"依据选择显示信息"的联动效果。
窗口其余部分是纯样式声明:为ListBoxItem设置 Verdana 字体与Padding="10"的内边距,两个区段标题TextBlock加粗显示,整体布局由外层StackPanel垂直排列。
集合绑定的底层机制简析
从 WPF 数据绑定引擎的角度看,这个示例背后有三层协同机制:
- 绑定源适配:
ListBox.ItemsSource接收IEnumerable,引擎将其包装为CollectionView。CollectionView是 WPF 中"集合的视图"抽象,所有绑定到集合的控件共享这一层,排序、筛选、分组也都在这一层进行(参见同仓库的 CollectionViewSource 示例,它演示了如何在 XAML 中为集合视图添加SortDescription与GroupDescription); - 当前项传播:
CollectionView.CurrentItem是"视图当前项",IsSynchronizedWithCurrentItem="True"使ListBox的SelectedItem与CurrentItem双向同步; - 模板渲染:
ContentControl在渲染ContentTemplate时,将CurrentItem作为DataContext传入DataTemplate,模板内相对路径的{Binding Path=...}因此都能正确解析到当前人物的属性。
同样的"当前项 + 主从联动"思想,在仓库的 MasterDetail 示例 中得到了更进一步的展示:两个ListBox共享同一数据上下文,第二级列表通过{Binding Path=Divisions}跟随第一个列表的选中项变化,三级联动全部建立在IsSynchronizedWithCurrentItem="true"之上。这印证了本示例模式是 WPF 主从界面通用的基础设施。
如何构建与运行
通过 Visual Studio
依据示例自带的 README 与仓库根 README 的说明,构建方式如下:
- 打开根目录下的 WPFSamples.sln(或直接打开
Data Binding/CollectionBinding/CollectionBinding.csproj); - 部署:选择菜单Build(生成) > Deploy Solution(部署解决方案);
- 调试运行:按F5,或选择Debug > Start Debugging;
- 免调试运行:按Ctrl+F5,或选择Debug > Start Without Debugging。
通过命令行
当前仓库 main 分支的所有示例均以 .NET 10 为目标(CollectionBinding.csproj 中TargetFramework为net10.0-windows,UseWpf为true),因此也可以使用 SDK 风格的构建命令:
dotnet build "Data Binding/CollectionBinding/CollectionBinding.csproj"然后运行生成的可执行文件CollectionBinding.exe(位于bin\Debug\net10.0-windows\等输出目录)。无论采用哪种方式,前提都是安装与net10.0-windows匹配的 .NET SDK,并在支持 WPF 的 Windows 环境中运行。
小结
CollectionBinding示例用最小的代码量完整呈现了 WPF 集合绑定的三条主线:以ObservableCollection<T>作为可通知的集合数据源、以IsSynchronizedWithCurrentItem同步选中项与集合视图当前项、以DataTemplate渲染当前项形成"列表—详情"联动。这套组合不仅是入门必学的绑定范式,也是仓库中 MasterDetail、CollectionViewSource、SortFilter 等众多数据绑定示例共同的底层基础设施,理解它即可顺藤摸瓜地掌握 WPF 数据绑定体系的其余部分。
- 示例工程
【免费下载链接】WPF-Samples
Repository for WPF related samples
相关推荐
WPF 绑定验证(Binding Validation)实战:基于 WPF-Samples 的 BindValidation 示例详解
WPF 绑定验证(Binding Validation)实战:基于 WPF Samples 的 BindValidation 示例详解 导读 本篇技术指南以 W
示例工程Zsh 与 Bash 全面对比:面向 refine 工程实践的命令行与脚本指南
Zsh 与 Bash 全面对比:面向 refine 工程实践的命令行与脚本指南 本篇指南系统对比 Unix 世界两大主流 Shell——Bash(Bourne
示例工程WPF 应用关闭机制实战:基于 WPF-Samples 的 ApplicationShutdown 示例解析
WPF 应用关闭机制实战:基于 WPF Samples 的 ApplicationShutdown 示例解析 导读 本文围绕微软 WPF Samples 仓库中
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考