淺談WPF之DataGrid過濾,分組,排序

来源:https://www.cnblogs.com/hsiang/archive/2023/12/22/17920372.html
-Advertisement-
Play Games

使用過Excel的用戶都知道,Excel可以方便的對數據進行分組,過濾,排序等操作,而在WPF中,預設提供的DataGrid只有很簡單的功能,那麼如何才能讓我們開發的DataGrid,也像Excel一樣具備豐富的客戶端操作呢?今天就以一個簡單的小例子,簡述如何在WPF中實現DataGrid的過濾,篩... ...


使用過Excel的用戶都知道,Excel可以方便的對數據進行分組,過濾,排序等操作,而在WPF中,預設提供的DataGrid只有很簡單的功能,那麼如何才能讓我們開發的DataGrid,也像Excel一樣具備豐富的客戶端操作呢?今天就以一個簡單的小例子,簡述如何在WPF中實現DataGrid的過濾,篩選,排序等功能。僅供學習分享使用,如有不足之處,還請指正。

涉及知識點

在本示例中,涉及知識點如下所示:

  1. CollectionView, CollectionView 類為實現 IEnumerable 介面的數據源提供分組和排序功能。
  2. CollectionViewSource,CollectionViewSource 類允許你從 XAML 設置 CollectionView 的屬性。

註意:此兩個類,是我們實現客戶端過濾,分組,排序的關鍵。

 

普通綁定

 

1. 構建數據源

 

在WPF中,DataGrid的ItemSource屬性用於綁定數據源,而數據源必須是實現IEnumerable介面的的列表類型,在本示例中,採用具有通知屬性的列表類型ObservableCollection。當列表中元素數量發生變化時,可以實時的通知DataGrid進行刷新。

1.1 創建實體

在本示例中,為了測試,創建Student實體模型,如下所示:

public class Student
{
    public string No { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public bool Sex { get; set; }

    public string Class { get; set; }
}

1.2 初始化數據源列表

在本示例採用MVVM模式開發,在ViewModel中創建ObservableCollection類型的Students列表,如下所示:

using CommunityToolkit.Mvvm.ComponentModel;
using DemoDataGrid2.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DemoDataGrid2.ViewModels
{
    public class TestWindowViewModel:ObservableObject
    {
        private ObservableCollection<Student> students;

        public ObservableCollection<Student> Students
        {
            get { return students; }
            set { SetProperty(ref students, value); }

        }
        public TestWindowViewModel()
        {
            var parentName = new string[5] { "張", "王", "李", "趙", "劉" };
            this.Students = new ObservableCollection<Student>();
            for (int i = 0; i < 100; i++)
            {
                Student student = new Student();
                student.No = i.ToString().PadLeft(3, '0');
                student.Name = parentName[(i % 4)] + i.ToString().PadLeft(2, 'A');
                student.Age = 20 + (i % 5);
                student.Sex = i % 2 == 0 ? true : false;
                student.Class = $"{(i % 3)}班";
                this.Students.Add(student);
            }
        }
    }
}

註意:構造函數中的方法,用於創建Students列表,包含100名學生,分別對應不同的編號,姓名,年齡,性別,班級等信息。

2. 頁面綁定

在ViewModel中創建數據源後,可以在Xaml中進行綁定【語法:ItemsSource="{Binding Students}"】,如下所示:

<Window x:Class="DemoDataGrid2.TestWindow"
        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:DemoDataGrid2"
        mc:Ignorable="d"
        Title="DataGrid示例" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <DockPanel Grid.Row="0">
            
        </DockPanel>
        <DataGrid Grid.Row="1" ItemsSource="{Binding Students}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="學號" Binding="{Binding No}" Width="*"></DataGridTextColumn>
                <DataGridTextColumn Header="姓名" Binding="{Binding Name}"  Width="*"></DataGridTextColumn>
                <DataGridTextColumn Header="年齡" Binding="{Binding Age}"  Width="*"></DataGridTextColumn>
                <DataGridTemplateColumn Header="性別"  Width="*">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock x:Name="sex">
                                <TextBlock.Style>
                                    <Style TargetType="TextBlock">
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding Sex}" Value="True">
                                                <Setter Property="Text" Value="男"></Setter>
                                            </DataTrigger>
                                            <DataTrigger Binding="{Binding Sex}" Value="False">
                                                <Setter Property="Text" Value="女"></Setter>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="班級" Binding="{Binding Class}"  Width="*"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

以下兩點需要註意:

  1. 在本示例中,性別為bool類型,要轉換成漢字,用到了DataTrigger。
  2. DataGrid的列可以自動生成,也可以手動創建,可以通過AutoGenerateColumns="False"來設置。

