当前位置: 移动技术网 > IT编程>开发语言>.net > WPF实现带全选复选框的列表控件

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

2017年12月08日  | 移动技术网IT编程  | 我要评论

宿迁加油站闹鬼,滚动条颜色,讷河到哈尔滨火车

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


这个控件是由一个复选框(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 == 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 属性即可,在此不再贴代码了,具体请参考源代码。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网