web-dev-qa-db-fra.com

WPF MVVM: comment fermer une fenêtre

J'ai un Button qui ferme ma fenêtre quand on clique dessus:

<Button x:Name="buttonOk"  IsCancel="True">Ok</Button>

C’est bien jusqu’à ce que j’ajoute un Command au Button c.-à-d.

<Button x:Name="buttonOk" 
        Command="{Binding SaveCommand}" 
        IsCancel="True">Ok</Button>

Maintenant, il ne ferme probablement pas parce que je gère le Command. Je peux résoudre ce problème en mettant EventHandler dans et en appelant this.Close() i.e.

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

mais maintenant j'ai du code dans mon code derrière c’est-à-dire la méthode SaveCommand. J'utilise le modèle MVVM et SaveCommand est le seul code de mon code qui se trouve derrière.

Comment puis-je faire cela différemment pour ne pas utiliser de code derrière?

64
Bob

Je viens de terminer un blog post sur ce sujet même. En un mot, ajoutez une propriété Action à votre ViewModel avec les accesseurs get et set. Définissez ensuite le Action à partir de votre constructeur View. Enfin, appelez votre action dans la commande liée qui devrait fermer la fenêtre.

Dans le ViewModel:

public Action CloseAction  { get; set;}

et dans le constructeur View:

private View()
{
    InitializeComponent();
    ViewModel vm = new ViewModel();
    this.DataContext = vm;
    if ( vm.CloseAction == null )
        vm.CloseAction = new Action(this.Close);
}

Enfin, quelle que soit la commande liée devant fermer la fenêtre, nous pouvons simplement appeler

CloseAction(); // Calls Close() method of the View

Cela a fonctionné pour moi, semblait être une solution assez élégante et m'a évité beaucoup de codage.

52
Jonathan Shay

Malheureusement, l’affichage de windows est un réel problème pour MVVM, vous devez donc effectuer un travail d’infrastructure assez important ou utiliser un framework MVVM tel que Cinch . Si vous voulez investir le temps de le faire vous-même voici un lien de la façon dont Cinch le fait.

C’est bien que vous essayiez de garder toute logique hors de la vue mais que ce n’est vraiment pas la fin du monde si vous le faites. Dans ce cas, il ne semble pas que cela cause trop de problèmes.

22
Jon Mitchell

Comme quelqu'un l'a commenté, le code que j'ai posté n'est pas convivial avec MVVM, qu'en est-il de la deuxième solution?

1er, pas de solution MVVM (je ne supprimerai pas cela comme référence)

XAML:

<Button Name="okButton" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">OK</Button>

ViewModel:

public ICommand OkCommand
{
    get
    {
        if (_okCommand == null)
        {
            _okCommand = new ActionCommand<Window>(DoOk, CanDoOk);
        }
        return _okCommand ;
    }
}

void DoOk(Window win)
{
    // Your Code
    win.DialogResult = true;
    win.Close();
}

bool CanDoOk(Window win) { return true; }

2ème, probablement meilleure solution: Utilisation des comportements attachés

XAML

<Button Content="Ok and Close" Command="{Binding OkCommand}" b:CloseOnClickBehaviour.IsEnabled="True" />

Voir le modèle

public ICommand OkCommand
{
    get { return _okCommand; }
}

Classe de comportement Quelque chose de semblable à ceci:

public static class CloseOnClickBehaviour
{
    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached(
            "IsEnabled",
            typeof(bool),
            typeof(CloseOnClickBehaviour),
            new PropertyMetadata(false, OnIsEnabledPropertyChanged)
        );

    public static bool GetIsEnabled(DependencyObject obj)
    {
        var val = obj.GetValue(IsEnabledProperty);
        return (bool)val;
    }

    public static void SetIsEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsEnabledProperty, value);
    }

    static void OnIsEnabledPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
    {
        var button = dpo as Button;
        if (button == null)
            return;

        var oldValue = (bool)args.OldValue;
        var newValue = (bool)args.NewValue;

        if (!oldValue && newValue)
        {
            button.Click += OnClick;
        }
        else if (oldValue && !newValue)
        {
            button.PreviewMouseLeftButtonDown -= OnClick;
        }
    }

    static void OnClick(object sender, RoutedEventArgs e)
    {
        var button = sender as Button;
        if (button == null)
            return;

        var win = Window.GetWindow(button);
        if (win == null)
            return;

        win.Close();
    }

}
15
Simone

Personnellement, j'utiliserais un comportement pour faire ce genre de chose:

public class WindowCloseBehaviour : Behavior<Window>
{
    public static readonly DependencyProperty CommandProperty =
      DependencyProperty.Register(
        "Command",
        typeof(ICommand),
        typeof(WindowCloseBehaviour));