3. 普通綁定示例

普通綁定示例截圖,如下所示:

 

DataGrid過濾

在DataGrid中,實現客戶端過濾,且不需要重新初始化數據源,則需要用到CollectionViewSource。

1. 定義資源及綁定

將CollectionViewSource定義成一種資源,並將資源的Source屬性綁定到數據源,再將DataGrid中的ItemSource綁定到此資源,然後就可以在過濾時對資源進行過濾。

定義資源如下所示:

<Window.Resources>
    <CollectionViewSource x:Key="cvStudents" Source="{Binding Students}"></CollectionViewSource>
</Window.Resources>

DataGrid綁定資源【語法:ItemsSource="{Binding Source={StaticResource cvStudents}}"】,如下所示:

<DataGrid x:Name="dgStudents" Grid.Row="1" ItemsSource="{Binding Source={StaticResource cvStudents}}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" >
    <DataGrid.Columns>
        <DataGridTextColumn Header="學號" Binding="{Binding No}" Width="*"></DataGridTextColumn>
        <DataGridTextColumn Header="姓名" Binding="{Binding Name}"  Width="*"></DataGridTextColumn>
        <DataGridTextColumn Header="年齡" Binding="{Binding Age}"  Width="*"></DataGridTextColumn>
        <DataGridTemplateColumn Header="性別"  Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock x:Name="sex">
                        <TextBlock.Style>
                            <Style TargetType="TextBlock">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding Sex}" Value="True">
                                        <Setter Property="Text" Value="男"></Setter>
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding Sex}" Value="False">
                                        <Setter Property="Text" Value="女"></Setter>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </TextBlock.Style>
                    </TextBlock>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn Header="班級" Binding="{Binding Class}"  Width="*"></DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

2. 過濾條件

在本示例中,以性別為過濾條件,當點擊過濾條件時,觸發過濾命令,如下所示:

<DockPanel Grid.Row="0" Margin="5">
    <TextBlock Text="篩選條件:"></TextBlock>
    <TextBlock Text="性別:"></TextBlock>
    <CheckBox Content="男" IsChecked="{Binding FilterM.IsMaleChecked}" Command="{Binding FiterSexCheckedCommand}"></CheckBox>
    <CheckBox Content="女" IsChecked="{Binding FilterM.IsFemaleChecked}" Command="{Binding FiterSexCheckedCommand}"></CheckBox>
</DockPanel>

當用戶點擊時,觸發Command綁定的命令,如下所示:

private ICommand fiterSexCheckedCommand;

public ICommand FiterSexCheckedCommand
{
	get
	{
		if (fiterSexCheckedCommand == null)
		{
			fiterSexCheckedCommand = new RelayCommand<object>(FilterSexChecked);
		}
		return fiterSexCheckedCommand;
	}
}

private void FilterSexChecked(object obj)
{
	if (this.dataGrid != null)
	{
		ICollectionView cvs = CollectionViewSource.GetDefaultView(this.dataGrid.ItemsSource);
		if (cvs != null && cvs.CanFilter)
		{
			cvs.Filter = (object obj) =>
			{
				bool flag = true;
				bool flag1 = true;
				bool flag2 = true;
				var student = obj as Student;
				if (!FilterM.IsMaleChecked)
				{
					flag1 = student.Sex != true;
				}
				if (!FilterM.IsFemaleChecked)
				{
					flag2 = student.Sex != false;
				}
				flag = flag1 && flag2;
				return flag;
			};
		}
	}
}

註意:通過CollectionViewSource.GetDefaultView(this.dataGrid.ItemsSource)方法獲取具有過濾功能的CollectionView類對象,然後再對Filter進行委托即可。

其中FilterM是在ViewModel中聲明的FilterConditionM類型的屬性。

private FilterConditionM filterM;

public FilterConditionM FilterM
{
	get { return filterM; }
	set { SetProperty(ref filterM, value); }
}

 FilterConditionM是封裝的過濾條件模型類, 如下所示:

namespace DemoDataGrid2.Models
{
    public class FilterConditionM:ObservableObject
    {
		private bool isMaleChecked;

		public bool IsMaleChecked
		{
			get { return isMaleChecked; }
			set { SetProperty(ref isMaleChecked , value); }
		}

        private bool isFemaleChecked;

        public bool IsFemaleChecked
        {
            get { return isFemaleChecked; }
            set { SetProperty(ref isFemaleChecked, value); }
        }
    }
}

3. 過濾功能示例

具備過濾功能的示例截圖,如下所示:

 

DataGrid分組

