UWP 개발, MVVM 프로그램 패턴 중 뷰모델 이해하기

현대 애플리케이션 개발에서 디자인 패턴은 소프트웨어 구조를 개선하고 유지보수를 용이하게 만들어줍니다. Windows 플랫폼에서의 차세대 앱 개발인 UWP (Universal Windows Platform) 에서는 MVVM (Model-View-ViewModel) 패턴이 널리 사용됩니다. 이 글에서는 MVVM 패턴과 그 구성 요소 중 하나인 뷰모델(ViewModel)에 대해 자세히 설명하고, 예제 코드를 통해 이해를 돕겠습니다.

1. MVVM 패턴 개요

MVVM은 애플리케이션 구조를 세 가지 주요 컴포넌트로 분리합니다: Model, View, ViewModel. 이 세 가지의 역할을 간략히 설명하면 다음과 같습니다:

  • Model: 애플리케이션의 데이터 및 비즈니스 로직을 담고 있는 부분입니다. 데이터를 가져오고 저장하는 역할을 하며, View 및 ViewModel과는 직접적으로 연결되지 않습니다.
  • View: 사용자에게 표시되는 UI 요소들을 나타냅니다. 사용자의 입력을 받거나 화면을 업데이트하는 역할을 하며, View의 변경은 ViewModel을 통해 이루어집니다.
  • ViewModel: Model과 View 사이의 중재자입니다. View에 표시할 데이터를 제공하고, 사용자의 입력을 처리하여 Model을 업데이트합니다. 이로 인해 View와 Model 간의 의존성이 줄어듭니다.

2. MVVM 패턴의 장점

MVVM 패턴을 사용할 때의 주요 장점 몇 가지는 다음과 같습니다:

  • 테스트 용이성: ViewModel은 UI와 분리되어 있기 때문에, Unit Testing을 통해 비즈니스 로직을 쉽게 검증할 수 있습니다.
  • 유지보수 용이성: UI와 비즈니스 로직이 분리되어 있어, 수정 시 다른 부분에 미치는 영향을 최소화합니다.
  • 코드의 재사용성: 동일한 ViewModel로 여러 뷰를 지원할 수 있어, 코드를 재사용하는 데 유리합니다.

3. ViewModel의 역할

ViewModel의 주된 역할은 다음과 같습니다:

  • 전달할 데이터를 준비하고, 이를 View에 표시하거나 업데이트합니다.
  • 사용자의 입력을 수신하고, 이를 Model에 전달하거나 비즈니스 로직을 처리합니다.
  • View와의 데이터 바인딩을 통해 UI를 자동적으로 업데이트합니다.

4. ViewModel의 구성 요소

ViewModel은 대개 다음과 같은 구성 요소로 이루어집니다:

  • 속성(Properties): View에 표시될 데이터를 담고 있는 속성입니다. INotifyPropertyChanged 인터페이스를 구현하여 데이터 변경을 UI에 통지합니다.
  • 커맨드(Commands): 사용자의 입력을 처리하는 메서드를 위임하는 객체입니다. ICommand 인터페이스를 통해 구현하며, UI에서 버튼 클릭과 같은 사용자 액션을 처리합니다.
  • 메서드(Methods): 비즈니스 로직을 구현하는 메서드입니다. Model을 업데이트 하거나 특정 작업을 수행합니다.

5. 예제: UWP에서의 ViewModel 구현

이제 UWP에서 간단한 MVVM 패턴을 구현해보도록 하겠습니다. 이 예제에서는 사용자가 입력한 이름을 받아서 인사말을 표시하는 간단한 애플리케이션을 만들 것입니다.

5.1. Model 정의

public class GreetingModel
{
    public string Name { get; set; }
}

5.2. ViewModel 정의

using System.ComponentModel;
using System.Windows.Input;

public class GreetingViewModel : INotifyPropertyChanged
{
    private GreetingModel _greetingModel;
    private string _greetingMessage;

    public GreetingViewModel()
    {
        _greetingModel = new GreetingModel();
        GreetCommand = new RelayCommand(ExecuteGreetCommand);
    }

    public string Name
    {
        get => _greetingModel.Name;
        set
        {
            if (_greetingModel.Name != value)
            {
                _greetingModel.Name = value;
                OnPropertyChanged(nameof(Name));
            }
        }
    }

    public string GreetingMessage
    {
        get => _greetingMessage;
        set
        {
            if (_greetingMessage != value)
            {
                _greetingMessage = value;
                OnPropertyChanged(nameof(GreetingMessage));
            }
        }
    }

    public ICommand GreetCommand { get; }

    private void ExecuteGreetCommand()
    {
        GreetingMessage = $"안녕하세요, {Name}님!";
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

5.3. RelayCommand 클래스 정의

using System;
using System.Windows.Input;

public class RelayCommand : ICommand
{
    private readonly Action _execute;
    private readonly Func _canExecute;

    public RelayCommand(Action execute, Func canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter) => _canExecute == null || _canExecute();

    public void Execute(object parameter) => _execute();

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }
}

5.4. View 정의

<Page
    x:Class="UWP_MVVM.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWP_MVVM"
    DataContext="{Binding GreetingViewModel, Source={StaticResource Locator}}">

    <StackPanel>
        <TextBox
            Width="300"
            Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <Button Command="{Binding GreetCommand}" Content="인사하기" />
        <TextBlock Text="{Binding GreetingMessage}" FontSize="24" />
    </StackPanel>
</Page>

6. 결론

MVVM 패턴은 UWP 애플리케이션의 구조를 개선하고, 개발 효율성을 높여줍니다. ViewModel은 핵심적인 역할을 하며, 이를 통해 View와 Model 간의 결합도를 줄일 수 있습니다. 이 글을 통해 MVVM 패턴과 ViewModel의 역할을 좀 더 깊이 이해했길 바랍니다.

더 많은 정보를 얻고 싶다면 다양한 온라인 자료나 문서를 참고하시기 바랍니다. MVVM 패턴을 활용하여 더 나은 UWP 애플리케이션을 개발하시길 바랍니다!