WPF: 实现带全选复选框的列表控件
本文将说明如何创建一个带全选复选框的列表控件。其效果如下图:

这个控件是由一个复选框(CheckBox)与一个 ListView 组合而成。它的操作逻辑:
- 当选中“全选”时,列表中所有的项目都会被选中;反之,取消选中“全选”时,所有项都会被取消勾选。
- 在列表中选中部分数据项目时,“全选”框会呈现不确定状态(Indetermine)。
由此看出,“全选”复选框与列表项中的复选框达到了双向控制的效果。
其设计思路:首先,创建自定义控件(CheckListView),在其 ControlTemplate 中定义 CheckBox 和 ListView,并为 ListView 设置 ItemTemplate,在其中增加 CheckBox 控件,如下:
<ControlTemplate TargetType="{x:Type control:CheckListView}">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CheckBox Content="全选" />
<ListView x:Name="list"
Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ControlTemplate>
其次,为控件添加两个依赖属性,其中一个为 ItemsSource,即该控件所要接收的数据源,也即选择列表;本质上,这个数据源会指定给其内的 ListView。另外也需要一个属性 IsSelectAllChecked 表示是否选中全选复选框。
public static readonly DependencyProperty IsSelectAllCheckedProperty =
DependencyProperty.Register("IsSelectAllChecked", typeof(bool?), typeof(CheckListView), new PropertyMetadata(false)); public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(object), typeof(CheckListView), new PropertyMetadata(null)); /// <summary>
/// 返回或设置全选复选框的选中状态
/// </summary>
public bool? IsSelectAllChecked
{
get { return (bool?)GetValue(IsSelectAllCheckedProperty); }
set { SetValue(IsSelectAllCheckedProperty, value); }
} /// <summary>
/// 数据源
/// </summary>
public object ItemsSource
{
get { return (object)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
需要注意的一点是,作为一个自定义控件,我们必须考虑它的通用性,所以为了保证能设置各式各样的数据源(如用户列表、物品列表或 XX名称列表),在这里定义一个数据接口,只要数据源中的数据项实现该接口,即可达到通用的效果。该接口定义如下:
public interface ICheckItem
{
/// <summary>
/// 当前项是否选中
/// </summary>
bool IsSelected { get; set; } /// <summary>
/// 名称
/// </summary>
string Name { get; set; }
}
最后,我们把刚才定的属性绑定的控件上,如下:
<CheckBox Content="全选" IsChecked="{Binding IsSelectAllChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
<ListView x:Name="list"
Grid.Row="1"
ItemsSource="{TemplateBinding ItemsSource}">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
接下来,实现具体操作:
首先,通过“全选”复选框来控制所有列表项:这里通过其 Click 事件来执行 CheckAllItems 方法, 在此方法中,会对数据源进行遍历,将其 IsSelected 属性设置为 True 或 False。代码如下:
<CheckBox Content="全选" IsChecked="{Binding IsSelectAllChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction MethodName="CheckAllItems" TargetObject="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
/// <summary>
/// 全选或清空所用选择
/// </summary>
public void CheckAllItems()
{
foreach (ICheckItem item in ItemsSource as IList<ICheckItem>)
{
item.IsSelected = IsSelectAllChecked.HasValue ? IsSelectAllChecked.Value : false;
}
}
然后,通过选中或取消选中列表项时,更新“全选”复选框的状态:在 DataTemplate 中,我们也为 CheckBox 的 Click 事件设置了要触发的方法 UpdateSelectAllState,代码如下:
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction MethodName="UpdateSelectAllState" TargetObject="{Binding RelativeSource={RelativeSource AncestorType=control:CheckListView}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
/// <summary>
/// 根据当前选择的个数来更新全选框的状态
/// </summary>
public void UpdateSelectAllState()
{
var items = ItemsSource as IList<ICheckItem>;
if (items == null)
{
return;
} // 获取列表项中 IsSelected 值为 True 的个数,并通过该值来确定 IsSelectAllChecked 的值
int count = items.Where(item => item.IsSelected).Count();
if (count == items.Count)
{
IsSelectAllChecked = true;
}
else if (count == )
{
IsSelectAllChecked = false;
}
else
{
IsSelectAllChecked = null;
}
}
这里也有两点需要提醒:
- 我一开始定义属性 IsSelectAllChecked 时,它的类型是 bool 类型,那么,由于 CheckBox 控件的 IsChecked 值为 null 时,它将呈现 Indetermine 状态,所以后来把它改为 bool? 类型。
- 在XAML 代码中可以看出,对事件以及事件的响应使用了行为,所以,需要添加引用 System.Windows.Interactivity.dll 和 Microsoft.Expression.Interactions.dll 两个库,并在XMAL 头部添加如下命名空间的引用:
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
这样,这个控件就基本完成了,接下来是如何使用它。
首先,定义将要在列表中展示的数据项,并为它实现之前提到的 ICheckItem 接口,这里定义了一个 User 类,如下:
public class User : BindableBase, ICheckItem
{
private bool isSelected;
private string name; public bool IsSelected
{
get { return isSelected; }
set { SetProperty(ref isSelected, value); }
} public string Name
{
get { return name; }
set { SetProperty(ref name, value); }
}
}
接下来在 ViewModel 中定义一个列表 List<ICheckItem>,并添加数据,最后在 UI 上为其绑定 ItemsSource 属性即可,在此不再贴代码了,具体请参考源代码。
如果您有实现此控件的其它方式,欢迎提出您的建议或评论。
WPF: 实现带全选复选框的列表控件的更多相关文章
- WPF实现带全选复选框的列表控件
本文将说明如何创建一个带全选复选框的列表控件.其效果如下图: 这个控件是由一个复选框(CheckBox)与一个 ListView 组合而成.它的操作逻辑: 当选中“全选”时,列表中所有的项目都会被选中 ...
- QTableWidget自定义表头QHeaderView加全选复选框
1 QTableWidget自定义表头QHeaderView加全选复选框 在使用QTableWidget时需要在表头添加全选复选框,但是默认的表头无法添加复选框,只能用图片画上去一个复 ...
- ExtJS中,将Grid表头中的全选复选框取消复选
今天发现公司产品用的EXTJS中使用Grid时,Grid表头中的全选复选框的选中状态不是很准确,就写了这个小扩展 在js中加入下面方法,在需要取消全选的地方调用即可,例:Ext.getCmp('gri ...
- [原创]纯JS实现网页中多选复选框checkbox和单选radio的美化效果
图片素材: 最终效果图: <html><title> 纯JS实现网页中多选复选框checkbox和单选radio的美化效果</title><head>& ...
- java freemarker导出word时添加或勾选复选框
最近项目导出word碰到一个需求,要求根据数据动态的决定word里的复选框是否勾选, 公司导出word用的是freemarker,相比较其他技术,freemarker可以很容易的控制输出样式, 在wo ...
- JS-001-单选复选按钮操作
此文主要针对 web 页面中常见元素(例如:单选按钮.复选按钮)的 JavaScript 操作,进行简单的源码示例演示,敬请小主们参阅.若有不足之处,敬请大神指正,不胜感激! 话不多言了,直接上码: ...
- iOS开发-UITableView单选多选/复选实现1
TableView怎样实现单选或者多选呢? 我们的直接思路是改动某一个Cell的样式就可以, 那么改动样式须要通过改动相应的数据, 从这里能够判断我们须要给Cell相应的数据设置一个标志位, 当选中的 ...
- Asp.net绑定带层次下拉框(select控件)
1.效果图 2.数据库中表数据结构 3.前台页面 <select id="pid" runat="server" style="width:16 ...
- WPF进阶技巧和实战03-控件(3-文本控件及列表控件)
系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...
随机推荐
- 项目设计day1
项目内容:一个实时监控斗鱼TV某个主播弹幕的设计 通过python爬虫获取当前弹幕,通过flume采集数据,接下来数据分为线上和线下两种方案: 线上:实时分析,分为两种方案:(1) flume+kaf ...
- jQuery-少见获取元素的方式
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- C#.NET开源项目、机器学习、Power BI
[总目录]本博客博文总目录-实时更新 阅读目录 1.开源Math.NET基础数学类库使用系列 2.C#操作Excel组件Spire.XLS文章目录 3.彩票数据资料库文章 4.数据挖掘与机器学习相 ...
- CSS常见布局问题整理
实现div的水平居中和垂直居中 多元素水平居中 实现栅格化布局 1. 实现div的水平居中和垂直居中 实现效果: 这大概是最经典的一个题目了,所以放在第一个. 方法有好多, 一一列来 主要思路其实就是 ...
- Windows环境下MySQL 5.6安装与配置
1将MySQL压缩包解压到自定义目录下. 2.添加环境变量 右键单击我的电脑->属性->高级系统设置(高级)->环境变量. 点击系统变量下的新建按钮 1) 输入变量名:MYSQ ...
- 实用:Git 中的一些常见错误
无论是数据科学家.算法工程师还是普通开发人员,在每个团队协作开发任务中,Git 都是必不可少的版本控制工具,因此掌握它的基本操作十分有必要.但即便是教程满天飞的今天,开发人员在使用 Git 时也还是会 ...
- 微信小程序的概要
微信小程序的概要 学习小程序要了解一下什么事小程序,小程序开发前需要做哪些准备,微信小程序开发工具的使用,小程序中的目录结构解析,视图和渲染,事件. 小程序的配置详解,小程序的生命周期与app对象的使 ...
- 把ajax包装成promise的形式(2)
概述 为了体验promise的原理,我打算自己把ajax包装成promise的形式.主要希望实现下列功能: // 1.使用success和error进行链式调用,并且可以在后面加上无限个 promis ...
- css3动画:transition和animation
概述 之前写过css3 动画与display:none冲突的解决方案,但是最近却发现,使用animation效果比transition好得多,而且不和display:none冲突.下面我把相关新的记录 ...
- 在谷歌安装扩展程序Axure RP Extension for Chrome后,经常无故损坏,无法使用
最近因为要看需求给的原型图,但需求只给了html格式的文件,没有给可以在Axure软件里看的格式, 所以在谷歌安装了一个Axure RP Extension for Chrome扩展程序在谷歌浏览器看 ...