내용 보기

작성자

관리자 (IP : ::ffff:172.17.0.1)

날짜

2020-07-07 08:43

제목

[WPF] Command 실행 후 DialogResult 설정 하기


WPF의 Button은 WinForm의 Button과는 달리 Button에서 DialogResult를 설정 할 수 없다.

만약 MVVM패턴에서 특정 Button을 클릭 했을 때 Command로 바인딩 되어 있을때 Command가 실행 된 후 DialogResult를 설정하여 해당 Window를 Close시킬 경우 Button의 Click이벤트를 연결하여 OnClick에서 DialogResult를 설정 할 수 밖에 없다 아니면 ViewModel에서 이벤트를 이용하여 View에서 따로 DialogResult를 설정 하던가 해야 한다.

즉 다음과 같이 처리 해야만 한다.

Window.xaml

<Button x:Name="xTestBtn" Grid.Column="0" Grid.Row="0" Content="Test"
Command="{Binding TestSendMailCommand}" Click="xTestBtn_Click" />
cs

Window.cs

private void xTestBtn_Click(object sender, RoutedEventArgs e)
{
    this.DialogResult = true;
}
cs
위 처럼 처리 하면 Click이벤트가 먼저 발생 되어 DialogResult가 설정 되서 Window가 닫힌 후 바인딩 처리된 Command가 실행 된다.

위 코드는 MVVM패턴에 맞지 않는 코드이며(View에는 로직 코드가 노출되면 안된다.), Button에 대한 처리 코드가 양쪽으로 분리 되어 비효율 적인 코드가 된다. 또한 Window가 닫히는 시점과 처리 순서가 중요시 된다면 더욱 더 문제가 된다.

문제를 해결 하기 위해 UI종속 클래스를 만들어 Command가 처리 된 후 DialogResult가 설정 되도록 할 수 있다.
Command는 해당 Window의 ViewModel에서 처리되고, DialogResult는 별도의 UI종속 클래스에서 Command 호출 후 설정 하도록 구성한다.

DialogButtonManager.cs

using IntegratedManagementConsole.Commons;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
 
namespace IntegratedManagementConsole.Helper
{
    /// 
    /// Command 실행 후 DialogResult를 설정해주는 UI종속 클래스
    /// 
    public class DialogResultCommand : DependencyObject
    {
       private static ICommand _acceptButtonCommand;
       private static object _acceptButtonCommandParameter;
       private static ICommand _cancelButtonCommand;
       private static object _cancelButtonCommandParameter;
 
       public static readonly DependencyProperty AcceptButtonCommandProperty =
               DependencyProperty.RegisterAttached("AcceptButtonCommand"typeof(ICommand),
               typeof(DialogResultCommand),
               new FrameworkPropertyMetadata(OnAcceptButtonCommandPropertyChanged));
 
       public static readonly DependencyProperty AcceptButtonCommandParameterProperty =
               DependencyProperty.RegisterAttached("AcceptButtonCommandParameter"typeof(object),
               typeof(DialogResultCommand), new FrameworkPropertyMetadata(OnAcceptButtonCommandParameterPropertyChanged));
 
       public static readonly DependencyProperty CancelButtonCommandProperty =
               DependencyProperty.RegisterAttached("CancelButtonCommand"typeof(ICommand),
               typeof(DialogResultCommand), new FrameworkPropertyMetadata(OnCancelButtonCommandPropertyChanged));
 
       public static readonly DependencyProperty CancelButtonCommandParameterProperty =
               DependencyProperty.RegisterAttached("CancelButtonCommandParameter"typeof(object),
               typeof(DialogResultCommand), new FrameworkPropertyMetadata(OnCancelButtonCommandParameterPropertyChanged));
 
       public static readonly DependencyProperty IsAcceptButtonProperty =
               DependencyProperty.RegisterAttached("IsAcceptButton"typeof(bool),
               typeof(DialogResultCommand), new FrameworkPropertyMetadata(OnIsAcceptButtonPropertyChanged));
 
       public static readonly DependencyProperty IsCancelButtonProperty =
               DependencyProperty.RegisterAttached("IsCancelButton"typeof(bool),
               typeof(DialogResultCommand), new FrameworkPropertyMetadata(OnIsCancelButtonPropertyChanged)); 
 
       // AcceptButtonCommandProperty
       public static void SetAcceptButtonCommand(DependencyObject obj, ICommand value)
       {
           obj.SetValue(AcceptButtonCommandProperty, value);
       }
 
       public static ICommand GetAcceptButtonCommand(DependencyObject obj)
       {
           return (ICommand)obj.GetValue(AcceptButtonCommandProperty);
       }
 
       // AcceptButtonCommandParameterProperty
       public static void SetAcceptButtonCommandParameter(DependencyObject obj, object value)
       {
          obj.SetValue(AcceptButtonCommandParameterProperty, value);
       }
 
       public static object GetAcceptButtonCommandParameter(DependencyObject obj)
       {
           return (object)obj.GetValue(AcceptButtonCommandParameterProperty); 
       }
 
       // CancelButtonCommandProperty
       public static void SetCancelButtonCommand(DependencyObject obj, ICommand value)
       {
          obj.SetValue(CancelButtonCommandProperty, value);
       }
 
       public static ICommand GetCancelButtonCommand(DependencyObject obj)
       {
           return (ICommand)obj.GetValue(CancelButtonCommandProperty);
       }
 
       // CancelButtonCommandParameterProperty
       public static void SetCancelButtonCommandParameter(DependencyObject obj, object value)
       {
          obj.SetValue(CancelButtonCommandParameterProperty, value);
       }
 
