让WPF中的DataGrid像Excel一样可以筛选(下)

简介: 让WPF中的DataGrid像Excel一样可以筛选(下)

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

学号,姓名,年龄三列过滤列表绑定内容模型一致,为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. 
8. namespace DemoDataGrid
9. {
10. public class FilterInfo : ObservableObject
11.     {
12. private string filterText;
13. 
14. public string FilterText
15.         {
16. get { return filterText; }
17. set { SetProperty(ref filterText, value); }
18.         }
19. 
20. private bool isChecked;
21. 
22. public bool IsChecked
23.         {
24. get { return isChecked; }
25. set { SetProperty(ref isChecked, value); }
26.         }
27.     }
28. }

不足与思考

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

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

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

相关文章
|
2月前
|
数据采集 数据可视化 数据处理
【办公自动化】在Excel中按条件筛选数据并存入新的表2.0
【办公自动化】在Excel中按条件筛选数据并存入新的表2.0
48 1
|
2月前
|
前端开发 C#
浅谈WPF之DataGrid动态生成列
在日常开发中,DataGrid作为二维表格,非常适合数据的展示和统计。通常情况下,一般都有固定的格式和确定的数据列展示,但是在某些特殊情况下,也可能会需要用到动态生成列。本文以一些简单的小例子,简述在WPF开发中,如何动态生成DataGrid的行和列,仅供学习分享使用,如有不足之处,还请指正。
109 2
excel将筛选项的行全删掉
excel将筛选项的行全删掉
|
2月前
|
数据采集 数据可视化 数据处理
【办公自动化】在Excel中按条件筛选数据并存入新的表
【办公自动化】在Excel中按条件筛选数据并存入新的表
36 0
|
8月前
|
数据挖掘 数据处理 C#
WPF技术之DataGrid控件
WPF DataGrid是一种可以显示和编辑数据的界面控件。它可以作为表格形式展示数据,支持添加、删除、修改、排序和分组操作。
183 0
|
4月前
|
存储 数据可视化 定位技术
Python用若干列的数据多条件筛选、去除Excel数据并批量绘制直方图
Python用若干列的数据多条件筛选、去除Excel数据并批量绘制直方图
|
4月前
|
存储 定位技术 数据处理
Python基于指定范围筛选并剔除Excel表格中的数据
Python基于指定范围筛选并剔除Excel表格中的数据
|
9月前
|
前端开发 C# 数据库
让WPF中的DataGrid像Excel一样可以筛选(上)
让WPF中的DataGrid像Excel一样可以筛选(上)
119 0
让WPF中的DataGrid像Excel一样可以筛选(上)
|
18天前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
|
4月前
|
C#
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
65 1