当前位置:   article > 正文

让WPF中的DataGrid像Excel一样可以筛选_wpf datagrid用代码按条件选择多行

wpf datagrid用代码按条件选择多行

在默认情况下,WPF提供的DataGrid仅拥有数据展示等简单功能,如果要实现像Excel一样复杂的筛选过滤功能,则相对比较麻烦。本文以一个简单的小例子,简述如何通过WPF实话DataGrid的筛选功能,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点


在本示例中,从数据绑定,到数据展示,涉及知识点如下所示:

  • DataGrid,要WPF提供的进行二维数据展示在列表控件,默认功能非常简单,但是可以通过数据模板或者控件模板进行扩展和美化,可伸缩性很强。
  • MVVM,是Model-View-ViewModel的简写,主要进行数据和UI进行前后端分离,在本示例中,主要用到的MVVM第三方库为CommunityToolkit.Mvvm,大大简化原生MVVM的实现方式。
  • 集合视图, 要对 DataGrid 中的数据进行分组、排序和筛选,可以将其绑定到支持这些函数的 CollectionView。 然后,可以在不影响基础源数据的情况下处理 CollectionView 中的数据。 集合视图中的更改反映在 DataGrid 用户界面 (UI) 中。
  • Popup控件,直接继承FrameworkElement,提供了一种在单独的窗口中显示内容的方法,该窗口相对于指定的元素或屏幕坐标,浮动在当前Popup应用程序窗口上,可用于悬浮窗口。

示例截图


本示例主要模仿Excel的筛选功能进行实现,右键标题栏打开浮动窗口,悬浮于标题栏下方,既可以通过文本框进行筛选,也可以通过筛选按钮弹出右键菜单,选择具体筛选方式,截图如下所示:

选择筛选方式,弹出窗口,如下所示:

 输入筛选条件,点击确定,或者取消筛选。如筛选学号里面包含2的,效果如下所示:

 注意:以上筛选都是客户端筛选,不会修改数据源,也不会重连数据库。

核心源码


在本示例中,核心源码主要包含以下几个部分:

1. 前端视图【MainWindow.xaml】源码

