WPF 列表控件数据源绑定多个数据集合方法
在 WPF 用的多的列表控件如 ListBox 或 ListView 等,本文告诉大家在这些列表控件上进行绑定多个数据集合来源的多个实现方法。如有一个显示动物列表的控件,需要绑定的数据来源是阿猫和阿狗两个 ObservableCollection 列表,不在后台代码编写合并集合的代码情况下,可以通过 XAML 的编写,绑定多个数据集合
准备
在开始之前,咱先搭建一点测试使用的代码,假定咱有一个 列表控件 准备绑定到的数据源是两个 ObservableCollection 对象,下面来定义这两个 ObservableCollection 对象和对应的 阿猫和阿狗 的代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
{
Dogs.Add(new Dog()
{
Name = "Dog" + i
});
Cats.Add(new Cat()
{
Name = "Cat" + i
});
}
DataContext = this;
}
public ObservableCollection<Dog> Dogs { get; } = new ObservableCollection<Dog>();
public ObservableCollection<Cat> Cats { get; } = new ObservableCollection<Cat>();
}
public class Dog : Animal
{
}
public class Cat : Animal
{
}
public class Animal
{
public string Name { get; set; }
}
可以看到以上代码里面存在两个 ObservableCollection 对象,同时 MainWindow 的 DataContext 就是 MainWindow 对象。咱需要将两个 ObservableCollection 对象作为数据源,放在相同的一个 ListBox 里面
下面是多个不同的实现方式,解决如何在 WPF 中在 ListBox 或 ListView 绑定多个数据集合 ObservableCollection 对象
通过 CollectionViewSource 方式
在 ListView 或 ListBox 资源里面,添加 CollectionViewSource 绑定到集合里面,然后在 ItemsSource 使用 CompositeCollection 进行绑定,代码如下
<ListBox>
<ListBox.Resources>
<CollectionViewSource x:Key="DogCollection" Source="{Binding Dogs}"/>
<CollectionViewSource x:Key="CatCollection" Source="{Binding Cats}"/>
</ListBox.Resources>
<ListBox.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource DogCollection}}"/>
<CollectionContainer Collection="{Binding Source={StaticResource CatCollection}}"/>
</CompositeCollection>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
这个方法的优势在于可以完全使用 XAML 编写内容,但是缺点在于有重复的代码,如有多个绑定的集合对象,就需要在资源和 CompositeCollection 里面定义多个 CollectionViewSource 和 CollectionContainer 对象
如果绑定的集合数量不多,那么此写法还成,但如果集合数量比较多,而且需要不断变更顺序,那以上写法就有坑
此方法请参考 WPF 很少人知道的科技 - walterlv
通过 CompositeCollection 动态绑定
在 ListView 或 ListBox 的资源里面定义了 CompositeCollection 通过控件的 DataContext 绑定多个集合,代码如下
<CompositeCollection x:Key="MyColl">
<CollectionContainer Collection="{Binding DataContext.Dogs, Source={x:Reference MyList}}"/>
<CollectionContainer Collection="{Binding DataContext.Cats, Source={x:Reference MyList}}"/>
</CompositeCollection>
以上代码的 MyList 就是集合控件,此方法需要用到 x:Reference 获取对象的引用,同时需要通过 DataContext 的某个属性获取到对应的属性,全部代码如下
<ListBox x:Name="MyList" ItemsSource="{DynamicResource MyColl}">
<ListBox.Resources>
<CompositeCollection x:Key="MyColl">
<CollectionContainer Collection="{Binding DataContext.Dogs, Source={x:Reference MyList}}"/>
<CollectionContainer Collection="{Binding DataContext.Cats, Source={x:Reference MyList}}"/>
</CompositeCollection>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
对比上面的方法,此方法可以让绑定集合的代码只写一次,看起来代码更少一点。但不足的地方在于绑定 ItemsSource 需要用到 DynamicResource 的方式,相对性能不如上面方法。为什么需要 DynamicResource 资源?原因是资源本身定义在 Resources 里面。为什么资源需要定义在控件里面的 Resource 里面?原因是为了获取到控件的 x:Reference 对象。也就是说需要在控件创建出来之后,才能通过 x:Reference 获取控件,而控件的数据内容需要依赖资源的定义,因此也只有以上方式的写法
如果能从控件的上层容器拿到数据对象,那可以将资源定义在容器里面,通过 StaticResource 绑定到静态资源。如放在 Window 的 Resources 里
<Window x:Class="CibairyafocairluYerkinemde.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:CibairyafocairluYerkinemde"
mc:Ignorable="d"
x:Name="Root"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<CompositeCollection x:Key="MyColl">
<CollectionContainer Collection="{Binding DataContext.Dogs, Source={x:Reference Root}}"/>
<CollectionContainer Collection="{Binding DataContext.Cats, Source={x:Reference Root}}"/>
</CompositeCollection>
</Window.Resources>
<Grid>
<ListBox x:Name="MyList" ItemsSource="{StaticResource MyColl}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
以上写法没有啥缺点,也不存在动态资源的性能问题。但实际上在有动态资源下,性能问题也是很小的问题,对比渲染控件本身,动态绑定性能可以忽略
通过多绑定方法
此方法需要添加一点后台代码,定义 CompositeCollectionConverter 转换器,实现逻辑是通过多绑定的方法,将多个数据集合当成多个参数进行绑定
<ListBox>
<ListBox.ItemsSource>
<MultiBinding Converter="{x:Static local:CompositeCollectionConverter.Default}">
<Binding Path="Dogs" />
<Binding Path="Cats" />
</MultiBinding>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
可以看到此方法的 XAML 代码量最小,只是需要一个辅助的 CompositeCollectionConverter 类,代码如下
public class CompositeCollectionConverter : IMultiValueConverter
{
public static readonly CompositeCollectionConverter Default = new CompositeCollectionConverter();
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var compositeCollection = new CompositeCollection();
foreach (var value in values)
{
if (value is IEnumerable enumerable)
{
compositeCollection.Add(new CollectionContainer { Collection = enumerable });
}
else
{
compositeCollection.Add(value);
}
}
return compositeCollection;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException("CompositeCollectionConverter ony supports oneway bindings");
}
}
可以将 CompositeCollectionConverter 放在库里面,这样就可以让 XAML 代码看起来简单
本文所有代码放在 github 和 gitee 欢迎小伙伴访问
参考
本文以上方法参考了如下博客
wpf - How do you bind a CollectionContainer to a collection in a view model? - Stack Overflow
WPF 列表控件数据源绑定多个数据集合方法的更多相关文章
- ASP .NET MVC HtmlHelper扩展——简化“列表控件”的绑定
在众多表单元素中,有一类<select>元素用于绑定一组预定义列表.传统的ASP.NET Web Form中,它对应着一组重要的控件类型,即ListControl,我们经常用到DropDo ...
- 在Bootstrap开发框架中使用dataTable直接录入表格行数据(2)--- 控件数据源绑定
在前面随笔<在Bootstrap开发框架中使用dataTable直接录入表格行数据>中介绍了在Web页面中使用Jquery DataTable插件进行对数据直接录入操作,这种处理能够给用户 ...
- C#.NET 通用控件数据源绑定类
using System.Data; using System.Collections; using System.Collections.Generic; using System.Web.UI; ...
- WPF Image控件的绑定
在我们平时的开发中会经常用到Image控件,通过设置Image控件的Source属性,我们可以加载图片,设置Image的source属性时可以使用相对路径也可以使用绝对路径,一般情况下建议使用绝对路径 ...
- WPF 列表控件中的子控件上下文绑定
<DataGrid Grid.ColumnSpan=" Height="Auto" SelectedItem="{Binding Path=SelectP ...
- silverlight列表控件ComboBox 托管代码绑订数据集合
.xaml <ComboBox x:Name="myCombobox" Width="300" Height="30"> < ...
- .NET各大平台数据列表控件绑定原理及比较(WebForm、Winform、WPF)
说说WebForm: 数据列表控件: WebForm 下的列表绑定控件基本就是GridView.DataList.Repeater:当然还有其它DropDownList.ListBox等. 它们的共同 ...
- WPF DevExpress Chart控件 界面绑定数据源,不通过C#代码进行绑定
<Grid x:Name="myGrid" Loaded="Grid_Loaded" DataContext="{Binding PartOne ...
- 【WPF开发备忘】使用MVVM模式开发中列表控件内的按钮事件无法触发解决方法
实际使用MVVM进行WPF开发的时候,可能会用到列表控件中每行一个编辑或删除按钮,这时直接去绑定,发现无法响应: <DataGridTemplateColumn Header="操作& ...
- WPF: 实现带全选复选框的列表控件
本文将说明如何创建一个带全选复选框的列表控件.其效果如下图: 这个控件是由一个复选框(CheckBox)与一个 ListView 组合而成.它的操作逻辑: 当选中“全选”时,列表中所有的项目都 ...
随机推荐
- SSH和SFTP是否相同
SSH和SFTP是否相同?SSH和SFTP是经典的对.在确保通信安全方面,它们交织在一起,尽管它们具有类似的功能,但它们并不是一回事.那么,它们之间有什么区别?请仔细阅读,找出答案. 什么是SSH? ...
- 用cmd检查端口关闭命令
1.进入cmd 2.netstat -o -n -a | findstr :8080 TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 3116 3.taskkill /F / ...
- Redis高可用之战:主从架构
★ Redis24篇集合 1 主从模式介绍 在笔者的另外两篇文章 <Redis系列:RDB内存快照提供持久化能力>.<Redis稳定性之战:AOF日志支撑数据持久化>中,我们介 ...
- Games101:作业6
说明 本次作业主要实现对上一次作业代码的重构以及使用BVH加速求交的交点判断和递归调用 代码框架的修改 有影响的改动就是框架中定义了两个结构体一个是光线ray,一个是交点Intersection 交点 ...
- ArrayList,LinkedList,Vector三者的区别
List 中元素是有序的,元素可以重复,因为该集合体有索引 ArrayList: 底层数据结构是数组,查询快,增删慢. 线程不安全,效率高. 当元素放满了后,默认以原长度的 50%+1 的长度加长集合 ...
- #模拟#洛谷 5957 [POI2017]Flappy Bird
题目 分析 小鸟所在坐标的奇偶性一定相同, 考虑每次维护一个可行区间表示小鸟在当前列可以进入的纵坐标区间, 那么它有\(x_i-x_{i-1}\)的纵坐标最大改变差,然后根据奇偶性以及限制区间缩小范围 ...
- 基于vue3的Crontab组件
网上找的没有满意的,决定从若依前后端分离其前端vue2中的crontab进行转换,先上效果 若依: 改后: v2转v3没什么难度,其中有大量的将 this.*** 替换为 ***.value,笔者写了 ...
- Kubernetes(K8S)命令指南
本文提供了一份全面的Kubernetes(K8S)命令指南,旨在帮助用户掌握和运用K8S的各种命令. 关注[TechLeadCloud],分享互联网架构.云服务技术的全维度知识.作者拥有10+年互联网 ...
- 【直播预告】今晚7点,来HarmonyOS极客松直播间与技术专家聊聊新技术!
- CentOS 6.5 ZIP、RAR文件压缩解压操作详解
============zip文件的操作================= zip -r data.zip data 解释:将data文件夹压缩成了data.zip格式. unzip data.z ...