1. MVVM
[View (XAML)]
↓ Binding
[ViewModel]
↓ 데이터 처리
[Model]
2. Model(Data)
- 데이터
- UI 를 알 필요없음
- 로직 X
public class Car
{
public string Name { get; set; }
public int Speed { get; set; }
}
3. ViewModel
1) 역할
- UI에 보여줄 데이터 관리(Model > ViewModel > View)
- UI 이벤트 처리(View > ViewModel > Model)
- 상태 변경
2) 핵심 기능
- Property(데이터 처리)
- Command(명령)
using System.ComponentModel;
using System.Windows.Input;
public class MainViewModel : INotifyPropertyChanged
{
private Car _car;
public MainViewModel()
{
_car = new Car
{
Name = "Tesla",
Speed = 0
};
StartCommand = new RelayCommand(Start);
StopCommand = new RelayCommand(Stop);
}
// 바인딩 속성
public string CarName
{
get => _car.Name;
set
{
_car.Name = value;
OnPropertyChanged(nameof(CarName));
}
}
public int Speed
{
get => _car.Speed;
set
{
_car.Speed = value;
OnPropertyChanged(nameof(Speed));
}
}
// Command (명령)
public ICommand StartCommand { get; }
public ICommand StopCommand { get; }
private void Start()
{
Speed = 100;
}
private void Stop()
{
Speed = 0;
}
// Binding 필수 구현
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
3.1 PropertyChangedEventHandler(Property 구현)
※ 위 ViewModel 참고
1) 바인딩 속성에 있어 Property 형식이 필요한 이유
public string CarName
{
get => _car.Name;
set
{
_car.Name = value;
OnPropertyChanged(nameof(CarName));
}
}
- 이유) string 데이터를 일반 변수가 아닌 Property로 구현 : 바인딩한 View에게 알림을 주기 위해서임.
- 예를 들어) public string CarName이 일반변수인 경우 CarName의 값이 변경되어도 View는 알 방법이 없음.
- 따라서) 값이 변경되는 경우(Property : set) → OnPropertyChanged() 를 호출함으로써 View에게 알림을 주는 것.
2) PropertyChangedHandler 객체
public event PropertyChangedEventHandler PropertyChanged;
- PropertyChangedEventHandler 객체인 PropertyChanged 를 생성한다.
3) OnPropertyChanged() 메서드
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
- 위 바인딩 속성의 set 에서 호출하는 메서드를 구현한다.
3.2 RelayCommand(Command 구현)
1) RelayCommand 가 필요한 이유
- MVVM 내부 구조는 아래처럼 진행됨
[사용자 컨트롤 사용]
↓
[컨트롤]
↓
Command.Execute() 호출 (내부적)
↓
RelayCommand.Execute()
↓
Start() 와 같은 바인딩 메서드 실행
2) ViewModel 에서 사용되는 구조
public ICommand StartCommand { get; }
public ICommand StopCommand { get; }
private void Start()
{
Speed = 100;
}
private void Stop()
{
Speed = 0;
}
> ICommand 형 Command 생성
public MainViewModel()
{
_car = new Car
{
Name = "Tesla",
Speed = 0
};
StartCommand = new RelayCommand(Start);
StopCommand = new RelayCommand(Stop);
}
> 해당 객체를 RelayCommand 형으로 동적 생성
> RelayCommand 는 ICommand 를 상속하는 구조로써 객체지향 프로그래밍 특징 중 하나인 다형성을 활용해 기반 클래스 객체이더라도 파생클래스 형태로 동적으로 생성할 수 있다.
3) RelayCommand 구현
using System;
using System.Windows.Input;
public class RelayCommand : ICommand
{
private readonly Action _execute;
public RelayCommand(Action execute)
{
_execute = execute;
}
public bool CanExecute(object parameter) => true;
public void Execute(object parameter)
{
_execute();
}
public event EventHandler CanExecuteChanged;
}
3.1) Excute() 호출 구조 : MainViewModel의 Startcommand 기준
1. RelayCommand 형 객체 동적 생성
StartCommand = new RelayCommand(Start);
2. RelayCommand 의 생성자에 의해 _excute == Start() 가 됨
3. 사용자의 Control 사용
4. Control 은 Command.Excute() 호출(WPF 내부적 호출)
5. 바인딩된 RelayCommand.Excute() 호출
6. _excute() 호출 == Start() 호출
3.2) CanExcute() 호출 구조
1. 내부적으로 Control은 아래처럼 작동
if (Command.CanExecute(null))
{
버튼 활성화
}
else
{
버튼 비활성화
}
2. Control 활성화
public bool CanExecute(object parameter) => true;
> 항상 CanExcute 가 true 를 반환하도록 구현하였으므로, 언제나 Control은 활성화되어 있다.
4. View(XAML)
<Window x:Class="MVVMTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Margin="20">
<TextBlock Text="Car Name"/>
<TextBox Text="{Binding CarName, Mode=TwoWay}" />
<TextBlock Text="Speed"/>
<TextBlock Text="{Binding Speed}" FontSize="20"/>
<Button Content="Start"
Command="{Binding StartCommand}"
Margin="0,10,0,0"/>
<Button Content="Stop"
Command="{Binding StopCommand}"/>
</StackPanel>
</Window>
1) UI 표시(데이터 바인딩)
<TextBlock Text="Car Name"/>
<TextBox Text="{Binding CarName, Mode=TwoWay}" />
<TextBlock Text="Speed"/>
<TextBlock Text="{Binding Speed}" FontSize="20"/>
> Property Data 를 Text 에 Binding 하여 사용함
2) Contrl(명령 바인딩)
<Button Content="Start"
Command="{Binding StartCommand}"
Margin="0,10,0,0"/>
<Button Content="Stop"
Command="{Binding StopCommand}"/>
> Command 를 Control(Button) 에 Binding 하여 사용함
4.1 ViewModel - View 연결
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
DataContext = new MainViewModel();
> 해당 내용은 View 는 MainViewModel 을 기준으로 사용한다 라는 의미임.
'FRAMEWORK > WPF' 카테고리의 다른 글
| WPF : ViewModel - DI(의존성 주입) (0) | 2026.04.25 |
|---|---|
| WPF : Model (0) | 2026.04.25 |
| WPF : 타이머 만들기 (0) | 2026.04.23 |
| WPF : WPF 에 대하여 (0) | 2026.04.22 |