    public static readonly DependencyProperty CommandParameterProperty =
      DependencyProperty.Register(
        "CommandParameter",
        typeof(object),
        typeof(WindowCloseBehaviour));

    public static readonly DependencyProperty CloseButtonProperty =
      DependencyProperty.Register(
        "CloseButton",
        typeof(Button),
        typeof(WindowCloseBehaviour),
        new FrameworkPropertyMetadata(null, OnButtonChanged));

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public object CommandParameter
    {
        get { return GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }

    public Button CloseButton
    {
        get { return (Button)GetValue(CloseButtonProperty); }
        set { SetValue(CloseButtonProperty, value); }
    }

    private static void OnButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var window = (Window)((WindowCloseBehaviour)d).AssociatedObject;
        ((Button) e.NewValue).Click +=
            (s, e1) =>
            {
                var command = ((WindowCloseBehaviour)d).Command;
                var commandParameter = ((WindowCloseBehaviour)d).CommandParameter;
                if (command != null)
                {
                    command.Execute(commandParameter);                                                      
                }
                window.Close();
            };
        }
    }

Vous pouvez ensuite attacher ceci à votre Window et à votre Button pour faire le travail:

<Window x:Class="WpfApplication6.Window1"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"
        xmlns:local="clr-namespace:WpfApplication6"
        Title="Window1" Height="300" Width="300">
    <i:Interaction.Behaviors>
        <local:WindowCloseBehaviour CloseButton="{Binding ElementName=closeButton}"/>
    </i:Interaction.Behaviors>
    <Grid>
        <Button Name="closeButton">Close</Button>
    </Grid>
</Window>

J'ai ajouté Command et CommandParameter ici afin que vous puissiez exécuter une commande avant la fermeture de Window.

12

Très propre et méthode MVVM consiste à utiliser InteractionTrigger et CallMethodAction définis dans Microsoft.Interactivity.Core

Vous devrez ajouter deux espaces de noms comme ci-dessous

xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.Microsoft.com/expression/2010/interactions"

Et les assemblages System.Windows.Interactivity et Microsoft.Expression.Interactions puis le code xaml ci-dessous fonctionnera.

<Button Content="Save" Command="{Binding SaveCommand}">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
      <ei:CallMethodAction MethodName="Close"
                           TargetObject="{Binding RelativeSource={RelativeSource
                                                  Mode=FindAncestor,
                                                  AncestorType=Window}}" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</Button>

Vous n'avez besoin d'aucun code derrière ni de quoi que ce soit et vous pouvez aussi appeler n'importe quelle autre méthode de Window.

10
RAJ

Pour les petites applications, j'utilise mon propre contrôleur d'application pour afficher, fermer et supprimer des fenêtres et des DataContexts. C'est un point central dans l'interface utilisateur d'une application.

C'est quelque chose comme ça:

//It is singleton, I will just post 2 methods and their invocations
public void ShowNewWindow(Window window, object dataContext = null, bool dialog = true)
{
    window.DataContext = dataContext;
    addToWindowRegistry(dataContext, window);

    if (dialog)
        window.ShowDialog();
    else
        window.Show();

}

public void CloseWindow(object dataContextSender)
{
    var correspondingWindows = windowRegistry.Where(c => c.DataContext.Equals(dataContextSender)).ToList();
    foreach (var pair in correspondingWindows)
    {
        pair.Window.Close();              
    }
}

et leurs invocations depuis ViewModels:

// Show new Window with DataContext
ApplicationController.Instance.ShowNewWindow(
                new ClientCardsWindow(),
                new ClientCardsVM(),
                false);

// Close Current Window from viewModel
ApplicationController.Instance.CloseWindow(this);

Bien sûr, vous pouvez trouver des restrictions dans ma solution. Encore une fois: je l'utilise pour de petits projets, et c'est assez. Si cela vous intéresse, je peux poster le code complet ici ou ailleurs

7
Ilya Smagin

J'ai essayé de résoudre ce problème d'une manière générique, MVVM, mais je trouve toujours que je finis par une logique complexe inutile. Pour obtenir un comportement proche, j'ai fait une exception à la règle d'absence de code et ai simplement utilisé de bons événements dans le code:

XAML:

<Button Content="Close" Click="OnCloseClicked" />

Code derrière:

private void OnCloseClicked(object sender, EventArgs e)
{
    Visibility = Visibility.Collapsed;
}

Bien que je souhaite que cela soit mieux supporté avec les commandes/MVVM, je pense simplement qu’il n’ya pas de solution plus simple et plus claire que d’utiliser des événements.

5
larsmoa

J'utilise le modèle de publication d'abonnement pour les dépendances de classe compliquées:

ViewModel:

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

Fenêtre:

public partial class SomeWindow : Window
{
    Subscription _subscription = new Subscription();

    public SomeWindow()
    {
        InitializeComponent();

        _subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj =>
            {
                this.Close();
            });
    }
}

Vous pouvez utiliser Bizmonger.Patterns pour obtenir le 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
}

}

Abonnement

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);
    }
}
5
Scott Nimrod

Il existe un comportement utile pour cette tâche qui n'interrompt pas MVVM, un comportement introduit dans Expression Blend 3 pour permettre à la vue de se connecter à des commandes définies complètement dans le ViewModel.

Ce comportement illustre une technique simple permettant à ViewModel de gérer les événements de clôture de la vue dans une application Model-View-ViewModel.

Cela vous permet de créer un comportement dans votre vue (UserControl) qui permettra de contrôler la fenêtre du contrôle, ce qui permettra à ViewModel de contrôler si la fenêtre peut être fermée via des ICommandes standard.

tilisation de comportements pour permettre à ViewModel de gérer View Lifetime dans M-V-VM

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

Le lien ci-dessus a été archivé dans le répertoire http://code.msdn.Microsoft.com/Window-Close-Attached-fef26a66#content

3
akjoshi

Je me suis débattu avec ce sujet pendant un certain temps, puis j’ai opté pour l’approche la plus simple qui reste cohérente avec MVVM: demandez au bouton d’exécuter la commande qui fait tout le travail lourd et de laisser le gestionnaire de clic du bouton fermer la fenêtre.

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!

Certes, il y a toujours du code en retard, mais il n'y a rien de mauvais en soi. Et cela me semble le plus logique, dans une perspective OO), de simplement indiquer à la fenêtre de se fermer.

2
DPH

Nous avons la propriété name dans la définition .xaml:

x:Name="WindowsForm"

Ensuite nous avons le bouton:

<Button Command="{Binding CloseCommand}" 
CommandParameter="{Binding ElementName=WindowsForm}" />

Puis dans le ViewModel:

public DelegateCommand <Object>  CloseCommand { get; private set; }

Constructor for that view model:
this.CloseCommand = new DelegateCommand<object>(this.CloseAction);

Enfin, la méthode d'action:

private void CloseAction (object obj)
{
  Window Win = obj as Window;
  Win.Close();

}

J'ai utilisé ce code pour fermer une fenêtre contextuelle à partir d'une application.

1
Prabhuprasad NG

J'ai également dû faire face à ce problème, alors voici ma solution. Ça marche bien pour moi.

1. Créer la classe DelegateCommand

    public class DelegateCommand<T> : ICommand
{
    private Predicate<T> _canExecuteMethod;
    private readonly Action<T> _executeMethod;
    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<T> executeMethod) : this(executeMethod, null)
    {
    }
    public DelegateCommand(Action<T> executeMethod, Predicate<T> canExecuteMethod)
    {
        this._canExecuteMethod = canExecuteMethod;
        this._executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod), "Command is not specified."); 
    }


    public void RaiseCanExecuteChanged()
    {
        if (this.CanExecuteChanged != null)
            CanExecuteChanged(this, null);
    }
    public bool CanExecute(object parameter)
    {
        return _canExecuteMethod == null || _canExecuteMethod((T)parameter) == true;
    }

    public void Execute(object parameter)
    {
        _executeMethod((T)parameter);
    }
}

2. Définissez votre commande

        public DelegateCommand<Window> CloseWindowCommand { get; private set; }


    public MyViewModel()//ctor of your viewmodel
    {
        //do something

        CloseWindowCommand = new DelegateCommand<Window>(CloseWindow);


    }
        public void CloseWindow(Window win) // this method is also in your viewmodel
    {
        //do something
        win?.Close();
    }

3. Liez votre commande à la vue

public MyView(Window win) //ctor of your view, window as parameter
    {
        InitializeComponent();
        MyButton.CommandParameter = win;
        MyButton.Command = ((MyViewModel)this.DataContext).CloseWindowCommand;
    }

4. Et maintenant la fenêtre

  Window win = new Window()
        {
            Title = "My Window",
            Height = 800,
            Width = 800,
            WindowStartupLocation = WindowStartupLocation.CenterScreen,

        };
        win.Content = new MyView(win);
        win.ShowDialog();

donc c'est tout, vous pouvez également lier la commande dans le fichier xaml et trouver la fenêtre avec FindAncestor et la lier au paramètre de commande.

0
Hajvaz