主要实现了按学号,姓名,年龄三列进行筛选,既可以单列筛选,又可以组合筛选。且三列的筛选实现方式一致,仅是绑定列有差异。

  1. <Window x:Class="DemoDataGrid.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:DemoDataGrid"
  7. mc:Ignorable="d"
  8. Title="DataGrid筛选示例" Height="650" Width="800">
  9. <Window.Resources>
  10. <ResourceDictionary>
  11. <CollectionViewSource x:Key="ItemsSource" Source="{Binding Path=Students}"></CollectionViewSource>
  12. <CollectionViewSource x:Key="Names" Source="{Binding Path=Names}"></CollectionViewSource>
  13. <CollectionViewSource x:Key="Nos" Source="{Binding Path=Nos}"></CollectionViewSource>
  14. <CollectionViewSource x:Key="Ages" Source="{Binding Path=Ages}"></CollectionViewSource>
  15. <Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
  16. <Setter Property="ScrollViewer.CanContentScroll" Value="True"></Setter>
  17. <Setter Property="Template">
  18. <Setter.Value>
  19. <ControlTemplate TargetType="{x:Type ListBox}">
  20. <ScrollViewer x:Name="ScrollViewer" CanContentScroll="True">
  21. <ItemsPresenter></ItemsPresenter>
  22. </ScrollViewer>
  23. </ControlTemplate>
  24. </Setter.Value>
  25. </Setter>
  26. </Style>
  27. <Geometry x:Key="Icon_Filter">
  28. M608 864C588.8 864 576 851.2 576 832L576 448c0-6.4 6.4-19.2 12.8-25.6L787.2 256c6.4-6.4 6.4-19.2 0-19.2 0-6.4-6.4-12.8-19.2-12.8L256 224c-12.8 0-19.2 6.4-19.2 12.8 0 6.4-6.4 12.8 6.4 19.2l198.4 166.4C441.6 428.8 448 441.6 448 448l0 256c0 19.2-12.8 32-32 32S384 723.2 384 704L384 460.8 198.4 307.2c-25.6-25.6-32-64-19.2-96C185.6 179.2 217.6 160 256 160L768 160c32 0 64 19.2 76.8 51.2 12.8 32 6.4 70.4-19.2 89.6l-192 160L633.6 832C640 851.2 627.2 864 608 864z
  29. </Geometry>
  30. <ContextMenu x:Key="queryConditionMenu" MouseLeave="ContextMenu_MouseLeave" MenuItem.Click="ContextMenu_Click">
  31. <MenuItem FontSize="12" Header="等于" Tag="Equal"></MenuItem>
  32. <MenuItem FontSize="12" Header="不等于" Tag="NotEqual"></MenuItem>
  33. <MenuItem FontSize="12" Header="开头" Tag="Begin"></MenuItem>
  34. <MenuItem FontSize="12" Header="结尾" Tag="End"></MenuItem>
  35. <MenuItem FontSize="12" Header="包含" Tag="In"></MenuItem>
  36. <MenuItem FontSize="12" Header="不包含" Tag="NotIn"></MenuItem>
  37. </ContextMenu>
  38. </ResourceDictionary>
  39. </Window.Resources>
  40. <Grid Margin="10">
  41. <Grid.RowDefinitions>
  42. <RowDefinition Height="20"></RowDefinition>
  43. <RowDefinition Height="*"></RowDefinition>
  44. </Grid.RowDefinitions>
  45. <DataGrid Grid.Row="1" x:Name="dgStudents" ItemsSource="{Binding Source={StaticResource ItemsSource} }" AutoGenerateColumns="False"
  46. CanUserReorderColumns="True" CanUserDeleteRows="False" CanUserAddRows="False" HeadersVisibility="Column"
  47. CanUserSortColumns="True"
  48. VirtualizingPanel.VirtualizationMode="Recycling"
  49. EnableColumnVirtualization="True" VirtualizingPanel.IsVirtualizingWhenGrouping="True" GridLinesVisibility="All" RowHeight="25"
  50. SelectionUnit="FullRow" SelectionMode="Single" IsReadOnly="True" FontSize="12"
  51. SelectedIndex="{Binding SelectTaskItemIndex}" SelectedItem="{Binding SelectTaskItem}"
  52. CanUserResizeColumns="True">
  53. <DataGrid.Columns>
  54. <DataGridTextColumn Binding="{Binding Id}" Header="Id" Width="*">
  55. </DataGridTextColumn>
  56. <DataGridTextColumn Binding="{Binding No}" Width="*">
  57. <DataGridTextColumn.Header>
  58. <TextBlock Text="学号" FontWeight="Regular" MouseRightButtonDown="TextBlock_MouseRightButtonDown" Tag="No"></TextBlock>
  59. </DataGridTextColumn.Header>
  60. </DataGridTextColumn>
  61. <DataGridTextColumn Binding="{Binding Name}" Width="*">
  62. <DataGridTextColumn.Header>
  63. <TextBlock Text="姓名" FontWeight="Regular" MouseRightButtonDown="TextBlock_MouseRightButtonDown" Tag="Name"></TextBlock>
  64. </DataGridTextColumn.Header>
  65. </DataGridTextColumn>
  66. <DataGridTextColumn Binding="{Binding Age}" Width="*">
  67. <DataGridTextColumn.Header>
  68. <TextBlock Text="年龄" FontWeight="Regular" MouseRightButtonDown="TextBlock_MouseRightButtonDown" Tag="Age"></TextBlock>
  69. </DataGridTextColumn.Header>
  70. </DataGridTextColumn>
  71. </DataGrid.Columns>
  72. </DataGrid>
  73. <Popup x:Name="popupNo" Width="135" MaxHeight="500" Height="Auto" PopupAnimation="Slide" AllowsTransparency="False" MouseLeave="popup_MouseLeave">
  74. <Border BorderBrush="LightBlue" BorderThickness="1" Padding="5" Background="AliceBlue">
  75. <Grid>
  76. <Grid.ColumnDefinitions>
  77. <ColumnDefinition></ColumnDefinition>
  78. <ColumnDefinition></ColumnDefinition>
  79. </Grid.ColumnDefinitions>
  80. <Grid.RowDefinitions>
  81. <RowDefinition></RowDefinition>
  82. <RowDefinition></RowDefinition>
  83. <RowDefinition></RowDefinition>
  84. </Grid.RowDefinitions>
  85. <StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
  86. <TextBox Height="25" x:Name="txtNo" MinWidth="60" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Tag="No" TextChanged="TextBox_TextChanged"></TextBox>
  87. <Button x:Name="btnNoFilter" Tag="No" ClickMode="Press" Click="ButtonFilter_Click" ContextMenu="{StaticResource queryConditionMenu}">
  88. <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
  89. <Path Data="{StaticResource Icon_Filter}" Stroke="Gray" StrokeThickness="1"
  90. Height="12" Width="12" Stretch="Fill"></Path>
  91. <TextBlock Margin="2,0" Text="筛选" FontSize="12"></TextBlock>
  92. </StackPanel>
  93. </Button>
  94. </StackPanel>
  95. <ListBox x:Name="lbNos" ItemsSource="{Binding Source={StaticResource Nos}}" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True" Style="{StaticResource ListBoxStyle}">
  96. <ListBox.ItemTemplate>
  97. <DataTemplate>
  98. <CheckBox Content="{Binding FilterText}" IsChecked="{Binding IsChecked}"></CheckBox>
  99. </DataTemplate>
  100. </ListBox.ItemTemplate>
  101. </ListBox>
  102. <Button Tag="No" Content="取消" Width="60" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="0" Click="btnCancel_Click"></Button>
  103. <Button Content="确定" Width="60" HorizontalAlignment="Right" Grid.Row="2" Grid.Column="1" Click="btnOk_Click"></Button>
  104. </Grid>
  105. </Border>
  106. </Popup>
  107. <Popup x:Name="popupName" Width="135" MaxHeight="500" Height="Auto" PopupAnimation="Slide" AllowsTransparency="False" MouseLeave="popup_MouseLeave">
  108. <Border BorderBrush="LightBlue" BorderThickness="1" Padding="5" Background="AliceBlue">
  109. <Grid>
  110. <Grid.ColumnDefinitions>
  111. <ColumnDefinition></ColumnDefinition>
  112. <ColumnDefinition></ColumnDefinition>
  113. </Grid.ColumnDefinitions>
  114. <Grid.RowDefinitions>
  115. <RowDefinition></RowDefinition>
  116. <RowDefinition></RowDefinition>
  117. <RowDefinition></RowDefinition>
  118. </Grid.RowDefinitions>
  119. <StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
  120. <TextBox Height="25" x:Name="txtName" MinWidth="60" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Tag="Name" TextChanged="TextBox_TextChanged"></TextBox>
  121. <Button x:Name="btnNameFilter" Tag="Name" Click="ButtonFilter_Click" ContextMenu="{StaticResource queryConditionMenu}">
  122. <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
  123. <Path Data="{StaticResource Icon_Filter}" Stroke="Gray" StrokeThickness="1"
  124. Height="12" Width="12" Stretch="Fill"></Path>
  125. <TextBlock Margin="2,0" Text="筛选" FontSize="12"></TextBlock>
  126. </StackPanel>
  127. </Button>
  128. </StackPanel>
  129. <ListBox x:Name="lbNames" ItemsSource="{Binding Source={StaticResource Names}}" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True" Style="{StaticResource ListBoxStyle}">
  130. <ListBox.ItemTemplate>
  131. <DataTemplate>
  132. <CheckBox Content="{Binding FilterText}" IsChecked="{Binding IsChecked}"></CheckBox>
  133. </DataTemplate>
  134. </ListBox.ItemTemplate>
  135. </ListBox>
  136. <Button Tag="No" Content="取消" Width="60" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="0" Click="btnCancel_Click"></Button>
  137. <Button Content="确定" Width="60" HorizontalAlignment="Right" Grid.Row="2" Grid.Column="1" Click="btnOk_Click"></Button>
  138. </Grid>
  139. </Border>
  140. </Popup>
  141. <Popup x:Name="popupAge" Width="135" MaxHeight="500" Height="Auto" PopupAnimation="Slide" AllowsTransparency="False" MouseLeave="popup_MouseLeave">
  142. <Border BorderBrush="LightBlue" BorderThickness="1" Padding="5" Background="AliceBlue">
  143. <Grid>
  144. <Grid.ColumnDefinitions>
  145. <ColumnDefinition></ColumnDefinition>
  146. <ColumnDefinition></ColumnDefinition>
  147. </Grid.ColumnDefinitions>
  148. <Grid.RowDefinitions>
  149. <RowDefinition></RowDefinition>
  150. <RowDefinition></RowDefinition>
  151. <RowDefinition></RowDefinition>
  152. </Grid.RowDefinitions>
  153. <StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
  154. <TextBox Height="25" x:Name="txtAge" MinWidth="60" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Tag="Age" TextChanged="TextBox_TextChanged"></TextBox>
  155. <Button x:Name="btnAgeFilter" Tag="Age" Click="ButtonFilter_Click" ContextMenu="{StaticResource queryConditionMenu}">
  156. <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
  157. <Path Data="{StaticResource Icon_Filter}" Stroke="Gray" StrokeThickness="1"
  158. Height="12" Width="12" Stretch="Fill"></Path>
  159. <TextBlock Margin="2,0" Text="筛选" FontSize="12"></TextBlock>
  160. </StackPanel>
  161. </Button>
  162. </StackPanel>
  163. <ListBox x:Name="lbAges" ItemsSource="{Binding Source={StaticResource Ages}}" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True" Style="{StaticResource ListBoxStyle}">
  164. <ListBox.ItemTemplate>
  165. <DataTemplate>
  166. <CheckBox Content="{Binding FilterText}" IsChecked="{Binding IsChecked}"></CheckBox>
  167. </DataTemplate>
  168. </ListBox.ItemTemplate>
  169. </ListBox>
  170. <Button Tag="No" Content="取消" Width="60" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="0" Click="btnCancel_Click"></Button>
  171. <Button Content="确定" Width="60" HorizontalAlignment="Right" Grid.Row="2" Grid.Column="1" Click="btnOk_Click"></Button>
  172. </Grid>
  173. </Border>
  174. </Popup>
  175. <Popup x:Name="popupNoMenu" Width="300" MaxHeight="500" Height="200" PopupAnimation="Slide" AllowsTransparency="False" Tag="">
  176. <Border BorderThickness="1" BorderBrush="Beige" Padding="15" Background="AliceBlue">
  177. <Grid>
  178. <Grid.ColumnDefinitions>
  179. <ColumnDefinition></ColumnDefinition>
  180. <ColumnDefinition></ColumnDefinition>
  181. </Grid.ColumnDefinitions>
  182. <Grid.RowDefinitions>
  183. <RowDefinition Height="Auto"></RowDefinition>
  184. <RowDefinition Height="Auto"></RowDefinition>
  185. <RowDefinition Height="Auto"></RowDefinition>
  186. <RowDefinition></RowDefinition>
  187. </Grid.RowDefinitions>
  188. <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
  189. <TextBlock Text="学号" VerticalAlignment="Center"></TextBlock>
  190. <ComboBox x:Name="combNoMenu1" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
  191. <ComboBoxItem Content="等于" ></ComboBoxItem>
  192. <ComboBoxItem Content="不等于"></ComboBoxItem>
  193. <ComboBoxItem Content="开头"></ComboBoxItem>
  194. <ComboBoxItem Content="结尾"></ComboBoxItem>
  195. <ComboBoxItem Content="包含"></ComboBoxItem>
  196. <ComboBoxItem Content="不包含"></ComboBoxItem>
  197. </ComboBox>
  198. <TextBox x:Name="txtNoMenu1" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
  199. </StackPanel>
  200. <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
  201. <RadioButton x:Name="rbNoAnd" Content="与" IsChecked="True" Margin="4" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
  202. <RadioButton x:Name="rbNoOr" Content="或" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
  203. </StackPanel>
  204. <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
  205. <TextBlock Text="学号" VerticalAlignment="Center"></TextBlock>
  206. <ComboBox x:Name="combNoMenu2" Height="28" Margin="4" Width="100" VerticalContentAlignment="Center">
  207. <ComboBoxItem Content="等于" ></ComboBoxItem>
  208. <ComboBoxItem Content="不等于"></ComboBoxItem>
  209. <ComboBoxItem Content="开头"></ComboBoxItem>
  210. <ComboBoxItem Content="结尾"></ComboBoxItem>
  211. <ComboBoxItem Content="包含"></ComboBoxItem>
  212. <ComboBoxItem Content="不包含"></ComboBoxItem>
  213. </ComboBox>
  214. <TextBox x:Name="txtNoMenu2" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
  215. </StackPanel>
  216. <Button Tag="No" Content="取消" Width="100" Height="28" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="0" Click="btnCancelFilter_Click"></Button>
  217. <Button Tag="No" Content="确定" Width="100" Height="28" HorizontalAlignment="Right" Grid.Row="3" Grid.Column="1" Click="btnOkFilter_Click"></Button>
  218. </Grid>
  219. </Border>
  220. </Popup>
  221. <Popup x:Name="popupNameMenu" Width="300" MaxHeight="500" Height="200" PopupAnimation="Slide" AllowsTransparency="False" Tag="">
  222. <Border BorderThickness="1" BorderBrush="Beige" Padding="15" Background="AliceBlue">
  223. <Grid>
  224. <Grid.RowDefinitions>
  225. <RowDefinition Height="Auto"></RowDefinition>
  226. <RowDefinition Height="Auto"></RowDefinition>
  227. <RowDefinition Height="Auto"></RowDefinition>
  228. <RowDefinition Height="Auto"></RowDefinition>
  229. </Grid.RowDefinitions>
  230. <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
  231. <TextBlock Text="姓名" VerticalAlignment="Center"></TextBlock>
  232. <ComboBox x:Name="combNameMenu1" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
  233. <ComboBoxItem Content="等于" ></ComboBoxItem>
  234. <ComboBoxItem Content="不等于"></ComboBoxItem>
  235. <ComboBoxItem Content="开头"></ComboBoxItem>
  236. <ComboBoxItem Content="结尾"></ComboBoxItem>
  237. <ComboBoxItem Content="包含"></ComboBoxItem>
  238. <ComboBoxItem Content="不包含"></ComboBoxItem>
  239. </ComboBox>
  240. <TextBox x:Name="txtNameMenu1" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
  241. </StackPanel>
  242. <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0">
  243. <RadioButton x:Name="rbNameAnd" Content="与" IsChecked="True" Margin="4" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
  244. <RadioButton x:Name="rbNameOr" Content="或" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
  245. </StackPanel>
  246. <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0">
  247. <TextBlock Text="姓名" VerticalAlignment="Center"></TextBlock>
  248. <ComboBox x:Name="combNameMenu2" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
  249. <ComboBoxItem Content="等于" ></ComboBoxItem>
  250. <ComboBoxItem Content="不等于"></ComboBoxItem>
  251. <ComboBoxItem Content="开头"></ComboBoxItem>
  252. <ComboBoxItem Content="结尾"></ComboBoxItem>
  253. <ComboBoxItem Content="包含"></ComboBoxItem>
  254. <ComboBoxItem Content="不包含"></ComboBoxItem>
  255. </ComboBox>
  256. <TextBox x:Name="txtNameMenu2" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
  257. </StackPanel>
  258. <Button Tag="Name" Content="取消" Width="100" Height="28" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="0" Click="btnCancelFilter_Click"></Button>
  259. <Button Tag="Name" Content="确定" Width="100" Height="28" HorizontalAlignment="Right" Grid.Row="3" Grid.Column="1" Click="btnOkFilter_Click"></Button>
  260. </Grid>
  261. </Border>
  262. </Popup>
  263. <Popup x:Name="popupAgeMenu" Width="300" MaxHeight="500" Height="200" PopupAnimation="Slide" AllowsTransparency="False" Tag="">
  264. <Border BorderThickness="1" BorderBrush="Beige" Padding="15" Background="AliceBlue">
  265. <Grid>
  266. <Grid.RowDefinitions>
  267. <RowDefinition Height="Auto"></RowDefinition>
  268. <RowDefinition Height="Auto"></RowDefinition>
  269. <RowDefinition Height="Auto"></RowDefinition>
  270. <RowDefinition Height="Auto"></RowDefinition>
  271. </Grid.RowDefinitions>
  272. <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
  273. <TextBlock Text="年龄" VerticalAlignment="Center"></TextBlock>
  274. <ComboBox x:Name="combAgeMenu1" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
  275. <ComboBoxItem Content="等于" ></ComboBoxItem>
  276. <ComboBoxItem Content="不等于"></ComboBoxItem>
  277. <ComboBoxItem Content="开头"></ComboBoxItem>
  278. <ComboBoxItem Content="结尾"></ComboBoxItem>
  279. <ComboBoxItem Content="包含"></ComboBoxItem>
  280. <ComboBoxItem Content="不包含"></ComboBoxItem>
  281. </ComboBox>
  282. <TextBox x:Name="txtAgeMenu1" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
  283. </StackPanel>
  284. <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0">
  285. <RadioButton x:Name="rbAgeAnd" Content="与" IsChecked="True" Margin="4" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
  286. <RadioButton x:Name="rbAgeOr" Content="或" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
  287. </StackPanel>
  288. <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0">
  289. <TextBlock Text="年龄" VerticalAlignment="Center"></TextBlock>
  290. <ComboBox x:Name="combAgeMenu2" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
  291. <ComboBoxItem Content="等于" ></ComboBoxItem>
  292. <ComboBoxItem Content="不等于"></ComboBoxItem>
  293. <ComboBoxItem Content="开头"></ComboBoxItem>
  294. <ComboBoxItem Content="结尾"></ComboBoxItem>
  295. <ComboBoxItem Content="包含"></ComboBoxItem>
  296. <ComboBoxItem Content="不包含"></ComboBoxItem>
  297. </ComboBox>
  298. <TextBox x:Name="txtAgeMenu2" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
  299. </StackPanel>
  300. <Button Tag="Age" Content="取消" Width="100" Height="28" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="0" Click="btnCancelFilter_Click"></Button>
  301. <Button Tag="Age" Content="确定" Width="100" Height="28" HorizontalAlignment="Right" Grid.Row="3" Grid.Column="1" Click="btnOkFilter_Click"></Button>
  302. </Grid>
  303. </Border>
  304. </Popup>
  305. </Grid>
  306. </Window>