       public static object GetCancelButtonCommandParameter(DependencyObject obj)
       {
           return (object)obj.GetValue(CancelButtonCommandParameterProperty);
       }
 
       // IsAcceptButtonProperty
       public static void SetIsAcceptButton(DependencyObject obj, bool value)
       {
          obj.SetValue(IsAcceptButtonProperty, value);
       }
 
       public static bool GetIsAcceptButton(DependencyObject obj)
       {
           return (bool)obj.GetValue(IsAcceptButtonProperty);
       }
 
       // IsCancelButtonProperty
       public static void SetIsCancelButton(DependencyObject obj, bool value)
       {
           obj.SetValue(IsCancelButtonProperty, value);
        }
 
       public static bool GetIsCancelButton(DependencyObject obj)
       {
           return (bool)obj.GetValue(IsCancelButtonProperty);
       }
 
       private static void OnIsAcceptButtonPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           Button button = sender as Button; 
           if (button != null)
           {
               if ((bool)e.NewValue)
               {
                   SetAcceptButton(button);
               }
               else
               {
                   ResetAcceptButton(button);
               }
           }
       } 
 
       private static void OnIsCancelButtonPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           Button button = sender as Button; 
           if (button != null)
           {
               if ((bool)e.NewValue)
               {
                   SetCancelButton(button);
               }
               else
               {
                   ResetCancelButton(button);
               }
           }
       } 
 
       private static void OnAcceptButtonCommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           _acceptButtonCommand = e.NewValue as ICommand;
       } 
 
       private static void OnAcceptButtonCommandParameterPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           _acceptButtonCommandParameter = e.NewValue as object;
       }
 
       private static void OnCancelButtonCommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           _cancelButtonCommand = e.NewValue as ICommand;
       }
 
       private static void OnCancelButtonCommandParameterPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           _cancelButtonCommandParameter = e.NewValue as object;
       }
 
       private static void SetAcceptButton(Button button)
       {
            Window window = Window.GetWindow(button);
            button.Command = new RelayCommand(new Action<object>(ExecuteAccept), new Predicate<object>(CanAcceptButtonExecute));
            button.CommandParameter = window;
       }
 
       private static void ResetAcceptButton(Button button)
       {
           button.Command = null;
           button.CommandParameter = null;
       }
 
       private static void ExecuteAccept(object buttonWindow)
       {
           if (_acceptButtonCommand != null) _acceptButtonCommand.Execute(_acceptButtonCommandParameter);
                Window window = (Window)buttonWindow;
           window.DialogResult = true;
       }
 
        private static void SetCancelButton(Button button)
        {
            Window window = Window.GetWindow(button);
            button.Command = new RelayCommand(new Action<object>(ExecuteCancel), new Predicate<object>(CanCancelButtonExecute));
            button.CommandParameter = window;
        }
 
        private static void ResetCancelButton(Button button)
        {
            button.Command = null;
            button.CommandParameter = null;
        }
 
        private static void ExecuteCancel(object buttonWindow)
        {
            if (_cancelButtonCommand != null) _cancelButtonCommand.Execute(_cancelButtonCommandParameter);
 
            Window window = (Window)buttonWindow; 
            window.DialogResult = false;
        }
 
        private static bool CanAcceptButtonExecute(object param)
        {
            if (_acceptButtonCommand == null)
            {
                return true;
            }
 
            return (_acceptButtonCommand.CanExecute(_acceptButtonCommandParameter));
        }
 
        private static bool CanCancelButtonExecute(object param)
        {
            if (_cancelButtonCommand == null)
            {
                return true;
            }
 
            return (_cancelButtonCommand.CanExecute(_cancelButtonCommandParameter));
        }
    }
}
cs
위 처럼 Button에 속성을 설정 할 수 있는 DependencyObject클래스를 만들고 위 클래스는 다음과 같이 사용한다.

Window.xaml

<Button x:Name="xTestBtn" Grid.Column="0" Grid.Row="0" Content="Test"
                DialogButtonManager1:DialogButtonManager.AcceptButtonCommand="{Binding TestSendMailCommand}"
                DialogButtonManager1:DialogButtonManager.AcceptButtonCommandParameter="{Binding ElementName=xTestBtn, Path=Content}"
                DialogButtonManager1:DialogButtonManager.IsAcceptButton="True" />
cs

WindowViewModel.cs

private DelegateCommand<string>_testSendMailCommand;
public ICommand TestSendMailCommand
{
          get
          {
              return _testSendMailCommand ??
                  (_testSendMailCommand = new DelegateCommand<string>(
                      param => this.ExecuteTestSendMailCommand(param),
                      param => this.CanExecuteTestSendMailCommand(param)));
          }
}
 
private void ExecuteTestSendMailCommand(string param)
{
          MessageBox.Show(param);
}
 
private bool CanExecuteTestSendMailCommand(string param)
{
          Console.WriteLine("Test~~~~~~~~~~~~~~~!!");
          return (string.IsNullOrWhiteSpace(Txt)== false);
}
cs
위 처럼 처리 하면 Button의 Command가 실행 된 후 DialogResult를 설정하여 해당 Window가 Close하게 된다.


DialogButtonManager에서 의존 프로퍼티를 통해 DialogResult를 설정하는 Command를 설정 하고 실제 Button의 Command를 의존 프로퍼티로 받아
DialogResult를 설정 하는 Command안에서 실제 Button의 Command를 실행하도록 되어 있다.

출처1

http://stackoverflow.com/questions/4376475/wpf-mvvm-how-to-close-a-window

출처2




2020-07-09 08:32
참고 사이트에서 DialogButtonManager 클래스를 수정하여 재 구성 하였다.
관리자
(172.17.0.1)