WPF 데이터 뷰의 동작 원리와 활용 기법

데이터 뷰의 역할

컬렉션을 ItemsControl에 바인딩하면 백그라운드에서 데이터 뷰가 자동 생성됩니다. 뷰는 데이터 소스와 컨트롤 사이에서 중개자 역할을 수행하며, 현재 항목 추적, 정렬, 필터링, 그룹화 기능을 제공합니다. 동일한 데이터를 다양한 방식으로 표현할 수 있어 애플리케이션의 다른 영역에서 각기 다른 형태로 데이터를 표시할 수 있습니다.

뷰 객체 유형

데이터 소스 유형에 따라 다양한 뷰 객체가 생성됩니다:

  • IBindingList 구현체: BindingListCollectionView 생성 (예: ADO.NET DataTable)
  • IList 구현체: ListCollectionView 생성 (예: ObservableCollection)
  • IEnumerable 구현체: 기본 CollectionView 생성

뷰 객체 획득

현재 사용 중인 뷰 객체는 GetDefaultView() 정적 메서드로 획득합니다:

ListCollectionView dataView = 
    (ListCollectionView)CollectionViewSource.GetDefaultView(productList.ItemsSource);

뷰 내비게이션 구현

뷰 객체는 CurrentItem 속성으로 현재 데이터 객체를, CurrentPosition으로 위치 인덱스를 추적합니다. 레코드 간 이동 메서드:

dataView.MoveCurrentToFirst();
dataView.MoveCurrentToLast();
dataView.MoveCurrentToNext();
dataView.MoveCurrentToPrevious();

뷰 참조 저장 및 위치 표시:

private ListCollectionView dataView;

void InitializeView()
{
    var items = App.ProductRepository.FetchProducts();
    this.DataContext = items;
    
    dataView = (ListCollectionView)
        CollectionViewSource.GetDefaultView(this.DataContext);
    dataView.CurrentChanged += ViewCurrentChanged;
}

void ViewCurrentChanged(object sender, EventArgs e)
{
    positionLabel.Content = $"레코드 {dataView.CurrentPosition + 1} / {dataView.Count}";
    prevButton.IsEnabled = dataView.CurrentPosition > 0;
    nextButton.IsEnabled = dataView.CurrentPosition < dataView.Count - 1;
}

콤보박스와 동기화

ItemsControl.IsSynchronizedWithCurrentItem 속성으로 간편한 동기화:

<ComboBox Name="itemSelector" DisplayMemberPath="ProductName"
          IsSynchronizedWithCurrentItem="True"/>

선언적 뷰 생성

XAML에서 CollectionViewSource를 정의하여 뷰 생성:

<CollectionViewSource x:Key="CategoryViewSource">
  <CollectionViewSource.SortDescriptions>
    <component:SortDescription PropertyName="Category" Direction="Ascending"/>
  </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

코드에서 데이터 소스 연결:

var viewSource = (CollectionViewSource)FindResource("CategoryViewSource");
viewSource.Source = App.ProductRepository.FetchProducts();

데이터 조작 기법

필터링

Predicate 대리자를 이용한 필터링 구현:

void ApplyPriceFilter()
{
    dataView.Filter = item => 
    {
        Product productItem = item as Product;
        return productItem?.UnitPrice > minPriceFilter.Value;
    };
}

필터 갱신:

void UpdateFilter()
{
    if (dataView != null)
    {
        dataView.Refresh();
    }
}

정렬

SortDescription을 이용한 기본 정렬:

dataView.SortDescriptions.Add(
    new SortDescription("ProductName", ListSortDirection.Ascending));

사용자 정의 정렬:

class NameLengthSorter : IComparer
{
    public int Compare(object x, object y)
    {
        return ((Product)x).Name.Length.CompareTo(((Product)y).Name.Length);
    }
}

dataView.CustomSort = new NameLengthSorter();

그룹화

PropertyGroupDescription을 이용한 기본 그룹화:

dataView.GroupDescriptions.Add(new PropertyGroupDescription("Category"));

그룹 헤더 템플릿:

<ListBox.GroupStyle>
  <GroupStyle>
    <GroupStyle.HeaderTemplate>
      <DataTemplate>
        <TextBlock Text="{Binding Name}" FontWeight="Bold" 
                   Background="LightBlue" Padding="5"/>
      </DataTemplate>
    </GroupStyle.HeaderTemplate>
  </GroupStyle>
</ListBox.GroupStyle>

범위 그룹화

값 변환기를 이용한 범위 기반 그룹화:

class PriceRangeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
                          CultureInfo culture)
    {
        decimal price = (decimal)value;
        return $"{Math.Floor(price / 50)}00-{Math.Floor(price / 50) + 1}00";
    }
}

태그: WPF 데이터뷰 컬렉션뷰 필터링 정렬

5월 21일 17:44에 게시됨