在 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 代码看起来简单

本文所有代码放在 githubgitee 欢迎小伙伴访问

参考

本文以上方法参考了如下博客

c# - CompositeCollection + CollectionContainer: Bind CollectionContainer.Collection to property of ViewModel that is used as DataTemplates DataType - Stack Overflow

wpf - How do you bind a CollectionContainer to a collection in a view model? - Stack Overflow

WPF 很少人知道的科技 - walterlv

WPF 列表控件数据源绑定多个数据集合方法的更多相关文章

  1. ASP .NET MVC HtmlHelper扩展——简化“列表控件”的绑定

    在众多表单元素中,有一类<select>元素用于绑定一组预定义列表.传统的ASP.NET Web Form中,它对应着一组重要的控件类型,即ListControl,我们经常用到DropDo ...

  2. 在Bootstrap开发框架中使用dataTable直接录入表格行数据(2)--- 控件数据源绑定

    在前面随笔<在Bootstrap开发框架中使用dataTable直接录入表格行数据>中介绍了在Web页面中使用Jquery DataTable插件进行对数据直接录入操作,这种处理能够给用户 ...

  3. C#.NET 通用控件数据源绑定类

    using System.Data; using System.Collections; using System.Collections.Generic; using System.Web.UI; ...

  4. WPF Image控件的绑定

    在我们平时的开发中会经常用到Image控件,通过设置Image控件的Source属性,我们可以加载图片,设置Image的source属性时可以使用相对路径也可以使用绝对路径,一般情况下建议使用绝对路径 ...

  5. WPF 列表控件中的子控件上下文绑定

    <DataGrid Grid.ColumnSpan=" Height="Auto" SelectedItem="{Binding Path=SelectP ...

  6. silverlight列表控件ComboBox 托管代码绑订数据集合

    .xaml <ComboBox x:Name="myCombobox" Width="300" Height="30"> < ...

  7. .NET各大平台数据列表控件绑定原理及比较(WebForm、Winform、WPF)

    说说WebForm: 数据列表控件: WebForm 下的列表绑定控件基本就是GridView.DataList.Repeater:当然还有其它DropDownList.ListBox等. 它们的共同 ...

  8. WPF DevExpress Chart控件 界面绑定数据源,不通过C#代码进行绑定

    <Grid x:Name="myGrid" Loaded="Grid_Loaded" DataContext="{Binding PartOne ...

  9. 【WPF开发备忘】使用MVVM模式开发中列表控件内的按钮事件无法触发解决方法

    实际使用MVVM进行WPF开发的时候,可能会用到列表控件中每行一个编辑或删除按钮,这时直接去绑定,发现无法响应: <DataGridTemplateColumn Header="操作& ...

  10. WPF: 实现带全选复选框的列表控件

    本文将说明如何创建一个带全选复选框的列表控件.其效果如下图:     这个控件是由一个复选框(CheckBox)与一个 ListView 组合而成.它的操作逻辑: 当选中“全选”时,列表中所有的项目都 ...

随机推荐

  1. 记录-Symbol学习笔记

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 Symbol是JavaScript中的原始数据类型之一,它表示一个唯一的.不可变的值,通常用作对象属性的键值.由于Symbol值是唯一的, ...

  2. JavaScript知识总结 异步编程篇

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1. 异步编程的实现方式? JavaScript中的异步机制可以分为以下几种: 回调函数 的方式,使用回调函数的方式有一个缺点是,多个回调 ...

  3. 记录--六道题理解Vue2 和 Vue3 的响应式原理比对

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 技术栈是 Vue 的同学,在面试中难免会被问到 Vue2 和 Vue3 的相关知识点的实现原理和比较,面试官是步步紧逼,一环扣一环. ...

  4. C# Demo 资源汇总

    1.OCR 相关OCRService Onnx版 https://lw112190.blog.csdn.net/article/details/132082357 OCRService Sdcb.Pa ...

  5. Unable to load library ‘xxx‘: 找不到指定的模块。找不到指定的模块。 Can‘t obtain InputStream for win32-x86-64/xxx.dll

    我使用的是 <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</a ...

  6. 什么是GRAY色彩空间

    GRAY色彩空间通常指的是灰度图像,灰度图像是一种每个像素都是从黑到白,被处理为256个灰度级别的单色图像.这256个灰度级别分别用区间[0,255]中的数值表示,其中,"0"表示 ...

  7. kafka集群启动命令脚本文件kf.sh

    注意代码缩进 添加执行权限 chmod +x kf.sh 1 #! /bin/bash 2 case $1 in 3 "start"){ 4 for i in hadoop102 ...

  8. 如何保证MySQL和Redis数据一致性?

    背景 在高并发的业务场景中,因为MySQL数据库是操作磁盘效率比较低,因此大多数情况下数据库都是高并发系统的瓶颈.因为Redis操作数据是在内存中进行,所以就需要使用Redis做一个缓存.让请求先访问 ...

  9. 从bootstrap源码中学习Sass(一)

    可以在github看代码,非常方便:https://github.com/twbs/bootstrap/blob/main/scss/_variables.scss 就是有时候网络差. 基础用法 sc ...

  10. java中的内部类内部接口详解

    目录 简介 内部类 静态内部类 非静态内部类 静态方法内部类 非静态方法的内部类 匿名类 内部接口 总结 简介 一般来说,我们创建类和接口的时候都是一个类一个文件,一个接口一个文件,但有时候为了方便或 ...