在WPF中,實現DataGrid的分組,也是通過CollectionViewSource來實現。

1. 設置分組列

有兩種方式可以設置分組

1.1 XAML中設置

在XAML中,通過設置CollectionViewSource的GroupDescriptions屬性,來設置具體分組的列屬性,如下所示:

<CollectionViewSource x:Key="cvStudents" Source="{Binding Students}">
	<CollectionViewSource.GroupDescriptions>
		<PropertyGroupDescription PropertyName="Class"/>
		<PropertyGroupDescription PropertyName="Sex"/>
	</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

1.2 後臺代碼設置

在ViewModel中設置CollectionView的GroupDescriptions屬性,如下所示:

ICollectionView cvTasks = CollectionViewSource.GetDefaultView(this.dataGrid.ItemsSource);
if (cvTasks != null && cvTasks.CanGroup == true)
{
	cvTasks.GroupDescriptions.Clear();
	cvTasks.GroupDescriptions.Add(new PropertyGroupDescription("Class"));
	cvTasks.GroupDescriptions.Add(new PropertyGroupDescription("Sex"));
}

2. 設置分組樣式

在WPF中,通過設置DataGrid的GroupStyle屬性來改變分組樣式,如下所示:

<DataGrid x:Name="dgStudents" Grid.Row="1" ItemsSource="{Binding Source={StaticResource cvStudents}}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" >
	<DataGrid.GroupStyle>
		<!-- 第一層分組 -->
		<GroupStyle>
			<GroupStyle.ContainerStyle>
				<Style TargetType="{x:Type GroupItem}">
					<Setter Property="Margin" Value="0,0,0,5"/>
					<Setter Property="Template">
						<Setter.Value>
							<ControlTemplate TargetType="{x:Type GroupItem}">
								<Expander IsExpanded="True" Background="LightGray" BorderBrush="#FF002255" Foreground="DarkBlue" BorderThickness="1">
									<Expander.Header>
										<DockPanel>
											<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5"/>
											<TextBlock FontWeight="Bold" Text=" 班 , " VerticalAlignment="Center"></TextBlock>
											<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}" VerticalAlignment="Center"/>
											<TextBlock FontWeight="Bold" Text=" 名學生"  VerticalAlignment="Center"></TextBlock>
										</DockPanel>
									</Expander.Header>
									<Expander.Content>
										<ItemsPresenter />
									</Expander.Content>
								</Expander>
							</ControlTemplate>
						</Setter.Value>
					</Setter>
				</Style>
			</GroupStyle.ContainerStyle>
		</GroupStyle>
		<!-- 第二層及之後的分組 -->
		<GroupStyle>
			<GroupStyle.HeaderTemplate>
				<DataTemplate>
					<DockPanel Background="LightGoldenrodYellow">
						<TextBlock Foreground="Blue" Margin="30,0,0,0" Width="30">
							<TextBlock.Style>
								<Style TargetType="TextBlock">
									<Style.Triggers>
										<DataTrigger Binding="{Binding Path=Name}" Value="True">
											<Setter Property="Text" Value="男"></Setter>
										</DataTrigger>
										<DataTrigger Binding="{Binding Path=Name}" Value="False">
											<Setter Property="Text" Value="女"></Setter>
										</DataTrigger>
									</Style.Triggers>
								</Style>
							</TextBlock.Style>
						</TextBlock>
						<TextBlock Text="{Binding Path=ItemCount}" Foreground="Blue"/>
					</DockPanel>
				</DataTemplate>
			</GroupStyle.HeaderTemplate>
		</GroupStyle>
	</DataGrid.GroupStyle>
	<DataGrid.Columns>
		<DataGridTextColumn Header="學號" Binding="{Binding No}" Width="*"></DataGridTextColumn>
		<DataGridTextColumn Header="姓名" Binding="{Binding Name}"  Width="*"></DataGridTextColumn>
		<DataGridTextColumn Header="年齡" Binding="{Binding Age}"  Width="*"></DataGridTextColumn>
		<DataGridTemplateColumn Header="性別"  Width="*">
			<DataGridTemplateColumn.CellTemplate>
				<DataTemplate>
					<TextBlock x:Name="sex">
						<TextBlock.Style>
							<Style TargetType="TextBlock">
								<Style.Triggers>
									<DataTrigger Binding="{Binding Sex}" Value="True">
										<Setter Property="Text" Value="男"></Setter>
									</DataTrigger>
									<DataTrigger Binding="{Binding Sex}" Value="False">
										<Setter Property="Text" Value="女"></Setter>
									</DataTrigger>
								</Style.Triggers>
							</Style>
						</TextBlock.Style>
					</TextBlock>
				</DataTemplate>
			</DataGridTemplateColumn.CellTemplate>
		</DataGridTemplateColumn>
		<DataGridTextColumn Header="班級" Binding="{Binding Class}"  Width="*"></DataGridTextColumn>
	</DataGrid.Columns>