2. 业务逻辑【MainWindowViewModel】

业务逻辑处理主要复责数据初始化等业务相关内容,和UI无关,如下所示:

  1. using CommunityToolkit.Mvvm.ComponentModel;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace DemoDataGrid
  8. {
  9. public class MainWindowViewModel:ObservableObject
  10. {
  11. #region 属性及构造函数
  12. private List<Student> students;
  13. public List<Student> Students
  14. {
  15. get { return students; }
  16. set { SetProperty(ref students, value); }
  17. }
  18. private List<FilterInfo> names;
  19. public List<FilterInfo> Names
  20. {
  21. get { return names; }
  22. set { SetProperty(ref names, value); }
  23. }
  24. private List<FilterInfo> nos;
  25. public List<FilterInfo> Nos
  26. {
  27. get { return nos; }
  28. set {SetProperty(ref nos , value); }
  29. }
  30. private List<FilterInfo> ages;
  31. public List<FilterInfo> Ages
  32. {
  33. get { return ages; }
  34. set {SetProperty(ref ages , value); }
  35. }
  36. public MainWindowViewModel()
  37. {
  38. this.Students= new List<Student>();
  39. for (int i = 0; i < 20; i++) {
  40. this.Students.Add(new Student()
  41. {
  42. Id = i,
  43. Name = $"张{i}牛",
  44. Age = (i % 10) + 10,
  45. No = i.ToString().PadLeft(4, '0'),
  46. });
  47. }
  48. this.Nos= new List<FilterInfo>();
  49. this.Names= new List<FilterInfo>();
  50. this.Ages= new List<FilterInfo>();
  51. this.Students.ForEach(s => {
  52. this.Nos.Add(new FilterInfo() { FilterText=s.No,IsChecked=false });
  53. this.Names.Add(new FilterInfo() { FilterText = s.Name, IsChecked = false });
  54. this.Ages.Add(new FilterInfo() { FilterText = s.Age.ToString(), IsChecked = false });
  55. });
  56. this.Ages=this.Ages.Distinct().ToList();//去重
  57. }
  58. #endregion
  59. }
  60. }

