WPF MVVM: How to close a window

后端 未结 21 1715
后悔当初
后悔当初 2020-12-04 08:19

I have a Button that closes my window when it\'s clicked:


相关标签:
21条回答
  • 2020-12-04 08:42

    I have following solution in Silverlight. Would also be in WPF.

    ChildWindowExt.cs:

    namespace System.Windows.Controls
    {
        public class ChildWindowExt : ChildWindow
        {
            public static readonly DependencyProperty IsOpenedProperty =
              DependencyProperty.Register(
              "IsOpened",
              typeof(bool),
              typeof(ChildWindowExt),
              new PropertyMetadata(false, IsOpenedChanged));
    
            private static void IsOpenedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                if ((bool)e.NewValue == false)
                {
                    ChildWindowExt window = d as ChildWindowExt;
                    window.Close();
                }
                else if ((bool)e.NewValue == true)
                {
                    ChildWindowExt window = d as ChildWindowExt;
                    window.Show();
                }
            }
    
            public bool IsOpened
            {
                get { return (bool)GetValue(IsOpenedProperty); }
                set { SetValue(IsOpenedProperty, value); }
            }
    
            protected override void OnClosing(ComponentModel.CancelEventArgs e)
            {
                this.IsOpened = false;
                base.OnClosing(e);
            }
    
            protected override void OnOpened()
            {
                this.IsOpened = true;
                base.OnOpened();
            }
        }
    }
    

    ItemWindow.xaml:

    <extControls:ChildWindowExt  
        x:Class="MyProject.ItemWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:extControls="clr-namespace:System.Windows.Controls"
        Title="{Binding Title}" IsOpened="{Binding IsOpened, Mode=TwoWay}" Width="640" Height="480">
    
        <Grid x:Name="LayoutRoot">
            <Button Command="{Binding UpdateCommand}" Content="OK" Width="70" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>
    
    </extControls:ChildWindowExt>
    

    ItemViewModel.cs:

    private bool _IsOpened;
    public bool IsOpened
    {
        get
        {
            return _IsOpened;
        }
        set
        {
            if (!Equals(_IsOpened, value))
            {
                _IsOpened = value;
                RaisePropertyChanged("IsOpened");
            }
        }
    }
    
    private RelayCommand _UpdateCommand;
    /// <summary>
    /// Insert / Update data entity
    /// </summary>
    public RelayCommand UpdateCommand
    {
        get
        {
            if (_UpdateCommand == null)
            {
                _UpdateCommand = new RelayCommand(
                    () =>
                    {
                        // Insert / Update data entity
                        ...
    
                        IsOpened = false;
                    },
                    () =>
                    {
                        return true;
                    });
            }
            return _UpdateCommand;
        }
    }
    

    ItemsViewModel.cs:

        private RelayCommand _InsertItemCommand;
        /// <summary>
        /// 
        /// </summary>
        public RelayCommand InsertItemCommand
        {
            get
            {
                if (_InsertItemCommand == null)
                {
                    _InsertItemCommand = new RelayCommand(
                        () =>
                        {
                            ItemWindow itemWin = new ItemWindow();
                            itemWin.DataContext = new ItemViewModel();
                            itemWin.Show();
    
                            // OR
    
                            // ItemWindow itemWin = new ItemWindow();
                            // ItemViewModel newItem = new ItemViewModel();
                            // itemWin.DataContext = newItem;
                            // newItem.IsOpened = true;
    
                        },
                        () =>
                        {
                            return true;
                        });
                }
                return _InsertItemCommand;
            }
        }
    

    MainPage.xaml:

    <Grid x:Name="LayoutRoot">
        <Button Command="{Binding InsertItemCommand}" Content="Add New" Width="70" HorizontalAlignment="Left" VerticalAlignment="Center" />
    </Grid>
    

    I wish you all good ideas and projects ;-)

    0 讨论(0)
  • 2020-12-04 08:43

    I struggled with this topic for some time, and eventually went with the simplest approach that is still consistent with MVVM: Have the button execute the Command that does all the heavy lifting and have the button's Click handler close the window.

    XAML

    <Button x:Name="buttonOk" 
            Click="closeWindow" 
            Command="{Binding SaveCommand}" />
    

    XAML.cs

    public void closeWindow() 
    {
        this.DialogResult = true;
    }
    

    SaveCommand.cs

     // I'm in my own file, not the code-behind!
    

    True, there is still code-behind, but there isn't anything inherently bad about that. And it makes the most sense to me, from an OO perspective, to just tell the window to close itself.

    0 讨论(0)
  • 2020-12-04 08:43

    The solution to close a window in wpf that that worked for me is not answered here so i thought i would add my solution too.

            private static Window GetWindow(DependencyObject sender)
            {
                Window window = null;
                if (sender is Window)
                    window = (Window)sender;
                if (window == null)
                    window = Window.GetWindow(sender);
                return window;
            }
            private void CloseWindow(object sender, RoutedEventArgs e)
            {
                var button = (Button)sender as DependencyObject;
    
                Window window = GetWindow(button);
                    if (window != null)
                        window.Close();
                       // window.Visibility = Visibility.Hidden; 
               // choose between window.close or set window.visibility to close or hide the window.
    
                //            }
            }
    
    

    Add CloseWindow event to the button in you window as following.

    <Button Content="Cancel" Click="CloseWindow" >
    
    0 讨论(0)
  • 2020-12-04 08:45

    I use the Publish Subscribe pattern for complicated class-dependencies:

    ViewModel:

        public class ViewModel : ViewModelBase
        {
            public ViewModel()
            {
                CloseComand = new DelegateCommand((obj) =>
                    {
                        MessageBus.Instance.Publish(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, null);
                    });
            }
    }
    

    Window:

    public partial class SomeWindow : Window
    {
        Subscription _subscription = new Subscription();
    
        public SomeWindow()
        {
            InitializeComponent();
    
            _subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj =>
                {
                    this.Close();
                });
        }
    }
    

    You can leverage Bizmonger.Patterns to get the MessageBus.

    MessageBus

    public class MessageBus
    {
        #region Singleton
        static MessageBus _messageBus = null;
        private MessageBus() { }
    
        public static MessageBus Instance
        {
            get
            {
                if (_messageBus == null)
                {
                    _messageBus = new MessageBus();
                }
    
                return _messageBus;
            }
        }
        #endregion
    
        #region Members
        List<Observer> _observers = new List<Observer>();
        List<Observer> _oneTimeObservers = new List<Observer>();
        List<Observer> _waitingSubscribers = new List<Observer>();
        List<Observer> _waitingUnsubscribers = new List<Observer>();
    
        int _publishingCount = 0;
        #endregion
    
        public void Subscribe(string message, Action<object> response)
        {
            Subscribe(message, response, _observers);
        }
    
        public void SubscribeFirstPublication(string message, Action<object> response)
        {
            Subscribe(message, response, _oneTimeObservers);
        }
    
        public int Unsubscribe(string message, Action<object> response)
        {
            var observers = new List<Observer>(_observers.Where(o => o.Respond == response).ToList());
            observers.AddRange(_waitingSubscribers.Where(o => o.Respond == response));
            observers.AddRange(_oneTimeObservers.Where(o => o.Respond == response));
    
            if (_publishingCount == 0)
            {
                observers.ForEach(o => _observers.Remove(o));
            }
    
            else
            {
                _waitingUnsubscribers.AddRange(observers);
            }
    
            return observers.Count;
        }
    
        public int Unsubscribe(string subscription)
        {
            var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription).ToList());
            observers.AddRange(_waitingSubscribers.Where(o => o.Subscription == subscription));
            observers.AddRange(_oneTimeObservers.Where(o => o.Subscription == subscription));
    
            if (_publishingCount == 0)
            {
                observers.ForEach(o => _observers.Remove(o));
            }
    
            else
            {
                _waitingUnsubscribers.AddRange(observers);
            }
    
            return observers.Count;
        }
    
        public void Publish(string message, object payload)
        {
            _publishingCount++;
    
            Publish(_observers, message, payload);
            Publish(_oneTimeObservers, message, payload);
            Publish(_waitingSubscribers, message, payload);
    
            _oneTimeObservers.RemoveAll(o => o.Subscription == message);
            _waitingUnsubscribers.Clear();
    
            _publishingCount--;
        }
    
        private void Publish(List<Observer> observers, string message, object payload)
        {
            Debug.Assert(_publishingCount >= 0);
    
            var subscribers = observers.Where(o => o.Subscription.ToLower() == message.ToLower());
    
            foreach (var subscriber in subscribers)
            {
                subscriber.Respond(payload);
            }
        }
    
        public IEnumerable<Observer> GetObservers(string subscription)
        {
            var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription));
            return observers;
        }
    
        public void Clear()
        {
            _observers.Clear();
            _oneTimeObservers.Clear();
        }
    
        #region Helpers
        private void Subscribe(string message, Action<object> response, List<Observer> observers)
        {
            Debug.Assert(_publishingCount >= 0);
    
            var observer = new Observer() { Subscription = message, Respond = response };
    
            if (_publishingCount == 0)
            {
                observers.Add(observer);
            }
            else
            {
                _waitingSubscribers.Add(observer);
            }
        }
        #endregion
    }
    

    }

    Subscription

    public class Subscription
    {
        #region Members
        List<Observer> _observerList = new List<Observer>();
        #endregion
    
        public void Unsubscribe(string subscription)
        {
            var observers = _observerList.Where(o => o.Subscription == subscription);
    
            foreach (var observer in observers)
            {
                MessageBus.Instance.Unsubscribe(observer.Subscription, observer.Respond);
            }
    
            _observerList.Where(o => o.Subscription == subscription).ToList().ForEach(o => _observerList.Remove(o));
        }
    
        public void Subscribe(string subscription, Action<object> response)
        {
            MessageBus.Instance.Subscribe(subscription, response);
            _observerList.Add(new Observer() { Subscription = subscription, Respond = response });
        }
    
        public void SubscribeFirstPublication(string subscription, Action<object> response)
        {
            MessageBus.Instance.SubscribeFirstPublication(subscription, response);
        }
    }
    
    0 讨论(0)
  • 2020-12-04 08:45

    There is a useful behavior for this task which doesn't break MVVM, a Behavior, introduced with Expression Blend 3, to allow the View to hook into commands defined completely within the ViewModel.

    This behavior demonstrates a simple technique for allowing the ViewModel to manage the closing events of the View in a Model-View-ViewModel application.

    This allows you to hook up a behavior in your View (UserControl) which will provide control over the control's Window, allowing the ViewModel to control whether the window can be closed via standard ICommands.

    Using Behaviors to Allow the ViewModel to Manage View Lifetime in M-V-VM

    http://gallery.expression.microsoft.com/WindowCloseBehavior/

    Above link has been archived to http://code.msdn.microsoft.com/Window-Close-Attached-fef26a66#content

    0 讨论(0)
  • 2020-12-04 08:47

    I've been searching for a solution to the same problem and found that doing following works fine. The solution is similar to what OP has mentioned in his question with some differences:

    1. No need of IsCancel property.

    2. Code behind should not close window. Just set DialogResult

    In my case it first executes code behind and then view model command bound to the button.

    XAML

    <Button x:Name="buttonOk" Click="Save_Click" Command="{Binding SaveCommand}">OK</Button>
    

    Code Behind

    private void Apply_OnClick(object sender, RoutedEventArgs e)
    {
        this.DialogResult = true;
    }
    

    View Model

    private void Save()
    {
     // Save data.
    }
    

    Hope this helps.

    0 讨论(0)
提交回复
热议问题