MVVM Sample for Wpf
์ด์ฒ ์ฐ
MVP ์์ ๊ฐ์ ํ ๊ฒ.
- C# WPF์ ICommand ๋ฅผ ์ด์ฉํ์ฌ
- View ์ ๋ฒํผ Event๋ฅผ Model์ Method ์ Bindingํ๋ ํด๋์ค ViewModel์ ๋ง๋ค๊ณ
- ์ด ViewModel์ View์ DataContext์ ํ ๋นํ์ฌ
- ViewModel๊ณผ View๋ฅผ ๋ถ๋ฆฌํ์๋ค.
-
๋จผ์ Wpf ํ๋ก์ ํธ(.Net 7)๋ฅผ ๋ง๋ ๋ค.
0-1. ํ๋ก์ ํธ ์์ฑ์์ 'Console Applicationโ์ ์ ํํ๋ค.
0-2. ํจํค์ง CommunityToolkit.Mvvm๋ฅผ ํ๋ก์ ํธ์ ์ถ๊ฐํ๋ค.
dotnet add package CommunityToolkit.Mvvm --version 8.2.2 -
Model.cs
using System;
using System.ComponentModel;
namespace MvvmSample.Wpf
{
public class Model : INotifyPropertyChanged
{
public Model() { }
public int Data
{
get => _data;
set
{
if (_data != value)
{
_data = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Data)));
Console.WriteLine(ToString());
}
}
}
private int _data = 0;
public void Reset() => Data = 0;
public void Increase() => Data++;
public override string ToString() => $"Data:{Data}";
public event PropertyChangedEventHandler? PropertyChanged;
}
}
- ViewModel.cs
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.ComponentModel;
namespace MvvmSample.Wpf
{
public class ViewModel : ObservableObject
{
public Model Model { get; init; }
public ViewModel(Model model)
{
Model = model;
ResetCommand = new RelayCommand(Model.Reset);
IncreaseCommand = new RelayCommand(Model.Increase);
}
public ICommand ResetCommand { get; }
public ICommand IncreaseCommand { get; }
}
}
- MainWindow.xaml.cs
using System.Windows;
namespace MvvmSample.Wpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel(new Model());
}
}
}
- MainWindow.xaml
<Window x:Class="MvvmSample.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MvvmSample.Wpf"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:ViewModel, IsDesignTimeCreatable=False}"
Title="MVVM for C# WPF" Height="120" Width="360" FontSize="14">
<DockPanel LastChildFill="False">
<DockPanel DockPanel.Dock="Top" LastChildFill="False">
<Label Content="Data" DockPanel.Dock="Left"/>
<TextBox Text="{Binding Path=Model.Data}" Width="100" TextAlignment="Right"/>
</DockPanel>
<DockPanel DockPanel.Dock="Top" LastChildFill="False">
<Button Content="Reset" Command="{Binding Path=ResetCommand}"/>
<Button Content="Increase" Command="{Binding Path=IncreaseCommand}"/>
</DockPanel>
</DockPanel>
</Window>
์ ๋ด์ฉ์ ์กฐ๊ธ ๊ณ ์นฉ๋๋ค.
MVVM์์ Model์ ๋ํ์ฌ ์ํคํผ๋์๋ฅผ ์ฐธ๊ณ ํ๋,
์ํ(real state content), ๋ฐ์ดํฐ ์ ๊ทผ ์ธต(data access layer) ๋๋ ๋ด์ฉ(content)์ด๋ผ๊ณ ํฉ๋๋ค.
์ ๋ ๋์(Processing)๊น์ง๋ฅผ ํฌํจํ๋ ์ค ์์์ต๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก ์ ์์ ์์ Model.cs์์,
๋ Method - Increase(), Reset() - ์ ViewModel.cs๋ก ์ฎ๊ธฐ๊ฒ ์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ , Model.Data๋ฅผ ์ฐธ์กฐํ๋ ํ๋กํผํฐ Data๋ฅผ ViewModel์ ์ถ๊ฐํ๊ณ ,
๋ Method๋ ์ถ๊ฐํ ํ๋กํผํฐ์ ๋ํด ๋์ํ๋๋ก ํฉ๋๋ค.
Model.cs์๋ Data๋ง ๋จ์ต๋๋ค.
MainWindow.xaml์์ Binding Path=Model.Data๋ Binding Path=Data๋ก ๋ฐ๊ฟ๋๋ค.
์ด ๋ถ๋ถ์ด View๊ฐ Model์ ์ฐธ์กฐํ ๊ณณ์ด์์ต๋๋ค.
ViewModel ์์ฑ์์์ Model์ ์์ฑํ๊ณ View์ Datacontext์ ํ ๋นํฉ๋๋ค.
Model์ ViewModel์ ์ฃผ์
ํ ๊ฒ์ด View๊ฐ Model์ ์ฐธ์กฐํ๋ ๊ฒ์ ์๋๋๋ค.
ViewModel์ Model์ ์ํ, ๋ด์ฉ, ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊พธ๋ ๋์์ด ์์ด์ผ ํ๋ค๋ ๊ฒ์ ์๊ฒ๋์์ต๋๋ค.
์๋๋ ์ฝ๋์
๋๋ค.
Model.cs
using System;
namespace MvvmSample.Wpf
{
public class Model
{
public Model() { Data = 0; }
public int Data
{
get => _data;
set
{
if (_data != value)
{
_data = value;
Console.WriteLine(this);
}
}
}
public int _data = 0;
public override string ToString() => $"Data:{Data}";
}
}
ViewModel.cs
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.ComponentModel;
namespace MvvmSample.Wpf
{
public class ViewModel : ObservableObject
{
public readonly Model _model;
public ViewModel()
{
_model = new Model();
ResetCommand = new RelayCommand(Reset);
IncreaseCommand = new RelayCommand(Increase);
}
public int Data
{
get => _model.Data;
set => SetProperty(_model.Data, value, _model, (u, n) => u.Data = n);
}
private void Increase()
{
Data++;
}
private void Reset()
{
Data = 0;
}
public ICommand ResetCommand { get; }
public ICommand IncreaseCommand { get; }
}
}
MainWindow.xaml
<Window x:Class="MvvmSample.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MvvmSample.Wpf"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:ViewModel, IsDesignTimeCreatable=False}"
Title="MVVM for C# WPF" Height="120" Width="360" FontSize="14">
<DockPanel LastChildFill="False">
<DockPanel DockPanel.Dock="Top" LastChildFill="False">
<Label Content="Data" DockPanel.Dock="Left"/>
<TextBox Text="{Binding Path=Data}" Width="100" TextAlignment="Right"/>
</DockPanel>
<DockPanel DockPanel.Dock="Top" LastChildFill="False">
<Button Content="Reset" Command="{Binding Path=ResetCommand}"/>
<Button Content="Increase" Command="{Binding Path=IncreaseCommand}"/>
</DockPanel>
</DockPanel>
</Window>
MainWindow.xaml.cs
using System.Windows;
namespace MvvmSample.Wpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
}