(동영상)WPF, MVVM, ListBox의 컬렉션 정렬, 필터링, 탐색 실습(ListCollectionView)
n ListCollectionView 클래스는 List를 구현하는 컬렉션에 대한 컬렉션의 뷰를 나타내며 이를 통해 컬렉션의 정렬, 필터링(검색), 탐색(앞/뒤/맨앞/맨뒤) 기능을 구현할 수 있습니다.
n 사원의 목록을 ListBox에 출력하고 상단의 버튼을 통해 정렬 기능을 구현하고 하단의 버튼을 통해 탐색, 필터링(검색) 기능을 구현해 보겠습니다.
n 실행화면
n 프로젝트명 : DataBindingSortExam
n MainWindow.xaml
n Emp.cs(모델)
using System;
using System.ComponentModel;
namespace DataBindingSortExam
{
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));
}
}
}
n EmpViewModel.cs(뷰모델)
using System.Collections.ObjectModel;
namespace DataBindingSortExam
{
class EmpVlewModel : ObservableCollection<Emp>
{
public EmpVlewModel ()
{
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" });
}
}
}
<Window x:Class="DataBindingSortExam.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:DataBindingSortExam"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="600">
<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 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 Name="rootElement"
DataContext="{Binding Source={StaticResource emps}}"
DataContextChanged="DCChange">
<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">사원 리스트</TextBlock>
<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">이전/이후/데이터필터링</TextBlock>
<Button Grid.Row="4" Grid.Column="0" Name="Previous" Click="OnMove">Previous</Button>
<Button Grid.Row="4" Grid.Column="1" Name="Next" Click="OnMove">Next</Button>
<Button Grid.Row="4" Grid.Column="2" Name="Filter" Click="OnFilter">Show only Manager</Button>
<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>
n MainWindow.xaml.cs
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace DataBindingSortExam
{
public partial class MainWindow : Window
{
// 컬렉션의 정렬, 필터링, 탐색 기능을 구현가능하도록 지원
public ListCollectionView MyCollectionView;
public Emp emp;
public MainWindow()
{
InitializeComponent();
}
public void DCChange(object sender, DependencyPropertyChangedEventArgs args)
{
// StackPanel의 DataContext로 지정된 emps 컬렉션을 소스로 해서 ListCollectionView 생성
// 이를 이용하여 정렬, 탐색, 필터링 기능 등을 구현한다.
MyCollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(rootElement.DataContext);
}
// 리스트박스 상단의 정렬 기능 처리
private void OnClick(object sender, RoutedEventArgs e)
{
var b = sender as Button;
MyCollectionView.SortDescriptions.Clear();
switch(b.Name)
{
case "BtnEmpno":
MyCollectionView.SortDescriptions.Add(new SortDescription("Empno", ListSortDirection.Ascending));
break;
case "BtnEname":
MyCollectionView.SortDescriptions.Add(new SortDescription("Ename", ListSortDirection.Ascending));
break;
case "BtnJob":
MyCollectionView.SortDescriptions.Add(new SortDescription("Job", ListSortDirection.Ascending));
break;
}
}
//Prevous, Next 버튼 처리
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)
{
//관리자만
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";
}
}
}