Je pense que le moyen le plus simple n'a pas déjà été inclus (presque). Au lieu d'utiliser Behaviors qui ajoute de nouvelles dépendances, utilisez simplement les propriétés attachées:

    using System;
    using System.Windows;
    using System.Windows.Controls;

    public class DialogButtonManager
    {
        public static readonly DependencyProperty IsAcceptButtonProperty = DependencyProperty.RegisterAttached("IsAcceptButton", typeof(bool), typeof(DialogButtonManager), new FrameworkPropertyMetadata(OnIsAcceptButtonPropertyChanged));
        public static readonly DependencyProperty IsCancelButtonProperty = DependencyProperty.RegisterAttached("IsCancelButton", typeof(bool), typeof(DialogButtonManager), new FrameworkPropertyMetadata(OnIsCancelButtonPropertyChanged));

        public static void SetIsAcceptButton(UIElement element, bool value)
        {
            element.SetValue(IsAcceptButtonProperty, value);
        }

        public static bool GetIsAcceptButton(UIElement element)
        {
            return (bool)element.GetValue(IsAcceptButtonProperty);
        }

        public static void SetIsCancelButton(UIElement element, bool value)
        {
            element.SetValue(IsCancelButtonProperty, value);
        }

        public static bool GetIsCancelButton(UIElement element)
        {
            return (bool)element.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 SetAcceptButton(Button button)
        {
            Window window = Window.GetWindow(button);
            button.Command = new RelayCommand(new Action<object>(ExecuteAccept));
            button.CommandParameter = window;
        }

        private static void ResetAcceptButton(Button button)
        {
            button.Command = null;
            button.CommandParameter = null;
        }

        private static void ExecuteAccept(object buttonWindow)
        {
            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));
            button.CommandParameter = window;
        }

        private static void ResetCancelButton(Button button)
        {
            button.Command = null;
            button.CommandParameter = null;
        }

        private static void ExecuteCancel(object buttonWindow)
        {
            Window window = (Window)buttonWindow;

            window.DialogResult = false;
        }
    }

Ensuite, il suffit de le définir sur vos boutons de dialogue:

<UniformGrid Grid.Row="2" Grid.Column="1" Rows="1" Columns="2" Margin="3" >
    <Button Content="Accept" IsDefault="True" Padding="3" Margin="3,0,3,0" DialogButtonManager.IsAcceptButton="True" />
    <Button Content="Cancel" IsCancel="True" Padding="3" Margin="3,0,3,0" DialogButtonManager.IsCancelButton="True" />
</UniformGrid>
0
Ignacio Soler Garcia

Je cherchais une solution au même problème et je me suis rendu compte que la suite du processus fonctionnait bien. La solution est similaire à ce que OP a mentionné dans sa question avec quelques différences:

  1. Pas besoin de la propriété IsCancel.

  2. Le code derrière ne doit pas fermer la fenêtre. Il suffit de définir DialogResult

Dans mon cas, il exécute d'abord le code derrière, puis affiche la commande de modèle associée au bouton.

XAML

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

Code derrière

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

Voir le modèle

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

J'espère que cela t'aides.

0
AksharRoop

J'ai la solution suivante dans Silverlight. Serait également dans 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>

Je vous souhaite de bonnes idées et projets; -)

0
ADM-IT

Cela pourrait vous aider à fermer une fenêtre wpf avec mvvm avec un code minimal derrière: http://jkshay.com/closing-a-wpf-window-using-mvvm-and-minimal-code-behind/ =

0
EvilInside

Vous pouvez reformuler la question et, ce faisant, proposer une autre solution. Comment puis-je activer la communication entre les vues, les modèles de vues et tout ce qui ne va pas dans un environnement MVVM? Vous pouvez utiliser le motif Mediator. C'est fondamentalement un système de notification. Pour l'implémentation réelle du médiateur, recherchez-le sur Google ou contactez-moi et je pourrai l'envoyer par courrier électronique.

Créez une commande dont le but est de fermer la vue.

public void Execute( object parameter )
{
    this.viewModel.DisposeMyStuff();
    Mediator.NotifyColleagues(Mediator.Token.ConfigWindowShouldClose);
}

Le médiateur émettra une notification (un jeton)

Écoutez cette notification (jeton) comme celle-ci dans le constructeur View codebehind:

public ClientConfigView()
{
    InitializeComponent();
    Mediator.ListenOn(Mediator.Token.ConfigWindowShouldClose, callback => this.Close() );
}
0
imbageek

La solution pour fermer une fenêtre dans wpf qui a fonctionné pour moi n’est pas résolue ici, alors j’ai pensé que j’ajouterais ma solution.

        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.

            //            }
        }

Ajoutez l'événement CloseWindow au bouton dans votre fenêtre comme suit.

<Button Content="Cancel" Click="CloseWindow" >
0
sheraz yousaf