How to cancel window closing in MVVM WPF application

前端 未结 3 906
滥情空心
滥情空心 2021-02-13 11:22

How can I cancel exiting from particular form after Cancel button (or X at the top right corner, or Esc) was clicked?

WPF:



        
3条回答
  •  青春惊慌失措
    2021-02-13 12:06

    Very good example of doing this in the View Model way can be found in the article of Nish Nishant, where he's using attached properties to hook up window events with commands.

    Sample code of attached behaviour (author of the code: Nish Nishant)

    public class WindowClosingBehavior {
    
        public static ICommand GetClosed(DependencyObject obj) {
            return (ICommand)obj.GetValue(ClosedProperty);
        }
    
        public static void SetClosed(DependencyObject obj, ICommand value) {
            obj.SetValue(ClosedProperty, value);
        }
    
        public static readonly DependencyProperty ClosedProperty 
            = DependencyProperty.RegisterAttached(
            "Closed", typeof(ICommand), typeof(WindowClosingBehavior),
            new UIPropertyMetadata(new PropertyChangedCallback(ClosedChanged)));
    
        private static void ClosedChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) {
    
            Window window = target as Window;
    
            if (window != null) {
    
                if (e.NewValue != null) {
                    window.Closed += Window_Closed;
                }
                else {
                    window.Closed -= Window_Closed;
                }
            }
        }
    
        public static ICommand GetClosing(DependencyObject obj) {
            return (ICommand)obj.GetValue(ClosingProperty);
        }
    
        public static void SetClosing(DependencyObject obj, ICommand value) {
            obj.SetValue(ClosingProperty, value);
        }
    
        public static readonly DependencyProperty ClosingProperty 
            = DependencyProperty.RegisterAttached(
            "Closing", typeof(ICommand), typeof(WindowClosingBehavior),
            new UIPropertyMetadata(new PropertyChangedCallback(ClosingChanged)));
    
        private static void ClosingChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) {
    
            Window window = target as Window;
    
            if (window != null) {
    
                if (e.NewValue != null) {
                    window.Closing += Window_Closing;
                }
                else {
                    window.Closing -= Window_Closing;
                }
            }
        }
    
        public static ICommand GetCancelClosing(DependencyObject obj) {
            return (ICommand)obj.GetValue(CancelClosingProperty);
        }
    
        public static void SetCancelClosing(DependencyObject obj, ICommand value) {
            obj.SetValue(CancelClosingProperty, value);
        }
    
        public static readonly DependencyProperty CancelClosingProperty 
            = DependencyProperty.RegisterAttached(
            "CancelClosing", typeof(ICommand), typeof(WindowClosingBehavior));
    
        static void Window_Closed(object sender, EventArgs e) {
    
            ICommand closed = GetClosed(sender as Window);
    
            if (closed != null) {
                closed.Execute(null);
            }
        }
    
        static void Window_Closing(object sender, CancelEventArgs e) {
    
            ICommand closing = GetClosing(sender as Window);
    
            if (closing != null) {
    
                if (closing.CanExecute(null)) {
                    closing.Execute(null);
                }
                else {
    
                    ICommand cancelClosing = GetCancelClosing(sender as Window);
    
                    if (cancelClosing != null) {
                        cancelClosing.Execute(null);
                    }
    
                    e.Cancel = true;
                }
            }
        }
    }   
    

    Example how to bind commands:

    
    

    Commands "ClosedCommand", "ClosingCommand" and "CancelClosingCommand" should be defined in the separate View-Model.

    internal class MainViewModel : ViewModelBase {
    
        private ObservableCollection log = new ObservableCollection();
    
        public ObservableCollection Log {
            get { return log; }
        }
    
        private DelegateCommand exitCommand;
    
        public ICommand ExitCommand {
    
            get {
    
                if (exitCommand == null) {
                    exitCommand = new DelegateCommand(Exit);
                }
    
                return exitCommand;
            }
        }
    
        private void Exit() {
            Application.Current.Shutdown();
        }
    
        private DelegateCommand closedCommand;
    
        public ICommand ClosedCommand {
    
            get {
    
                if (closedCommand == null) {
                    closedCommand = new DelegateCommand(Closed);
                }
    
                return closedCommand;
            }
        }
    
        private void Closed() {
            log.Add("You won't see this of course! Closed command executed");
            MessageBox.Show("Closed");
        }
    
        private DelegateCommand closingCommand;
    
        public ICommand ClosingCommand {
    
            get {
    
                if (closingCommand == null) {
                    closingCommand = new DelegateCommand(ExecuteClosing, CanExecuteClosing);
                }
    
                return closingCommand;
            }
        }
    
        private void ExecuteClosing() {
            log.Add("Closing command executed");
            MessageBox.Show("Closing");
        }
    
        private bool CanExecuteClosing() {
    
            log.Add("Closing command execution check");
    
            return MessageBox.Show("OK to close?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes;
        }
    
        private DelegateCommand cancelClosingCommand;
    
        public ICommand CancelClosingCommand {
    
            get {
    
                if (cancelClosingCommand == null) {
                    cancelClosingCommand = new DelegateCommand(CancelClosing);
                }
    
                return cancelClosingCommand;
            }
        }
    
        private void CancelClosing() {
            log.Add("CancelClosing command executed");
            MessageBox.Show("CancelClosing");
        }
    }
    

提交回复
热议问题