WPF 개발, INotifyCollectionChanged

WPF (Windows Presentation Foundation)는 Microsoft에서 제공하는 GUI 프레임워크로, 강력한 데이터 바인딩과 유연한 UI 설계를 지원합니다. WPF에서 컬렉션과 데이터를 다루는 것은 매우 중요하며, 이 과정에서 INotifyCollectionChanged 인터페이스가 핵심적인 역할을 합니다. 이 글에서는 INotifyCollectionChanged 인터페이스의 개념, 사용 방법, 그리고 실제 예제를 통해 이를 어떻게 활용할 수 있는지를 깊이 있게 설명하겠습니다.

INotifyCollectionChanged란?

INotifyCollectionChanged는 컬렉션에서 항목이 추가, 제거 또는 변경될 때 발생하는 변경 사항을 알리기 위한 이벤트를 제공하는 인터페이스입니다. 이 인터페이스는 주로 데이터 바인딩이 이루어지는 WPF와 같은 MVVM (Model-View-ViewModel) 아키텍처에서 사용됩니다.

뷰(View)는 모델(Model)로부터 데이터를 바인딩 받고, 모델의 변경 사항을 반영하기 위해서 INotifyCollectionChanged를 통해 이벤트를 수신합니다. 이 컬렉션의 변화가 발생하면 CollectionChanged 이벤트가 발생하여 UI가 자동으로 갱신됩니다.

INotifyCollectionChanged 인터페이스의 메서드

이 인터페이스는 다음과 같은 이벤트를 정의합니다.

  • CollectionChanged: 컬렉션의 변경 사항을 알리는 이벤트입니다. 이 이벤트는 다음과 같은 매개변수를 가집니다:
    • sender: 이벤트를 발생시킨 객체입니다.
    • args: NotifyCollectionChangedEventArgs 형식의 객체로, 변경된 내용에 대한 정보를 담고 있습니다.

또한, NotifyCollectionChangedEventArgs는 변화의 유형을 알려주는 NotifyCollectionChangedAction 열거형을 사용할 수 있습니다. 변화 유형에는 다음과 같은 것들이 있습니다:

  • Add: 항목이 추가되었습니다.
  • Remove: 항목이 제거되었습니다.
  • Replace: 항목이 대체되었습니다.
  • Move: 항목의 위치가 변경되었습니다.
  • Reset: 컬렉션이 초기화되었습니다.

예제: INotifyCollectionChanged의 사용

이제, INotifyCollectionChanged 인터페이스를 사용하는 간단한 예제를 살펴보겠습니다. 이 예제에서는 사용자 정의 컬렉션 클래스를 작성하고, 컬렉션의 변화에 따라 UI가 자동으로 업데이트되는 모습을 보여주겠습니다.

1단계: 사용자 정의 컬렉션 클래스 작성

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;

public class ObservableCollectionEx<T> : ICollection<T>, INotifyCollectionChanged 
{
    private readonly List<T> _items;

    public ObservableCollectionEx() 
    {
        _items = new List<T>();
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public void Add(T item) 
    {
        _items.Add(item);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
    }

    public void Remove(T item) 
    {
        if (_items.Remove(item)) 
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
        }
    }

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    {
        CollectionChanged?.Invoke(this, e);
    }

    public int Count => _items.Count;


    public bool IsReadOnly => false;

    public void Clear() 
    {
        _items.Clear();
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public bool Contains(T item) 
    {
        return _items.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex) 
    {
        _items.CopyTo(array, arrayIndex);
    }

    public IEnumerator<T> GetEnumerator() 
    {
        return _items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator() 
    {
        return GetEnumerator();
    }

    public bool Remove(T item) 
    {
        return _items.Remove(item);
    }
}

2단계: WPF 뷰(View) 만들기

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ListBox Name="ItemsListBox" />
        <Button Content="Add Item" Width="100" Height="30" Click="AddItem_Click" />
    </Grid>
</Window>

3단계: 코드 비하인드 작성

using System.Windows;

public partial class MainWindow : Window 
{
    private ObservableCollectionEx<string> _items;

    public MainWindow() 
    {
        InitializeComponent();
        _items = new ObservableCollectionEx<string>();
        _items.CollectionChanged += Items_CollectionChanged;
        ItemsListBox.ItemsSource = _items;
    }

    private void AddItem_Click(object sender, RoutedEventArgs e) 
    {
        _items.Add("New Item " + (_items.Count + 1));
    }

    private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    {
        // 컬렉션 변경 시 추가적인 처리를 이곳에 작성할 수 있습니다.
    }
}

최종 결과 확인

이제 프로그램을 실행하면 “Add Item” 버튼을 클릭할 때마다 새로운 항목이 ListBox에 추가됩니다. ListBox는 INotifyCollectionChanged 덕분에 컬렉션의 변화에 자동으로 반응하여 UI를 업데이트합니다.

결론

INotifyCollectionChanged 인터페이스는 WPF에서 데이터 바인딩을 통한 UI 업데이트를 매우 간편하게 만들어 줍니다. 이 인터페이스를 잘 활용하면 MVVM 아키텍처를 사용하는 WPF 애플리케이션을 보다 효율적으로 구성할 수 있습니다. 사용자 정의 컬렉션을 쉽게 만들고, UI와의 데이터 동기화를 간단히 처리할 수 있다는 점에서 매우 유용합니다.

이 글을 통해 INotifyCollectionChanged에 대한 이해와 사용 방법에 대해 충분히 알았기를 바랍니다. 더 복잡한 시나리오에서도 이 개념을 적용하여 WPF 애플리케이션에서 강력한 데이터 관리를 구현해 보세요.