일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- algorithm
- IValueConverter
- Visual Studio
- convert
- WPF
- nullable
- Coding
- commit
- programmers
- C#
- File
- Process
- mysql
- coding-test
- git
- windows
- ListView
- dotNET
- .net
- Github
- windows10
- tls
- chashtag
- log
- Microsoft
- string
- 코딩테스트
- csharp
- logging
- Binding
Archives
- Today
- Total
CHashtag
[C# WPF] MVVM 패턴 ListView Filter (Binding) 본문
반응형
결론부터 알려드리겠습니다.
public class MainViewModel
{
private string _filter = string.Empty;
public string Filter
{
get => _filter;
set
{
_filter = value;
OnFilterChanged();
}
}
private ObservableCollection<string> StringFilter { get; set; }
private CollectionViewSource StringCollectionViewSource { get; set; }
public ICollectionView StringCollection
{
get { return StringCollectionViewSource.View; }
}
public MainViewModel()
{
StringFilter = new ObservableCollection<string>();
StringCollectionViewSource = new CollectionViewSource();
StringCollectionViewSource.Source = this.StringFilter;
StringCollectionViewSource.Filter += ApplyFilter;
}
private void OnFilterChanged()
{
StringCollectionViewSource.View.Refresh();
}
void ApplyFilter(object sender, FilterEventArgs e)
{
string str = (string)e.Item;
if (string.IsNullOrWhiteSpace(this.Filter) || this.Filter.Length == 0)
{
e.Accepted = true;
}
else
{
e.Accepted = Filter == str;
}
}
}
<!-- xaml -->
<TextBox Width="400" Height="30" Padding="5" FontSize="14" HorizontalAlignment="Center" Margin="5" Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}"/>
<ListView Grid.Row="1" ItemsSource="{Binding StringCollection}" />
안녕하세요.
오늘은 WPF ListView를 사용하여 특정 콘텐츠로 검색하는 방법에 대해 알아보기 위해
학생 관리 시스템을 만들어 학생을 검색할 수 있는 프로그램을 제작해 보도록 하겠습니다.
프로그램에 대한 설명은 주석으로 달아 두었습니다.
// Student.cs
using System.ComponentModel;
namespace WPF_Listview_Filter.Models
{
public class Student : INotifyPropertyChanged
{
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
private int _age;
public int Age
{
get => _age;
set
{
_age = value;
OnPropertyChanged(nameof(Age));
}
}
private string _country;
public string Country
{
get => _country;
set
{
_country = value;
OnPropertyChanged(nameof(Country));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
// MainViewModel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
using WPF_Listview_Filter.Models;
namespace WPF_Listview_Filter.ViewModels
{
public class MainViewModel
{
#region Properties
private string _filter = string.Empty;
public string Filter
{
get => _filter;
set
{
_filter = value;
// filter text가 변경되면 검색 조건이 변한 것이므로 필터를 refresh하여 데이터를 다시 검색하도록 합니다.
OnFilterChanged();
}
}
/// <summary>
/// Data의 변경 사항이 View에도 Notify되어야 하기 때문에 Source는 ObservableCollection이여야 합니다.
/// </summary>
private ObservableCollection<Student> StudentFilter { get; set; }
private CollectionViewSource StudentCollectionViewSource { get; set; }
public ICollectionView StudentCollection
{
get { return StudentCollectionViewSource.View; }
}
#endregion
public MainViewModel()
{
StudentFilter = new ObservableCollection<Student>();
AddDummyData();
StudentCollectionViewSource = new CollectionViewSource();
StudentCollectionViewSource.Source = this.StudentFilter;
StudentCollectionViewSource.Filter += ApplyFilter;
}
private void AddDummyData()
{
StudentFilter.Add(new Student { Age = 20, Country = "Korea", Name = "Henry" });
StudentFilter.Add(new Student { Age = 22, Country = "United States", Name = "James" });
StudentFilter.Add(new Student { Age = 24, Country = "Japan", Name = "Dami" });
StudentFilter.Add(new Student { Age = 21, Country = "Russia", Name = "Cad" });
StudentFilter.Add(new Student { Age = 18, Country = "China", Name = "이효성" });
StudentFilter.Add(new Student { Age = 17, Country = "China", Name = "Tim" });
StudentFilter.Add(new Student { Age = 17, Country = "Japan", Name = "Jane" });
StudentFilter.Add(new Student { Age = 17, Country = "Japan", Name = "Kiru" });
}
private void OnFilterChanged()
{
// Refresh하게되면 CollectionViewSource의 Source로 지정된 StudentFilter가 차례로 ApplyFilter의 FilterEventArgs로 들어가게 됩니다.
StudentCollectionViewSource.View.Refresh();
}
/// <summary>
/// 조건에 부합한다면 e.Accepted 에 true를, 그렇지 않다면 e.Accepted에 false를 넣어주면 됩니다.
/// </summary>
void ApplyFilter(object sender, FilterEventArgs e)
{
Student svm = (Student)e.Item;
// Filter Text 가 비어있다면 필터를 적용하지 않고 모든 콘텐츠를 보여주어야 하기때문에 true를 대입합니다.
if (string.IsNullOrWhiteSpace(this.Filter) || this.Filter.Length == 0)
{
e.Accepted = true;
}
else
{
// 대소문자 구분없이 찾기 위해 모두 소문자로 변경하여 검색하도록 합니다.
// 또한 완전 일치가 아닌 함유하고 있어도 찾기 위하여 Equals가 아닌 Contains를 사용하였습니다.
e.Accepted = svm.Name.ToLower().Contains(Filter.ToLower());
}
}
}
}
<!-- MainWindow.xaml -->
<Window x:Class="WPF_Listview_Filter.MainWindow"
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:WPF_Listview_Filter"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!-- 검색 영역 -->
<StackPanel Margin="3" Orientation="Horizontal" Grid.Row="0">
<TextBlock Margin="5" Text="이름으로 검색" VerticalAlignment="Center" FontWeight="Bold" FontSize="16"/>
<TextBox Width="400" Height="30" Padding="5" FontSize="14" HorizontalAlignment="Center" Margin="5" Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
<!-- ListView 영역 -->
<ListView Grid.Row="1" ItemsSource="{Binding StudentCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- DataTemplate 에는 하나의 자식만 허용하기 때문에 Grid로 감싸면 편리합니다. -->
<Grid>
<TextBlock FontSize="16">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}, Age: {1}, Country: {2}">
<Binding Path="Name" />
<Binding Path="Age" />
<Binding Path="Country" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
// MainWindow.cs
using System.Windows;
using WPF_Listview_Filter.ViewModels;
namespace WPF_Listview_Filter
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private MainViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = new MainViewModel();
this.DataContext = _viewModel;
}
}
}
전체 코드는 아래 링크에서 확인하실 수 있습니다.
github.com/Hyo-Seong/CHashtag/tree/master/WPF_Listview_Filter
감사합니다.
반응형
'C# > WPF' 카테고리의 다른 글
[C#] [WPF] DispatcherTimer 사용방법 (0) | 2021.02.24 |
---|---|
[C# WPF] Binding 값 자동 변환 Converter (IValueConverter, IMultiValueConverter) (1) | 2021.02.23 |
[C#] [WPF] MultiBinding StringFormat (여러개 동시 바인딩) (0) | 2021.02.21 |
[C#][WPF] MVVM패턴 CheckBox 양방향 Binding (0) | 2021.02.19 |
[C# WPF] MVVM 패턴 csv 파일 파싱 프로그램 (ListView, Binding, Prism) (0) | 2020.12.22 |