19장. WPF MVVM, ListBox의 컬렉션 정렬, 필터링, 탐색 실습(ListCollectionView)
- C#/WPF
- 2021. 5. 17. 18:33
19장. WPF MVVM, ListBox의 컬렉션 정렬, 필터링, 탐색 실습(ListCollectionView)
참조
목적
- WPF MVVM, ListBox의 컬렉션 정렬, 필터링, 탐색 실습에 대해 학습합니다.
WPF, MVVM, ListBox의 컬렉션 정렬, 필터링, 탐색 실습
- ListCollectionView 클래스는 List를 구현하는 컬렉션에 대한 컬렉션의 뷰를 나타내며 이를 통해 컬렉션의 정렬, 필터링(검색), 탐색(앞/뒤/맨앞/맨뒤) 기능을 구현할 수 있습니다.
- 사원의 목록을 ListBox에 출력하고 상단의 버튼을 통해 정렬 기능을 구현하고 하단의 버튼을 통해 탐색, 필터링(검색) 기능을 구현해 보겠습니다.
MVVM 구조
- MVVM 패턴은 (Model - ViewModel- View) 의 줄임말입니다.
- Model은 Business Logic을 정의하고, Data Model을 정의합니다.
- 그리고 Model은 ViewModel에게 Property 변경을 통지해야 하기 때문에 INotifyProperty 인터페이스를 상속받습니다.
- ViewModel 은 Presentation Logic과 State를 정의합니다.
- ViewModel은 Model에서 속성들을 알고, 데이터를 Model에게 Update 합니다.
- View와 ViewModel은 Data Binding을 합니다.
실습
MainWindow.xaml
<Window x:Class="WPF17_Test.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:WPF17_Test"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="400">
<Window.Resources>
<local:EmpViewModel x:Key="emps"/>
<DataTemplate x:Key="template">
<Grid Width="400">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding Path=Empno}"/>
<TextBlock Grid.Column ="1"
Text="{Binding Path=Ename}"/>
<TextBlock Grid.Column="2"
Text="{Binding Path=Job}"/>
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel x:Name="rootElement"
DataContext="{Binding Source={StaticResource emps}}"
DataContextChanged="rootElement_DataContextChanged">
<Grid Width="400">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="20"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock HorizontalAlignment="Center"
Grid.ColumnSpan="3"
Text="사원 리스트"/>
<Button Grid.Row="1" Grid.Column="0"
Name="BtnEmpno" Content="Empno"
Click="OnClick"/>
<Button Grid.Row="1" Grid.Column="1"
Name="BtnEname" Content="Ename"
Click="OnClick"/>
<Button Grid.Row="1" Grid.Column="2"
Name="BtnJob" Content="Job"
Click="OnClick"/>
<ListBox Grid.Row="2" Grid.ColumnSpan="3" Name="empListBox"
ItemsSource="{Binding Source={StaticResource emps}}"
ItemTemplate="{StaticResource template}"
IsSynchronizedWithCurrentItem="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"/>
<TextBlock Foreground="Blue" Grid.Row="3" Grid.ColumnSpan="3"
Text="이전/이후/데이터필터링"/>
<Button Grid.Row="4" Grid.Column="0"
Content="Previous"
x:Name="Previous"
Click="OnMove"/>
<Button Grid.Row ="4" Grid.Column="1"
Content="Next"
x:Name="Next"
Click="OnMove"/>
<Button Grid.Row="4" Grid.Column="2"
Content="Show only Manager"
Click="OnFilter"/>
<TextBlock Grid.Row="5" Grid.Column="0"
Name="TblkEmpno"
Text="{Binding Path=Empno}"/>
<TextBlock Grid.Row="5" Grid.Column="1"
Name="TblkEname"
Text="{Binding Path=Ename}"/>
<TextBlock Grid.Row="5" Grid.Column="2"
Name="TblkJob"
Text="{Binding Path=Job}"/>
</Grid>
</StackPanel>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPF17_Test
{
/// <summary>
/// MainWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainWindow : Window
{
//컬렉션의 정렬, 필터링, 탐색 기능을 구현 가능하도록 지원
public ListCollectionView MycollectionView;
public Emp emp;
public MainWindow()
{
InitializeComponent();
}
private void rootElement_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
//StackPanel의 DataContext로 지정된 emps 컬렉션을 소스로 해서 ListCollectionView 생성
//이를 이용하여 정렬, 탐색, 필터링 기능 등을 구현한다.
MycollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(rootElement.DataContext);
}
/// <summary>
/// ListBox 상단의 정렬 기능 처리
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnClick(object sender, RoutedEventArgs e)
{
var b = sender as Button;
MycollectionView.SortDescriptions.Clear();
switch (b.Name)
{
case "BtnEmpno":
MycollectionView.SortDescriptions.Add(new System.ComponentModel.SortDescription
("Empno", System.ComponentModel.ListSortDirection.Ascending));
break;
case "BtnEname":
MycollectionView.SortDescriptions.Add(new System.ComponentModel.SortDescription
("Ename", System.ComponentModel.ListSortDirection.Ascending));
break;
case "BtnJob":
MycollectionView.SortDescriptions.Add(new System.ComponentModel.SortDescription
("Job", System.ComponentModel.ListSortDirection.Ascending));
break;
}
}
private void OnMove(object sender, RoutedEventArgs e)
{
var b = sender as Button;
switch (b.Name)
{
case "Previous":
if (MycollectionView.MoveCurrentToPrevious())
emp = MycollectionView.CurrentAddItem as Emp;
else
MycollectionView.MoveCurrentToFirst();
break;
case "Next":
if (MycollectionView.MoveCurrentToNext())
emp = MycollectionView.CurrentAddItem as Emp;
else
MycollectionView.MoveCurrentToLast();
break;
}
}
//필터링 기능, 관리자만 또는 관리자가 아닌 사원 리스트 출력
private void OnFilter(object sender, RoutedEventArgs e)
{
//토글 기능 구현
switch (MycollectionView.Filter)
{
//Filter 델리게이트는 보여줄 데이터인지 아닌지 판단할 수 있는 메서드 참조
case null: MycollectionView.Filter = IsManager; break; //관리자만
default: MycollectionView.Filter = null; break; //전체사원
}
}
private bool IsManager(object o)
{
var e = o as Emp;
return e?.Job == "Manager";
}
}
}
Emp.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WPF17_Test
{
/// <summary>
/// Model Class
/// </summary>
public class Emp : INotifyPropertyChanged
{
private int _empno;
private string _ename;
private string _job;
public event PropertyChangedEventHandler PropertyChanged;
public int Empno
{
get
{
return _empno;
}
set
{
_empno = value;
OnPropertyChanged("Empno");
}
}
public string Ename
{
get
{
return _ename;
}
set
{
_ename = value;
OnPropertyChanged("Ename");
}
}
public string Job
{
get
{
return _job;
}
set
{
_job = value;
OnPropertyChanged("Job");
}
}
public void OnPropertyChanged(string PName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PName));
}
}
}
EmpViewModel.cs
using System.Collections.ObjectModel;
namespace WPF17_Test
{
public class EmpViewModel : ObservableCollection<Emp>
{
public EmpViewModel()
{
Add(new Emp() { Empno = 1, Ename = "김길동", Job = "Salesman" });
Add(new Emp() { Empno = 2, Ename = "박길동", Job = "Clerk" });
Add(new Emp() { Empno = 3, Ename = "정길동", Job = "Clerk" });
Add(new Emp() { Empno = 4, Ename = "남길동", Job = "Clerk" });
Add(new Emp() { Empno = 5, Ename = "황길동", Job = "Salesman" });
Add(new Emp() { Empno = 6, Ename = "홍길동", Job = "Manager" });
}
}
}
실행 결과
728x90
'C# > WPF' 카테고리의 다른 글
[WPF] GridSplitter 컨트롤 Position 값 가져오기 (0) | 2021.05.20 |
---|---|
20장. WPF 계산기, MVVM, Command, 데이터바인딩이용 (2) | 2021.05.17 |
18장. WPF IValueConverter를 이용한 데이터바인딩, DataType이 다른 경우의 Data Binding (0) | 2021.05.15 |
14장. WPF Command패턴, 데이터바인딩 DataBinding 개요, 실습 (2) | 2021.05.14 |
13장. WPF 데이터바인딩 실습, INotifyPropertyChanged, PropertyChanged 이용 (0) | 2021.05.13 |
이 글을 공유하기