WPF MVVM Command ํจํด ์์ ์ ๋ณต - RelayCommand ๊ตฌํ
๐ WPF MVVM Command ํจํด ์์ ์ ๋ณต
WPF์์ MVVM ํจํด์ ์ฌ์ฉํ ๋ ๋ฒํผ ํด๋ฆญ ๋ฑ์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฐ์ฅ ์ค์ํ ๊ฐ๋
์ด Command ํจํด์
๋๋ค.
์ด ๊ธ์์๋ ICommand ์ธํฐํ์ด์ค์ RelayCommand ๊ตฌํ์ ์ค์ ์ฝ๋์ ํจ๊ป ์์ธํ ์๊ฐํฉ๋๋ค.
๐ ๋ชฉ์ฐจ
1. ์ Command ํจํด์ด ํ์ํ๊ฐ?
MVVM์์๋ View๊ฐ ViewModel์ ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถํ ์ ์์ต๋๋ค.
Command๋ View์ ViewModel ๊ฐ์ ๊ฐ์ ์ ์ธ ์ํธ์์ฉ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
- ๐ข ์ฝ๋ ๋นํ์ธ๋(XAML.cs)๋ฅผ ์ค์ด๊ณ ํ ์คํธ ๊ฐ๋ฅ์ฑ ํฅ์
- ๐ข Button, MenuItem, ListBox ๋ฑ ๋ค์ํ ์ปจํธ๋กค์์ ์ฌ์ฉ ๊ฐ๋ฅ
- ๐ข MVVM ๊ตฌ์กฐ๋ฅผ ์ ์งํ๋ฉด์ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๊ฐ๋ฅ
2. ICommand ์ธํฐํ์ด์ค ๊ตฌ์กฐ
WPF์ ๋ชจ๋ ์ปค๋งจ๋๋ ICommand
๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
public interface ICommand
{
event EventHandler CanExecuteChanged;
bool CanExecute(object parameter);
void Execute(object parameter);
}
- `CanExecute()`๋ ์ปค๋งจ๋ ์คํ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ฐํ (๋ฒํผ ํ์ฑํ ์กฐ๊ฑด ๋ฑ)
- `Execute()`๋ ์ปค๋งจ๋๊ฐ ์คํ๋ ๋ ํธ์ถ๋๋ ๋ฉ์๋
3. RelayCommand ๊ตฌํ
๋ฐ๋ณต์ ์ธ ICommand ๊ตฌํ์ ์ค์ด๊ธฐ ์ํด ๋ณดํต RelayCommand ๋๋ DelegateCommand๋ฅผ ์ง์ ๋ง๋ค์ด ์ฌ์ฉํฉ๋๋ค.
โ๏ธ ๊ธฐ๋ณธ RelayCommand ๊ตฌํ
using System;
using System.Windows.Input;
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
this.execute = execute ?? throw new ArgumentNullException(nameof(execute));
this.canExecute = canExecute;
}
public bool CanExecute(object parameter) => canExecute == null || canExecute(parameter);
public void Execute(object parameter) => execute(parameter);
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
4. ์ค์ต ์์ : ๋ฒํผ ํด๋ฆญ์ผ๋ก ๋ฉ์์ง ๋ณ๊ฒฝ
โ๏ธ MainWindow.xaml
<Window x:Class="CommandSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CommandSample"
Title="Command ์์ " Height="200" Width="400">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Message}" FontSize="20" Margin="0,0,0,10"/>
<Button Content="๋ณ๊ฒฝํ๊ธฐ" Command="{Binding ChangeMessageCommand}" Width="120"/>
</StackPanel>
</Window>
โ๏ธ MainViewModel.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace CommandSample
{
public class MainViewModel : INotifyPropertyChanged
{
private string message = "์ด๊ธฐ ๋ฉ์์ง";
public string Message
{
get => message;
set { message = value; OnPropertyChanged(); }
}
public ICommand ChangeMessageCommand { get; }
public MainViewModel()
{
ChangeMessageCommand = new RelayCommand(_ =>
{
Message = "Command๋ก ๋ณ๊ฒฝ๋จ!";
});
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
5. CanExecute ์กฐ๊ฑด ์ฌ์ฉ ์
์ฌ์ฉ์๊ฐ ์กฐ๊ฑด์ ๋ง์กฑํ ๋๋ง ๋ฒํผ์ ํ์ฑํํ๊ณ ์ถ์ ๋๋ CanExecute
๋ฅผ ์ค์ ํ๋ฉด ๋ฉ๋๋ค.
ChangeMessageCommand = new RelayCommand(
execute: _ => Message = "์กฐ๊ฑด ๋ง์กฑ!",
canExecute: _ => Message.Length < 10
);
์ ์ฝ๋์์๋ ๋ฉ์์ง ๊ธธ์ด๊ฐ 10์ ๋ฏธ๋ง์ผ ๋๋ง ๋ฒํผ์ด ํ์ฑํ๋ฉ๋๋ค.
WPF๋ CommandManager.RequerySuggested
๋ฅผ ํตํด ์๋์ผ๋ก UI ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
6. ๋ง๋ฌด๋ฆฌ ๋ฐ ๋ค์ ๊ธ ์๋ด
MVVM์์ Command ํจํด์ View์ ViewModel์ ์ฐ๊ฒฐํ๋ ํต์ฌ ์ญํ ์ ํฉ๋๋ค.
RelayCommand๋ ์ด๋ฅผ ํจ์จ์ ์ผ๋ก ๊ตฌํํ ์ ์๋ ๋๊ตฌ์ด๋ฉฐ, ์ค๋ฌด์์๋ ๊ฑฐ์ ๋ชจ๋ ํ๋ก์ ํธ์์ ํ์ฉ๋ฉ๋๋ค.
๋ค์ ์๋ฆฌ์ฆ์์๋ UserControl๊ณผ CustomControl์ ์ฐจ์ด์ ๊ณผ ์ค์ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ํด ์๊ฐํ ์์ ์ ๋๋ค.
์ด ๊ธ์ด ๋์์ด ๋์ จ๋ค๋ฉด ๋๊ธ๊ณผ ๊ณต์ ๋ถํ๋๋ ค์! ๐