WPF實(shí)現(xiàn)帶全選復(fù)選框的列表控件
本文將說明如何創(chuàng)建一個(gè)帶全選復(fù)選框的列表控件。其效果如下圖:
這個(gè)控件是由一個(gè)復(fù)選框(CheckBox)與一個(gè) ListView 組合而成。它的操作邏輯:
- 當(dāng)選中“全選”時(shí),列表中所有的項(xiàng)目都會(huì)被選中;反之,取消選中“全選”時(shí),所有項(xiàng)都會(huì)被取消勾選。
- 在列表中選中部分?jǐn)?shù)據(jù)項(xiàng)目時(shí),“全選”框會(huì)呈現(xiàn)不確定狀態(tài)(Indetermine)。
由此看出,“全選”復(fù)選框與列表項(xiàng)中的復(fù)選框達(dá)到了雙向控制的效果。
其設(shè)計(jì)思路:首先,創(chuàng)建自定義控件(CheckListView),在其 ControlTemplate 中定義 CheckBox 和 ListView,并為 ListView 設(shè)置 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>
其次,為控件添加兩個(gè)依賴屬性,其中一個(gè)為 ItemsSource,即該控件所要接收的數(shù)據(jù)源,也即選擇列表;本質(zhì)上,這個(gè)數(shù)據(jù)源會(huì)指定給其內(nèi)的 ListView。另外也需要一個(gè)屬性 IsSelectAllChecked 表示是否選中全選復(fù)選框。
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> /// 返回或設(shè)置全選復(fù)選框的選中狀態(tài) /// </summary> public bool? IsSelectAllChecked { get { return (bool?)GetValue(IsSelectAllCheckedProperty); } set { SetValue(IsSelectAllCheckedProperty, value); } } /// <summary> /// 數(shù)據(jù)源 /// </summary> public object ItemsSource { get { return (object)GetValue(ItemsSourceProperty); } set { SetValue(ItemsSourceProperty, value); } }
需要注意的一點(diǎn)是,作為一個(gè)自定義控件,我們必須考慮它的通用性,所以為了保證能設(shè)置各式各樣的數(shù)據(jù)源(如用戶列表、物品列表或 XX名稱列表),在這里定義一個(gè)數(shù)據(jù)接口,只要數(shù)據(jù)源中的數(shù)據(jù)項(xiàng)實(shí)現(xiàn)該接口,即可達(dá)到通用的效果。該接口定義如下:
public interface ICheckItem { /// <summary> /// 當(dāng)前項(xiàng)是否選中 /// </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>
接下來,實(shí)現(xiàn)具體操作:
首先,通過“全選”復(fù)選框來控制所有列表項(xiàng):這里通過其 Click 事件來執(zhí)行 CheckAllItems 方法, 在此方法中,會(huì)對(duì)數(shù)據(jù)源進(jìn)行遍歷,將其 IsSelected 屬性設(shè)置為 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; } }
然后,通過選中或取消選中列表項(xiàng)時(shí),更新“全選”復(fù)選框的狀態(tài):在 DataTemplate 中,我們也為 CheckBox 的 Click 事件設(shè)置了要觸發(fā)的方法 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> /// 根據(jù)當(dāng)前選擇的個(gè)數(shù)來更新全選框的狀態(tài) /// </summary> public void UpdateSelectAllState() { var items = ItemsSource as IList<ICheckItem>; if (items == null) { return; } // 獲取列表項(xiàng)中 IsSelected 值為 True 的個(gè)數(shù),并通過該值來確定 IsSelectAllChecked 的值 int count = items.Where(item => item.IsSelected).Count(); if (count == items.Count) { IsSelectAllChecked = true; } else if (count == 0) { IsSelectAllChecked = false; } else { IsSelectAllChecked = null; } }
這里也有兩點(diǎn)需要提醒:
我一開始定義屬性 IsSelectAllChecked 時(shí),它的類型是 bool 類型,那么,由于 CheckBox 控件的 IsChecked 值為 null 時(shí),它將呈現(xiàn) Indetermine 狀態(tài),所以后來把它改為 bool? 類型。
在XAML 代碼中可以看出,對(duì)事件以及事件的響應(yīng)使用了行為,所以,需要添加引用 System.Windows.Interactivity.dll 和 Microsoft.Expression.Interactions.dll 兩個(gè)庫(kù),并在XMAL 頭部添加如下命名空間的引用:
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
這樣,這個(gè)控件就基本完成了,接下來是如何使用它。
首先,定義將要在列表中展示的數(shù)據(jù)項(xiàng),并為它實(shí)現(xiàn)之前提到的 ICheckItem 接口,這里定義了一個(gè) 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 中定義一個(gè)列表 List<ICheckItem>,并添加數(shù)據(jù),最后在 UI 上為其綁定 ItemsSource 屬性即可,在此不再貼代碼了,具體請(qǐng)參考源代碼。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- WPF自定義控件和樣式之自定義按鈕(Button)
- WPF如何自定義TabControl控件樣式示例詳解
- 超炫酷的WPF實(shí)現(xiàn)Loading控件效果
- WPF的ListView控件自定義布局用法實(shí)例
- 在WPF中動(dòng)態(tài)加載XAML中的控件實(shí)例代碼
- C# 使用WPF 用MediaElement控件實(shí)現(xiàn)視頻循環(huán)播放
- WPF自定義TreeView控件樣式實(shí)現(xiàn)QQ聯(lián)系人列表效果
- WPF實(shí)現(xiàn)ScrollViewer滾動(dòng)到指定控件處
- WPF開發(fā)技巧之花式控件功能擴(kuò)展詳解
相關(guān)文章
Asp.net Mvc 身份驗(yàn)證、異常處理、權(quán)限驗(yàn)證(攔截器)實(shí)現(xiàn)代碼
本問主要介紹asp.net的身份驗(yàn)證機(jī)制及asp.net MVC攔截器在項(xiàng)目中的運(yùn)用?,F(xiàn)在讓我們來模擬一個(gè)簡(jiǎn)單的流程:用戶登錄》權(quán)限驗(yàn)證》異常處理2012-10-10.net生成縮略圖及水印圖片時(shí)出現(xiàn)GDI+中發(fā)生一般性錯(cuò)誤解決方法
這篇文章主要介紹了.net生成縮略圖及水印圖片時(shí)出現(xiàn)GDI+中發(fā)生一般性錯(cuò)誤解決方法 ,需要的朋友可以參考下2014-11-11利用ASP.NET MVC+Bootstrap搭建個(gè)人博客之praise.js點(diǎn)贊特效插件(二)
這篇文章主要介紹了利用ASP.NET和MVC+Bootstrap搭建個(gè)人博客之praise.js點(diǎn)贊特效插件(二)的相關(guān)資料,需要的朋友可以參考下2016-06-06在?.NET?平臺(tái)使用?ReflectionDynamicObject?優(yōu)化反射調(diào)用的代碼詳解
這篇文章主要介紹了在?.NET?平臺(tái)使用?ReflectionDynamicObject?優(yōu)化反射調(diào)用代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03利用IIS調(diào)試ASP.NET網(wǎng)站程序的完整步驟
這篇文章主要給大家介紹了關(guān)于利用IIS調(diào)試ASP.NET網(wǎng)站程序的完整步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11Asp.Net模擬表單提交數(shù)據(jù)和上傳文件的實(shí)現(xiàn)代碼
這篇文章主要介紹了Asp.Net模擬表單提交數(shù)據(jù)和上傳文件的實(shí)現(xiàn)代碼,本文對(duì)3種情況都做了介紹,只有普通數(shù)據(jù)的表單、只上傳文件的表單、包含普通數(shù)據(jù)和上傳文件表單,需要的朋友可以參考下2014-08-08MVC使用Log4Net進(jìn)行錯(cuò)誤日志記錄學(xué)習(xí)筆記4
這篇文章主要為大家詳細(xì)介紹了MVC使用Log4Net進(jìn)行錯(cuò)誤日志記錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09如此高效通用的分頁(yè)存儲(chǔ)過程是帶有sql注入漏洞的zt
通常大家都會(huì)認(rèn)為存儲(chǔ)過程可以避免sql注入的漏洞,這適用于一般的存儲(chǔ)過程,而對(duì)于通用分頁(yè)存儲(chǔ)過程是不適合的,請(qǐng)看下面的代碼和分析!2010-07-07瀏覽器窗口滾動(dòng)加載數(shù)據(jù)采用異步形式從后臺(tái)加載數(shù)據(jù)
在滾動(dòng)條距頂部距離(頁(yè)面超出窗口的高度)時(shí)采用異步形式從后臺(tái)加載數(shù)據(jù),下面是具體的實(shí)現(xiàn),希望對(duì)大家有所幫助2014-01-01