3. 筛选功能实现【MainWindow.xaml.cs】

本示例为了简化实现,筛选功能处理主要在cs后端实现,如下所示:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Documents;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Imaging;
  13. using System.Windows.Navigation;
  14. using System.Windows.Shapes;
  15. namespace DemoDataGrid
  16. {
  17. /// <summary>
  18. /// Interaction logic for MainWindow.xaml
  19. /// </summary>
  20. public partial class MainWindow : Window
  21. {
  22. private MainWindowViewModel viewModel;
  23. public MainWindow()
  24. {
  25. InitializeComponent();
  26. viewModel = new MainWindowViewModel();
  27. this.DataContext = viewModel;
  28. }
  29. #region 筛选
  30. private void TextBlock_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
  31. {
  32. if (sender != null && sender is TextBlock)
  33. {
  34. var textBlock = sender as TextBlock;
  35. var tag = textBlock.Tag.ToString();
  36. var pop = this.FindName($"popup{tag}");
  37. if (pop != null)
  38. {
  39. var popup = pop as System.Windows.Controls.Primitives.Popup;
  40. if (popup != null)
  41. {
  42. popup.IsOpen = true;
  43. popup.PlacementTarget = textBlock;
  44. popup.Placement = System.Windows.Controls.Primitives.PlacementMode.RelativePoint;
  45. popup.VerticalOffset = 10;
  46. popup.HorizontalOffset = 10;
  47. }
  48. }
  49. }
  50. }
  51. private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
  52. {
  53. TextBox textBox = e.OriginalSource as TextBox;
  54. var tag = textBox.Tag;//条件
  55. var text = textBox.Text;
  56. if (tag != null)
  57. {
  58. if (tag.ToString() == "No")
  59. {
  60. Filter(this.lbNos.ItemsSource, this.txtNo.Text);
  61. }
  62. if (tag.ToString() == "Name")
  63. {
  64. Filter(this.lbNames.ItemsSource, this.txtName.Text);
  65. }
  66. if (tag.ToString() == "Age")
  67. {
  68. Filter(this.lbAges.ItemsSource, this.txtAge.Text);
  69. }
  70. }
  71. }
  72. private void Filter(object source, string filter)
  73. {
  74. var cv = CollectionViewSource.GetDefaultView(source);
  75. if (cv != null && cv.CanFilter)
  76. {
  77. cv.Filter = new Predicate<object>((obj) => {
  78. bool flag = true;
  79. var t = obj as FilterInfo;
  80. if (t != null)
  81. {
  82. flag = t.FilterText.Contains(filter);
  83. }
  84. return flag;
  85. });
  86. }
  87. }
  88. private void popup_MouseLeave(object sender, MouseEventArgs e)
  89. {
  90. var popup = e.OriginalSource as System.Windows.Controls.Primitives.Popup;
  91. var showContext = (this.FindResource("queryConditionMenu") as ContextMenu)?.IsOpen;
  92. if (popup != null && showContext==false)
  93. {
  94. popup.IsOpen = false;
  95. }
  96. }
  97. private void btnCancel_Click(object sender, RoutedEventArgs e)
  98. {
  99. var btn = e.OriginalSource as Button;
  100. if (btn != null)
  101. {
  102. var tag = btn.Tag;
  103. if (tag.ToString() == "No")
  104. {
  105. ClearFilter(this.txtNo, this.viewModel.Nos);
  106. }
  107. if (tag.ToString() == "Name")
  108. {
  109. ClearFilter(this.txtName, this.viewModel.Names);
  110. }
  111. if (tag.ToString() == "Age")
  112. {
  113. ClearFilter(this.txtAge, this.viewModel.Ages);
  114. }
  115. FilterTask();//清除以后,重新刷新
  116. }
  117. }
  118. private void ClearFilter(TextBox textBox, List<FilterInfo> collection)
  119. {
  120. textBox.Clear();
  121. foreach (var f in collection)
  122. {
  123. f.IsChecked = false;
  124. }
  125. }
  126. private void btnOk_Click(object sender, RoutedEventArgs e)
  127. {
  128. //
  129. FilterTask();
  130. }
  131. private void FilterTask()
  132. {
  133. var cv = CollectionViewSource.GetDefaultView(this.dgStudents.ItemsSource);
  134. if (cv != null && cv.CanFilter)
  135. {
  136. cv.Filter = new Predicate<object>((obj) =>
  137. {
  138. bool flag = true;
  139. var t = obj as Student;
  140. if (t != null)
  141. {
  142. var nos = this.viewModel.Nos.Where(r => r.IsChecked == true).ToList();
  143. var names = this.viewModel.Names.Where(r => r.IsChecked == true).ToList();
  144. var ages = this.viewModel.Ages.Where(r => r.IsChecked == true).ToList();
  145. if (nos.Count() > 0)
  146. {
  147. flag = flag && nos.Select(r => r.FilterText).Contains(t.No);
  148. }
  149. if (names.Count() > 0)
  150. {
  151. flag = flag && names.Select(r => r.FilterText).Contains(t.Name);
  152. }
  153. if (ages.Count() > 0)
  154. {
  155. flag = flag && ages.Select(r => r.FilterText).Contains(t.Age.ToString());
  156. }
  157. }
  158. return flag;
  159. });
  160. }
  161. }
  162. #endregion
  163. private List<string> condition = new List<string>() { "Equal", "NotEqual", "Begin", "End", "In", "NotIn" };
  164. private void ButtonFilter_Click(object sender, RoutedEventArgs e)
  165. {
  166. var btn = e.OriginalSource as Button;
  167. if (btn != null)
  168. {
  169. var tag = btn.Tag;
  170. var popup = this.FindName($"popup{tag}") as System.Windows.Controls.Primitives.Popup;
  171. if (popup != null)
  172. {
  173. popup.IsOpen = true;
  174. }
  175. if (btn.ContextMenu.IsOpen)
  176. {
  177. btn.ContextMenu.IsOpen = false;
  178. }
  179. else
  180. {
  181. btn.ContextMenu.Tag = tag;
  182. btn.ContextMenu.Width = 100;
  183. btn.ContextMenu.Height = 150;
  184. btn.ContextMenu.IsOpen = true;
  185. btn.ContextMenu.PlacementTarget = btn;
  186. btn.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
  187. }
  188. }
  189. }
  190. private void ContextMenu_MouseLeave(object sender, MouseEventArgs e)
  191. {
  192. var menu = e.OriginalSource as ContextMenu;
  193. if (menu != null)
  194. {
  195. menu.IsOpen = false;
  196. }
  197. }
  198. private void ContextMenu_Click(object sender, RoutedEventArgs e)
  199. {
  200. var contextMenu = sender as ContextMenu;
  201. if (contextMenu == null)
  202. {
  203. return;
  204. }
  205. var menuItem = e.OriginalSource as MenuItem;
  206. if (menuItem == null)
  207. {
  208. return;
  209. }
  210. var tag1 = contextMenu.Tag.ToString();//点击的哪一个按钮
  211. var tag2 = menuItem.Tag.ToString();//点击的是哪一个菜单
  212. var pop = this.FindName($"popup{tag1}Menu");
  213. var comb = this.FindName($"comb{tag1}Menu1");
  214. HideParentPopup(tag1);//隐藏父Popup
  215. if (comb != null)
  216. {
  217. var combMenu = comb as ComboBox;
  218. combMenu.SelectedIndex = condition.IndexOf(tag2);
  219. }
  220. if (pop != null)
  221. {
  222. var popup = pop as System.Windows.Controls.Primitives.Popup;
  223. popup.IsOpen = true;
  224. popup.PlacementTarget = dgStudents;
  225. popup.Placement = System.Windows.Controls.Primitives.PlacementMode.Center;
  226. }
  227. }
  228. private void btnCancelFilter_Click(object sender, RoutedEventArgs e)
  229. {
  230. if (sender == null)
  231. {
  232. return;
  233. }
  234. var btn = sender as System.Windows.Controls.Button;
  235. if (btn != null)
  236. {
  237. var tag = btn.Tag.ToString();
  238. HidePopupMenu(tag);//隐藏Popup控件
  239. if (tag == "No")
  240. {
  241. ClearMenuFilter(this.txtNoMenu1, this.txtNoMenu2);
  242. }
  243. if (tag == "Name")
  244. {
  245. ClearMenuFilter(this.txtNameMenu1, this.txtNameMenu2);
  246. }
  247. if (tag == "Age")
  248. {
  249. ClearMenuFilter(this.txtAgeMenu1, this.txtAgeMenu2);
  250. }
  251. FilterMenuTask();
  252. }
  253. }
  254. private void btnOkFilter_Click(object sender, RoutedEventArgs e)
  255. {
  256. if (sender == null)
  257. {
  258. return;
  259. }
  260. var btn = sender as System.Windows.Controls.Button;
  261. if (btn != null)
  262. {
  263. var tag = btn.Tag.ToString();
  264. HidePopupMenu(tag);
  265. FilterMenuTask();
  266. }
  267. }
  268. /// <summary>
  269. /// 隐藏父Popup
  270. /// </summary>
  271. /// <param name="tag"></param>
  272. private void HideParentPopup(string tag)
  273. {
  274. //点击右键菜单时,隐藏父Popup控件
  275. if (tag == "No")
  276. {
  277. this.popupNo.IsOpen = false;
  278. }
  279. if (tag == "Name")
  280. {
  281. this.popupName.IsOpen = false;
  282. }
  283. if (tag == "Age")
  284. {
  285. this.popupAge.IsOpen = false;
  286. }
  287. }
  288. /// <summary>
  289. /// 隐藏菜单弹出的Popup控件
  290. /// </summary>
  291. /// <param name="tag"></param>
  292. private void HidePopupMenu(string tag)
  293. {
  294. var pop = this.FindName($"popup{tag}Menu");
  295. if (pop != null)
  296. {
  297. var popup = pop as System.Windows.Controls.Primitives.Popup;
  298. popup.IsOpen = false;
  299. }
  300. }
  301. /// <summary>
  302. /// 清除菜单中的文本过滤条件
  303. /// </summary>
  304. /// <param name="txt1"></param>
  305. /// <param name="txt2"></param>
  306. private void ClearMenuFilter(TextBox txt1, TextBox txt2)
  307. {
  308. txt1?.Clear();
  309. txt2?.Clear();
  310. }
  311. /// <summary>
  312. ///
  313. /// </summary>
  314. private void FilterMenuTask()
  315. {
  316. var cv = CollectionViewSource.GetDefaultView(this.dgStudents.ItemsSource);
  317. if (cv != null && cv.CanFilter)
  318. {
  319. cv.Filter = new Predicate<object>((obj) =>
  320. {
  321. bool flag = true;
  322. var t = obj as Student;
  323. if (t != null)
  324. {
  325. string noText1 = this.txtNoMenu1.Text.Trim();
  326. string noText2 = this.txtNoMenu2.Text.Trim();
  327. int noConditionType1 = this.combNoMenu1.SelectedIndex;
  328. int noConditionType2 = this.combNoMenu2.SelectedIndex;
  329. string nameText1 = this.txtNameMenu1.Text.Trim();
  330. string nameText2 = this.txtNameMenu2.Text.Trim();
  331. int nameConditionType1 = this.combNameMenu1.SelectedIndex;
  332. int nameConditionType2 = this.combNameMenu2.SelectedIndex;
  333. string ageText1 = this.txtAgeMenu1.Text.Trim();
  334. string ageText2 = this.txtAgeMenu2.Text.Trim();
  335. int ageConditionType1 = this.combAgeMenu1.SelectedIndex;
  336. int ageConditionType2 = this.combAgeMenu2.SelectedIndex;
  337. bool? isNoAnd = this.rbNoAnd.IsChecked;
  338. bool? isNoOr = this.rbNoOr.IsChecked;
  339. bool? isNameAnd = this.rbNameAnd.IsChecked;
  340. bool? isNameOr = this.rbNameOr.IsChecked;
  341. bool? isAgeAnd = this.rbAgeAnd.IsChecked;
  342. bool? isAgeOr = this.rbAgeOr.IsChecked;
  343. bool flagNo = true;
  344. bool flagName = true;
  345. bool flagAge = true;
  346. flagNo = CheckConditions(noConditionType1, noConditionType2, t.No, noText1, noText2, isNoAnd, isNoOr);
  347. flagName = CheckConditions(nameConditionType1, nameConditionType2, t.Name, nameText1, nameText2, isNameAnd, isNameOr);
  348. flagAge = CheckConditions(ageConditionType1, ageConditionType2, t.Age.ToString(), ageText1, ageText2, isAgeAnd, isAgeOr);
  349. flag = flag && flagNo && flagName && flagAge;
  350. }
  351. return flag;
  352. });
  353. }
  354. }
  355. private bool CheckConditions(int conditionIndex1, int conditionIndex2, string source, string condition1, string condition2, bool? isAnd, bool? isOr)
  356. {
  357. bool flag = true;
  358. bool flag1 = true;
  359. bool flag2 = true;
  360. if (!string.IsNullOrEmpty(condition1) && !string.IsNullOrWhiteSpace(condition1) && conditionIndex1 != -1)
  361. {
  362. flag1 = CheckCondition(conditionIndex1, source, condition1);
  363. }
  364. if (!string.IsNullOrEmpty(condition2) && !string.IsNullOrWhiteSpace(condition2) && conditionIndex2 != -1)
  365. {
  366. flag2 = CheckCondition(conditionIndex2, source, condition2);
  367. }
  368. if (isAnd == true)
  369. {
  370. flag = flag1 && flag2;
  371. }
  372. if (isOr == true)
  373. {
  374. flag = flag1 || flag2;
  375. }
  376. return flag;
  377. }
  378. private bool CheckCondition(int condtionIndex, string source, string condition)
  379. {
  380. bool flag = true;
  381. if (condtionIndex == 0)
  382. {
  383. flag = flag && source == condition;
  384. }
  385. if (condtionIndex == 1)
  386. {
  387. flag = flag && source != condition;
  388. }
  389. if (condtionIndex == 2)
  390. {
  391. flag = flag && source.StartsWith(condition);
  392. }
  393. if (condtionIndex == 3)
  394. {
  395. flag = flag && source.EndsWith(condition);
  396. }
  397. if (condtionIndex == 4)
  398. {
  399. flag = flag && source.Contains(condition);
  400. }
  401. if (condtionIndex == 5)
  402. {
  403. flag = flag && !source.Contains(condition);
  404. }
  405. return flag;
  406. }
  407. }
  408. }

学号,姓名,年龄三列过滤列表绑定内容模型一致,为FilterInfo,如下所示:

  1. using CommunityToolkit.Mvvm.ComponentModel;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace DemoDataGrid
  8. {
  9. public class FilterInfo : ObservableObject
  10. {
  11. private string filterText;
  12. public string FilterText
  13. {
  14. get { return filterText; }
  15. set { SetProperty(ref filterText, value); }
  16. }
  17. private bool isChecked;
  18. public bool IsChecked
  19. {
  20. get { return isChecked; }
  21. set { SetProperty(ref isChecked, value); }
  22. }
  23. }
  24. }

不足与思考

上述筛选实现方式,并非唯一实现,也并非最优实现,同样存在许多可以优化的地方。

在本示例中,存在许多冗余代码,如视图页面,对三列的弹出窗口,内容虽然相对统一,只是列名和绑定内容不同而已,却堆积了三大段代码,是否可以从控件模块或者数据模板的角度,进行简化呢?

筛选功能实现上,同样存在许多冗余代码,是否可以进行简化呢?以上是我们需要思考的地方,希望可以集思广益,共同学习,一起进步。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/153247
推荐阅读
相关标签
  

闽ICP备14008679号