[SingletoneSean] WPF MVVM Tutorials(Commands / Navigation)
이 글은 [WPF MVVM Tutorials]을 수강하며 정리한 글입니다.
👉 기본 환경
- Language: C#, xaml
- IDE: Visual Basic 2022
Command 유효성 검사
namespace WPF_MVVM_Tutorial.Commands
{
public abstract class CommandBase : ICommand
{
public event EventHandler? CanExecuteChanged;
public virtual bool CanExecute(object? parameter)
{
return true;
}
public abstract void Execute(object? parameter);
protected void OnCanExecutedChanged()
{
CanExecuteChanged?.Invoke(this, new EventArgs());
}
}
}
namespace WPF_MVVM_Tutorial.Commands
{
public class MakeReservationCommand : CommandBase
{
private readonly MakeReservationViewModel _makeReservationViewModel;
public override bool CanExecute(object? parameter)
{
return !string.IsNullOrEmpty(_makeReservationViewModel.Username) && base.CanExecute(parameter);
}
}
}
CommnadBase를 상속받은 MakeReservationCommand에서
virtual 메서드로 선언하여 재정의할 수 있도록 만든 CanExecute 메서드에서 Validation 진행
Username이 공란일 경우, Submit Button에 연결된 MakeReservationCommand 비활성화
PropertyChanged 등록
public MakeReservationCommand(ViewModels.MakeReservationViewModel makeReservationViewModel, Hotel hotel)
{
_makeReservationViewModel = makeReservationViewModel;
_hotel = hotel;
_makeReservationViewModel.PropertyChanged += OnViewModelPropertyChanged;
}
public override bool CanExecute(object? parameter)
{
return !string.IsNullOrEmpty(_makeReservationViewModel.Username)
&& _makeReservationViewModel.FloorNumber > 0
&& _makeReservationViewModel.RoomNumber > 0
&& base.CanExecute(parameter);
}
private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == nameof(MakeReservationViewModel.Username)
|| (e.PropertyName == nameof(MakeReservationViewModel.FloorNumber))
|| (e.PropertyName == nameof(MakeReservationViewModel.RoomNumber)))
{
OnCanExecutedChanged();
}
}
⭐ makeReservationViewModel. PropertyChanged += OnViewModelPropertyChanged;
- makeReservationViewModel의 PropertyChanged 이벤트에 이벤트 핸들러인 OnViewModelPropertyChanged 메서드 추가
- PropertyChanged 이벤트가 발생하면 OnViewModelPropertyChanged 메서드를 호출
_makeReservationViewModel의 어떤 속성이 변하면, 그 변화를 감지하고 OnViewModelPropertyChanged 메서드를 실행하라는 지시
- OnViewModelPropertyChanged
- 이벤트 핸들러로, 이벤트가 발생했을 때 수행할 작업을 정의
- e.PropertyName를 통해 특정 속성의 변경에 따라 UI를 업데이트하거나 다른 작업을 수행하도록 함
Store View Change Event 설정
namespace WPF_MVVM_Tutorial.Stores
{
public class NavigationStore
{
private ViewModelBase _currentViewModel;
public ViewModelBase CurrentViewModel
{
get => _currentViewModel;
set
{
_currentViewModel = value;
OnCurrentViewModelChanged();
}
}
public event Action CurrentViewModelChanged;
private void OnCurrentViewModelChanged()
{
CurrentViewModelChanged?.Invoke();
}
}
}
NavigationStore
- CurrentViewModel 프로퍼티의 값이 변경될 때마다 CurrentViewModelChanged 이벤트가 발생
- 애플리케이션의 네비게이션 로직을 중앙에서 관리하고, 현재 활성화된 뷰모델이 변경될 때마다 이를 구독하는 객체에 알림
ViewModel과 View 연결
<Grid MaxWidth="600" Margin="20 10">
<Grid.Resources>
<DataTemplate DataType="{x:Type vms:MakeReservationViewModel}">
<views:MakeReservationView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:ReservationListingViewModel}">
<views:ReservationListingView/>
</DataTemplate>
</Grid.Resources>
<ContentControl Content="{Binding CurrentViewModel}"/>
</Grid>
ContentControl
- DataContext에서 데이터를 가져와 표시하는 컨트롤
- ViewModel을 바인딩 → ViewModel에 DataTemplate로 view 바인딩
CurrentViewModel Change
public class NavigationStore
{
private ViewModelBase _currentViewModel;
public ViewModelBase CurrentViewModel
{
get => _currentViewModel;
set
{
_currentViewModel = value;
OnCurrentViewModelChanged();
}
}
public event Action CurrentViewModelChanged;
private void OnCurrentViewModelChanged()
{
CurrentViewModelChanged?.Invoke();
}
}
namespace WPF_MVVM_Tutorial.ViewModels
{
public class MainViewModel : ViewModelBase
{
private readonly NavigationStore _navigationStore;
public MainViewModel(NavigationStore navigationStore)
{
_navigationStore = navigationStore;
_navigationStore.CurrentViewModelChanged += OnCurrentViewModelChanged;
}
private void OnCurrentViewModelChanged()
{
OnPropertyChanged(nameof(CurrentViewModel));
}
}
}
CurrentViewModel이 변경될 때마다 UI가 업데이트 되도록 CurrentViewModelChanged에 메서드 추가