Prism에서 DelegateCommand를 하는 방법
https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/11-UsingDelegateCommands
참고 코드
https://github.com/2Bbear/WindowsProgrmaDevelop/tree/master/WPF/UsingMvvmPrismLibrary/11-UsingDelegateCommands
내가 만든 코드
기본적인 코드는 비슷하니 패스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | using System; using Prism.Commands; using Prism.Mvvm; namespace UsingDelegateCommands.ViewModels { public class MainWindowViewModel : BindableBase { private bool _isEnabled; public bool IsEnabled { get { return _isEnabled; } set { SetProperty(ref _isEnabled, value); ExecuteDelegateCommand.RaiseCanExecuteChanged(); } } private string _updateText; public string UpdateText { get { return _updateText; } set { SetProperty(ref _updateText, value); } } public DelegateCommand ExecuteDelegateCommand { get; private set; } public DelegateCommand<string> ExecuteGenericDelegateCommand { get; private set; } public DelegateCommand DelegateCommandObservesProperty { get; private set; } public DelegateCommand DelegateCommandObservesCanExecute { get; private set; } public MainWindowViewModel() { Console.WriteLine("JJH: MainWindowViewModel MainWindowViewModel"); ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute); DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => IsEnabled); DelegateCommandObservesCanExecute = new DelegateCommand(Execute).ObservesCanExecute(() => IsEnabled); ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric).ObservesCanExecute(() => IsEnabled); } private void Execute() { Console.WriteLine("JJH: MainWindowViewModel Execute"); UpdateText = $"Updated: {DateTime.Now}"; } private void ExecuteGeneric(string parameter) { Console.WriteLine("JJH: MainWindowViewModel ExecuteGeneric"); UpdateText = parameter; } private bool CanExecute() { Console.WriteLine("JJH: MainWindowViewModel CanExecute"); return IsEnabled; } } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <Window x:Class="UsingDelegateCommands.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" Title="Using DelegateCommand" Width="350" Height="275"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <CheckBox IsChecked="{Binding IsEnabled}" Content="Can Execute Command" Margin="10"/> <Button Command="{Binding ExecuteDelegateCommand}" Content="DelegateCommand" Margin="10"/> <Button Command="{Binding DelegateCommandObservesProperty}" Content="DelegateCommand ObservesProperty" Margin="10"/> <Button Command="{Binding DelegateCommandObservesCanExecute}" Content="DelegateCommand ObservesCanExecute" Margin="10"/> <Button Command="{Binding ExecuteGenericDelegateCommand}" CommandParameter="Passed Parameter" Content="DelegateCommand Generic" Margin="10"/> <TextBlock Text="{Binding UpdateText}" Margin="10" FontSize="22"/> </StackPanel> </Window> | cs |
MainWindowViewModel 과 MainWindow가 XAML에서 ViewModelLocator로 연결되어 있는 상태이다.
메인윈도우 뷰모델을 확인하면.
IsChecked 컨트롤은 IsEnabled 프로퍼티와 연결되어 있다. 이게 two way인가보다 프로퍼티의 상태를 보면
get과 set이 있는데, get의 경우 단순히 _isEnabled를 반환하고
set의 경우 _isEnabled를 value값으로 초기화하고, ExecuteDelegateCommand.RaiseCanExecuteChanged();를 실행시킨다.
프로그램의 실행 순서로 보았을 때, 생성자가 제일먼저 실행되고 그 뒤에 CanExecute가 실행되는 것을 확인 할 수 있다.
생성자를 살펴보면
1 2 3 4 5 6 7 8 9 10 11 12 | public MainWindowViewModel() { Console.WriteLine("JJH: MainWindowViewModel MainWindowViewModel"); ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute); DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => IsEnabled); DelegateCommandObservesCanExecute = new DelegateCommand(Execute).ObservesCanExecute(() => IsEnabled); ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric).ObservesCanExecute(() => IsEnabled); Console.WriteLine("JJH: MainWindowViewModel MainWindowViewModel end"); } | cs |
이렇게 구성되어 있는데,
ExecuteDelegateCommand는 버튼의 DelegateCommand에 붙어있다.
ExecuteDelegateCommand는 이렇게 public DelegateCommand ExecuteDelegateCommand { get; private set; } 프로퍼티로 선언되어 있다.
이 ExecuteDelegateCommand에 들어간 new DelegateCommand(Execute, CanExecute);를 살펴보면
DelegateCommand를 생성하여 담았는데, 첫번째 매개변수에 실행할 함수, 두번째 매개변수에 CanExecute 즉 실행 여부 함수를 담아야 한다.
따라서 DelegateCommand버튼을 누를 경우 실행 순서가 CanExecute ->Execute 순으로 일어나게 될 것이다.
CanExecute가 먼저 실행되고 그 뒤에 Execute가 실행되는 모습을 볼 수 있다.
따라서 DelegateCommand(실행할 메소드, 실행 여부 판단 메소드)로 구성되는 것을 알 수 있었다.
==================================================================
이제 DelegateCommand ObservesProperty에 대해 확인해보면
해당 버튼은 DelegateCommandObservesProperty라는 프로퍼티와 연결되어 있다.
생성자에서 DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => IsEnabled); 이렇게 DelegateCommand가 붙어있는데 기본적인 딜리게이트 커맨드의 생성자는 이해했지만 ObservesProperty가 뭔지 모르겠다.
선언문을 확인해보면
//
// 요약:
// Observes a property that implements INotifyPropertyChanged, and automatically
// calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
//
// 매개 변수:
// propertyExpression:
// The property expression. Example: ObservesProperty(() => PropertyName).
//
// 형식 매개 변수:
// T:
// The object type containing the property specified in the expression.
//
// 반환 값:
// The current instance of DelegateCommand
public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression);
이렇게 되어 있는데
INotifyPropertyChanged 인터페이스를 구현한 property를 관찰합니다. 그리고 속성 변경 알림에서 자동적으로 DelegateCommandBase.RaiseCanExecutechanged를 호출합니다.
저 RaiseCanExecuteChanged는 뭘까요?
namespace Prism.Commands
{
//
// 요약:
// An System.Windows.Input.ICommand whose delegates can be attached for Prism.Commands.DelegateCommandBase.Execute(System.Object)
// and Prism.Commands.DelegateCommandBase.CanExecute(System.Object).
public abstract class DelegateCommandBase : ICommand, IActiveAware
{
//
// 요약:
// Creates a new instance of a Prism.Commands.DelegateCommandBase, specifying both
// the execute action and the can execute function.
protected DelegateCommandBase();
//
// 요약:
// Gets or sets a value indicating whether the object is active.
public bool IsActive { get; set; }
//
// 요약:
// Occurs when changes occur that affect whether or not the command should execute.
public event EventHandler CanExecuteChanged;
//
// 요약:
// Fired if the Prism.Commands.DelegateCommandBase.IsActive property changes.
public event EventHandler IsActiveChanged;
//
// 요약:
// Raises Prism.Commands.DelegateCommandBase.CanExecuteChanged so every command
// invoker can requery to check if the command can execute. Note that this will
// trigger the execution of Prism.Commands.DelegateCommandBase.CanExecuteChanged
// once for each invoker.
public void RaiseCanExecuteChanged();
DelegateCommand 가 상속한 DelegateCommandBase 안에 있는 RaiseCanExceuteChanged입니다.
요약을 읽어보면
command가 execute 할 수 있을 때, Prism.Commands.DelegateCommandBase.CanExcecutechanged를 올립니다 모든 command 호출자가 확인할 수 있도록 말입니다. 각 호출자에 대해서 한번씩 실행하게 됩니다.
어...음...번역이 매끄럽지 못한데. 이해를 해보자면
ObservesProperty(람다식)을 실행하게 되면 DelegateCommand를 반환합니다. 다만 이때 반환되는 DelegateCommand는 Property가 변경될때 어떠한 메소드가 trigger로 실행되게 됩니다. 그것이 람다식으로 넘긴 함수 ( )=>IsEnabled가 실행되게 됩니다.
즉 여기서의 IsEnabled는 get{return _isEnabled;}가 실행되게 되는 것입니다.
정확히 이해하자면.
ObservesProperty는 프로퍼티가 변경되어있는지 확인하는 메소드이며 변경되었다면 해당 Command를 실행 할 수 있게합니다.
매개변수로 넘어가는 람다 메소드 즉 프로퍼티 식은, 관찰할 프로퍼티이며 해당 프로퍼티가 바뀔 경우 반응하게 됩니다.
ObservesProperty(변경을 관찰할 프로퍼티)
new DelegateCommand(Execute).ObservesCanExecute(() => IsEnabled); 의 경우
CanExecute가 붙지 않았으므로 프로퍼티가 변경됨에 상관없이 항상 실행이 가능한 상태인데.
여기에 CanExecute를 관찰하는 ObservesCanExecute를 실행함으로써 다른 CanExecute를 이용 할 수 있게 만든 코드입니다.
즉 하나의 DelegateCommand가 굳이 하나의 CanExecute만을 사용하는 것이 아닌 런타임시에 변경 되게 할 수있는 코드입니다.
매개변수로 프로퍼티의 상태를 나타내는 get{}을 넘겼으므로 프로퍼티 상태에 따라서 해당 Command를 사용 할 수 있게 됩니다.
ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric).ObservesCanExecute(() => IsEnabled);
의 경우 제네릭을 사용하여 만들어진 Command인데.
이건 진짜 모르겠네.
대충 이해하자면 ExecuteGeneric를 실행시키는데 이 실행여부 함수로 ObservesCanExecute를 이용하여 IsEnabled가 실행 가능하게 true 일경우 이 command를 실행 가능하게 하는 것이고.
private void ExecuteGeneric(string parameter)
{
parameter = "what?";
Console.WriteLine("JJH: MainWindowViewModel ExecuteGeneric");
UpdateText = parameter;
}
이렇게 구현되어 있는데.
이 Execute가 실행되면 화면 하단의 시간이 출력되던 부분에서 waht? 이 출력되게 된다.
'중단한 프로젝트 > WPF_PrismLibrary(추후진행)' 카테고리의 다른 글
Prism에서의 전역 Command 세팅방법 - 모든 View의 Command를 한 커맨드로 실행시키고 싶을 때 (0) | 2019.02.20 |
---|---|
Prism에서 CustomViewModel을 view에 붙이는 방법 (0) | 2019.02.19 |
Prism으로 어떻게 다른 모듈의 view를 호출하는가 (0) | 2019.02.19 |
Prism은 어떻게 모듈을 관리하는가 (0) | 2019.02.19 |
Prism은 어떻게 View를 다른 View로 변경하는가 (0) | 2019.02.19 |