[MVVM] 10.MVVM과 WPF에서 성능 최적화, Data Virtualization과 Lazy Loading을 활용한 성능 향상

작성일: 2023년 10월 15일

저자: 조광형

목차

  1. 소개
  2. MVVM 패턴과 성능
  3. Data Virtualization
  4. Lazy Loading
  5. 구현 예제
  6. 결론

1. 소개

Windows Presentation Foundation (WPF)는 Microsoft의 UI 프레임워크로, 강력하고 유연한 데스크탑 애플리케이션을 구축하는 데 사용됩니다. MVVM(Model-View-ViewModel) 패턴은 WPF 애플리케이션에서 UI와 비즈니스 로직을 분리함으로써 유지보수성과 테스트 가능성을 높이는 데 기여합니다. 그러나 어떤 프레임워크나 패턴처럼, MVVM을 올바르게 활용하지 않으면 성능 문제가 발생할 수 있습니다. 이 글에서는 WPF 애플리케이션의 성능 최적화를 위해 Data Virtualization과 Lazy Loading을 활용하는 방법을 설명하겠습니다.

2. MVVM 패턴과 성능

MVVM은 세 가지 주 구성 요소로 이루어져 있습니다: Model, View, ViewModel. 이 패턴은 데이터 바인딩을 통해 View와 ViewModel 간의 상호작용을 단순화합니다. 하지만 데이터 집합이 매우 클 경우, ViewModel의 크기와 데이터가 UI에 바인딩되는 방식이 성능에 큰 영향을 미칠 수 있습니다.

예를 들어, 수천 개의 항목을 포함하는 ListBox를 생각해 봅시다. ViewModel이 모든 항목 정보를 포함하고 있다면, UI는 이러한 모든 항목을 렌더링하려고 시도하게 됩니다. 이 경우 렌더링 성능 저하 및 메모리 부족 문제가 발생할 수 있습니다.따라서, WPF 애플리케이션의 성능을 최적화하기 위해 데이터 가상화와 레이지 로딩 같은 기법을 활용해야 합니다.

3. Data Virtualization

Data Virtualization은 대량의 데이터를 효율적으로 처리할 수 있는 기법입니다. 이 기술을 사용하면 UI 요소가 표시되는 시점에 필요한 데이터만 가져와 메모리 사용량을 최소화합니다. WPF에서 Data Virtualization을 구현하는 일반적인 접근 방법은 VirtualizingStackPanel을 사용하는 것입니다.

VirtualizingStackPanel은 항목이 실제로 화면에 표시될 때에만 렌더링되도록 하는 패널입니다. 이 패널은 뷰포트(현재 보이는 영역) 내에서 필요한 항목만 표시하여 메모리 사용과 초기 렌더링 시간을 줄여줍니다.

3.1. Data Virtualization 구현 예

public class MainViewModel
{
    private ObservableCollection<Item> allItems;

    public ObservableCollection<Item> VisibleItems { get; private set; }

    public MainViewModel()
    {
        this.allItems = new ObservableCollection<Item>();
        this.VisibleItems = new ObservableCollection<Item>();
        LoadItems();
    }

    private void LoadItems()
    {
        // 여기서 데이터를 초기화합니다.
        for (int i = 0; i < 10000; i++)
        {
            this.allItems.Add(new Item { Name = $"Item {i}" });
        }
    }

    public void UpdateVisibleItems(int startIndex, int count)
    {
        VisibleItems.Clear();
        for (int i = startIndex; i < startIndex + count && i < allItems.Count; i++)
        {
            VisibleItems.Add(allItems[i]);
        }
    }
}

4. Lazy Loading

Lazy Loading은 필요한 데이터가 요청될 때만 데이터베이스나 API에서 가져오는 방식입니다. 이 기법은 초기 로딩 시간과 메모리 사용량을 줄이는 데 매우 유용합니다. Lazy Loading을 구현하면 사용자가 필요로 하는 데이터만 즉각적으로 로드되므로 남은 데이터는 사용자가 특정 액션을 취하기 전까지 로드되지 않습니다.

4.1. Lazy Loading 구현 예

public class ItemRepository
{
    public async Task<List<Item>> GetItemsAsync(int pageNumber, int pageSize)
    {
        using (var context = new MyDbContext())
        {
            return await context.Items
                .Skip((pageNumber - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();
        }
    }
}

위의 예제는 Entity Framework를 사용하여 데이터베이스에서 항목을 가져오는 간단한 Lazy Loading 구현을 보여줍니다. 페이지 번호와 페이지 크기를 지정하여 필요한 데이터만 로드할 수 있습니다. 이를 통해 사용자가 스크롤을 내리면서 추가 데이터를 요청할 수 있도록 하여 성능을 최적화할 수 있습니다.

5. 구현 예제

이제 MVVM, Data Virtualization 및 Lazy Loading을 결합하여 WPF 애플리케이션을 구현하는 방법을 살펴보겠습니다. 아래는 이러한 기술을 적용한 간단한 WPF 애플리케이션의 예입니다.

5.1. XAML 코드

<Window x:Class="WpfApp.MainWindow"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               Title="MVVM Performance Example" Height="450" Width="800">
    <Grid>
        <ListBox ItemsSource="{Binding VisibleItems}" 
                 VirtualizingStackPanel.IsVirtualizing="True" 
                 VirtualizingStackPanel.VirtualizationMode="Recycling">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

5.2. ViewModel 연결

public partial class MainWindow : Window
{
    private MainViewModel viewModel;

    public MainWindow()
    {
        InitializeComponent();
        viewModel = new MainViewModel();
        DataContext = viewModel;

        // 초기 데이터 로드를 위해 VisibleItems를 업데이트합니다.
        viewModel.UpdateVisibleItems(0, 100);
    }
}

위의 코드는 기본적인 WPF 애플리케이션의 구조를 보여 줍니다. 이처럼 MVVM 패턴을 사용하고 Data Virtualization과 Lazy Loading을 조합하여 성능을 최적화할 수 있습니다. 사용자가 스크롤할 때마다 UpdateVisibleItems 메서드를 호출하여 현재 범위에 해당하는 데이터만 요청하여 표시할 수 있습니다.

6. 결론

WPF 애플리케이션에서 MVVM 패턴을 따르는 것만으로는 성능 문제를 해결할 수 없습니다. 하지만 Data Virtualization과 Lazy Loading 같은 기법을 사용하면 대량의 데이터를 효율적으로 처리할 수 있습니다. 이 두 가지 기법을 결합하여 메모리 사용량을 줄이고 UI의 반응성을 향상시키는 것이 가능합니다. 이번 블로그 글을 통해 MVVM에서의 성능 최적화 기법을 이해하고, 실제 예제들을 통해 구현 방법을 배웠기를 바랍니다.

앞으로 더 나은 WPF 애플리케이션을 개발하는 데 이 글이 도움이 되기를 바랍니다!