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

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


    这个控件是由一个复选框(CheckBox)与一个 ListView 组合而成。它的操作逻辑:

  • 当选中“全选”时,列表中所有的项目都会被选中;反之,取消选中“全选”时,所有项都会被取消勾选。
  • 在列表中选中部分数据项目时,“全选”框会呈现不确定状态(Indetermine)。

由此看出,“全选”复选框与列表项中的复选框达到了双向控制的效果。

其设计思路:首先,创建自定义控件(CheckListView),在其 ControlTemplate 中定义 CheckBox 和 ListView,并为 ListView 设置 ItemDataTemplate,在其中增加 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>

其次,为控件添加两个依赖属性,其中一个为 ItemSource,即该控件所要接收的数据源,也即选择列表;本质上,这个数据源会指定给其内的 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 == 0)
            {
                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 属性即可,在此不再贴代码了,具体请参考源代码。

如果您有实现此控件的其它方式,欢迎指教、评论。

源代码下载

时间: 2024-12-18 07:50:00

WPF: 实现带全选复选框的列表控件的相关文章

全选复选框做法

全选复选框 js方法 function CheckAll(){ var qx = document.getElementById("qx").checked; var ck = document.getElementsByClassName("qx"); for(var i=0; i<ck.length;i++) { ck[i].checked = qx; } } jQuery方法: $(document).ready(function(e) { $(&quo

全选复选框

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title&

jquery 循环遍历选中的多选复选框checkbox

1多选复选框 <input type=checkbox  name=id value=${entity.id}> 2.循环遍历 var courseIdList = []; var $courseList = $('input[type="checkbox"]:checked'); $courseList.each(function() { courseIdList.push($(this).prop('value')); });

勾选复选框按钮可用否则不可用

勾选复选框按钮可用否则不可用 function check(){ var chec=document.getElementById("chec"); if(chec.checked==true){ alert(1111) document.getElementById("btn").removeAttribute("disabled") }else{ alert(22222) document.getElementById("btn&q

iOS开发-UITableView单选多选/复选实现1

TableView如何实现单选或者多选呢? 我们的直接思路是修改某一个Cell的样式即可, 那么修改样式需要通过修改对应的数据, 从这里可以推断我们需要给Cell对应的数据设置一个标志位, 当选中的时候来修改该标志位刷新那一行即可 如果是单选实现稍微复杂一些: 单选需要设置一个属性来保存上一次选中的行, 待选中新的行之后需要修改该行,不断维护 我的实现如下: (1)创建一个TableViewController, 为了简单使用系统的Cell样式 设置重用标识符为 ACELL cell对应的Mod

Jquery+json绑定带层次下拉框(select控件)

一.实现的效果图 二.主要代码 html代码 <select id="pid" runat="server"> <option value="0" data="|0|">不选父级类</option> </select> Jquery代码 var html = ['<option value="0">不选父级模块</option>'];

Asp.net绑定带层次下拉框(select控件)

1.效果图 2.数据库中表数据结构 3.前台页面 <select id="pid" runat="server"> <option value="0" data="|0|">不选父级类</option> </select> 备注:查看源代码 4.后台代码 using System; using System.Data; using System.Web.UI.WebControl

iOS_book 02 - 基本交互(约束、视图控制器、基本控件:按钮、文本框、分段控件、开关、标签、图像控件)

实现基本交互 MVC模式 Cocoa Touch 设计者们采用MVC(Model-View-Controller, 模型 - 视图 - 控制器)模式作为指导原则. MVC 模式把代码功能划分为3个不同的类别. 模型: 保存应用程序数据的类. 视图:包括窗口.控件以及其他一些用户可以看到并能与之交互的元素. 控制器:把模型和视图绑定在一起的代码,包括处理用户输入的应用程序逻辑. MVC的目标最大限度地分离这三类代码.MVC可以帮助确保代码的最大可重用性. 控制器组件通常有应用程序的具体类组成.控制

selenium处理富文本框,日历控件等 调用JS修改value值

http://blog.csdn.net/fudax/article/details/8089404 document.getElementById("js_domestic_fromdate").value = "2014-10-10" selenium处理富文本框,日历控件等 调用JS修改value值,布布扣,bubuko.com