</DataGrid>

 

DataGrid排序

在WPF中,實現DataGrid的排序,也是通過CollectionViewSource來實現。

1. 設置排序列

有兩種方式可以設置DataGrid排序列,如下所示:

1.1 XAML中設置

通過設置CollectionViewSource的SortDescriptions屬性,設置排序列和排序方向。如下所示:

<CollectionViewSource x:Key="cvStudents" Source="{Binding Students}">
	<CollectionViewSource.SortDescriptions>
		<scm:SortDescription PropertyName="No" Direction="Ascending"/>
		<scm:SortDescription PropertyName="Age" Direction="Descending"/>
	</CollectionViewSource.SortDescriptions>
</CollectionViewSource>

 其中scm是新定義的命名空間【xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"】

 

1.2 後臺代碼設置

在ViewModel中通過後臺代碼設置,同樣也需要引入對應的命名空間,如下所示:

ICollectionView cvTasks = CollectionViewSource.GetDefaultView(this.dataGrid.ItemsSource);
if (cvTasks != null && cvTasks.CanSort == true)
{
	cvTasks.SortDescriptions.Clear();
	cvTasks.SortDescriptions.Add(new SortDescription("No", ListSortDirection.Ascending));
	cvTasks.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Ascending));
}

DataGrid整體示例

具備過濾,分組,排序的示例截圖,如下所示:

參考文獻

1. 官方文檔:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/how-to-group-sort-and-filter-data-in-the-datagrid-control?view=netframeworkdesktop-4.8

 

以上就是【淺談WPF之DataGrid過濾,分組,排序】的全部內容,希望能夠一起學習,共同進步。


作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Python 介紹 Python 是一種 高級 的、解釋型 的、通用 的編程語言。其設計哲學強調代碼的可讀性,使用顯著的縮進。Python 是 動態類型 和 垃圾收集 的。 基本語法 設置 Python 環境並開始基礎知識。 文章鏈接:Python 安裝與快速入門 變數 變數用於存儲在電腦程式中引 ...
  • 平時習慣了./和../作為訪問目錄的路徑,但今天使用golang中fs.ReadDir這個函數的時候發現這個習慣是不正確的。 但是常用的命令並沒有分很清楚.和./ 在這幾個命令中使用.或./都可以到達目錄下 ls cd 錯誤示範 package main import ( "fmt" "io/fs" ...
  • 數據的預處理是數據分析,或者機器學習訓練前的重要步驟。通過數據預處理,可以 提高數據質量,處理數據的缺失值、異常值和重覆值等問題,增加數據的準確性和可靠性 整合不同數據,數據的來源和結構可能多種多樣,分析和訓練前要整合成一個數據集 提高數據性能,對數據的值進行變換,規約等(比如無量綱化),讓演算法更加 ...
  • 在實際的業務開發中,我們經常會碰到VO、BO、PO、DTO等對象屬性之間的賦值,當屬性較多的時候我們使用get,set的方式進行賦值的工作量相對較大,因此很多人會選擇使用spring提供的拷貝工具BeanUtils的copyProperties方法完成對象之間屬性的拷貝。通過這種方式可以很大程度上降... ...
  • 馬哥原創:小紅書詳情採集軟體,自動爬取xhs筆記的詳情數據,欄位含:筆記id,筆記鏈接,筆記標題,筆記內容,筆記類型,發佈時間,修改時間,IP屬地,點贊數,收藏數,評論數,轉發數,用戶昵稱,用戶id,用戶主頁鏈接。 ...
  • 內網代理可以實現不想暴露太多信息給外部,但是又能提供內部的完整信息支持,相當於建立了一條可用的HTTP通道。可以在有這方面需求的人優化網路結構。 ...
  • Qt 是一個跨平臺C++圖形界面開發庫,利用Qt可以快速開發跨平臺窗體應用程式,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實現圖形化開發極大的方便了開發效率,本章將重點介紹`StandardItemModel`數據模型組件的常用方法及靈活運用。`QStandardItemModel` ... ...
  • 根據上一篇博客可知,單純的通過求取最大面積而進行定位的局限性,因此我們接下來將通過cv2.moments()和cv2.HuMoments()這兩個方法來在更複雜的環境中去找到我們的目標區域。 cv2.moments(): 參數: array:表示輸入圖像的單通道數組。通常是灰度圖像,可以是8位或浮點 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...