Comment le ViewModel doit-il fermer le formulaire?

J’essaie d’apprendre WPF et le problème MVVM, mais j’ai rencontré un problème. Cette question est similaire mais pas tout à fait identique à celle-ci (handling-dialogs-in-wpf-with-mvvm) …

J’ai un formulaire “Login” écrit en utilisant le pattern MVVM.

Ce formulaire a un ViewModel qui contient le nom d’utilisateur et le mot de passe, qui sont liés à la vue dans XAML en utilisant des liaisons de données normales. Il a également une commande “Login” qui est liée au bouton “Login” du formulaire, en utilisant une liaison de données normale.

Lorsque la commande “Login” se déclenche, elle appelle une fonction du ViewModel qui s’éteint et envoie des données sur le réseau pour se connecter. Lorsque cette fonction est terminée, il y a 2 actions:

  1. Le login était invalide – nous montrons simplement un MessageBox et tout va bien

  2. Le login était valide, nous devons fermer le formulaire de connexion et le rendre vrai comme DialogResult

Le problème est que ViewModel ne sait rien de la vue réelle, alors comment peut-il fermer la vue et lui dire de renvoyer un DialogResult particulier? Je pourrais coller du code dans CodeBehind et / ou passer la vue à ViewModel, mais cela semble aller à l’encontre de tout l’intérêt de MVVM …


Mettre à jour

En fin de compte, j’ai juste violé la “pureté” du modèle MVVM et la vue a publié un événement Closed et exposé une méthode Close . Le ViewModel appelle alors view.Close . La vue est uniquement connue via une interface et connectée via un conteneur IOC, donc aucune testabilité ou maintenabilité n’est perdue.

Il semble plutôt idiot que la réponse acceptée soit à -5 votes! Bien que je sois bien conscient des bons sentiments que l’on éprouve en résolvant un problème tout en étant “pur”, je ne suis sûrement pas le seul à penser que 200 lignes d’événements, de commandes et de comportements permettent d’éviter une méthode en une ligne. le nom de “motifs” et de “pureté” est un peu ridicule ….

J’ai été inspiré par la réponse de Thejuan pour écrire une propriété jointe plus simple. Aucun style, aucun déclencheur; à la place, vous pouvez simplement faire ceci:

  

C’est presque aussi propre que si l’équipe de WPF l’avait bien définie et avait fait de DialogResult une propriété de dépendance en premier lieu. Il suffit de mettre un bool? DialogResult bool? DialogResult propriété sur votre ViewModel et implémenter INotifyPropertyChanged, et voilà, votre ViewModel peut fermer la fenêtre (et définir son DialogResult) simplement en définissant une propriété. MVVM comme il se doit.

Voici le code pour DialogCloser:

 using System.Windows; namespace ExCastle.Wpf { public static class DialogCloser { public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached( "DialogResult", typeof(bool?), typeof(DialogCloser), new PropertyMetadata(DialogResultChanged)); private static void DialogResultChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d as Window; if (window != null) window.DialogResult = e.NewValue as bool?; } public static void SetDialogResult(Window target, bool? value) { target.SetValue(DialogResultProperty, value); } } } 

J’ai aussi posté ceci sur mon blog .

De mon sharepoint vue, la question est plutôt bonne car la même approche serait utilisée non seulement pour la fenêtre “Login”, mais pour tout type de fenêtre. J’ai passé en revue beaucoup de suggestions et aucune n’est acceptable pour moi. Veuillez consulter ma suggestion tirée de l’ article sur le modèle de conception de MVVM .

Chaque classe ViewModel doit hériter de WorkspaceViewModel qui possède l’événement CloseCommand et la propriété ICommand type ICommand . L’implémentation par défaut de la propriété CloseCommand l’ CloseCommand .

Pour fermer la fenêtre, la méthode OnLoaded de votre fenêtre doit être remplacée:

 void CustomerWindow_Loaded(object sender, RoutedEventArgs e) { CustomerViewModel customer = CustomerViewModel.GetYourCustomer(); DataContext = customer; customer.RequestClose += () => { Close(); }; } 

ou méthode OnStartup de votre application:

  protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); MainWindow window = new MainWindow(); var viewModel = new MainWindowViewModel(); viewModel.RequestClose += window.Close; window.DataContext = viewModel; window.Show(); } 

Je suppose que l’événement CloseCommand et l’ CloseCommand propriété CloseCommand dans WorkspaceViewModel sont assez clairs, mais je vais les montrer cohérents:

 public abstract class WorkspaceViewModel : ViewModelBase // There's nothing interesting in ViewModelBase as it only implements the INotifyPropertyChanged interface { RelayCommand _closeCommand; public ICommand CloseCommand { get { if (_closeCommand == null) { _closeCommand = new RelayCommand( param => Close(), param => CanClose() ); } return _closeCommand; } } public event Action RequestClose; public virtual void Close() { if ( RequestClose != null ) { RequestClose(); } } public virtual bool CanClose() { return true; } } 

Et le code source du RelayCommand :

 public class RelayCommand : ICommand { #region Constructors public RelayCommand(Action execute, Predicate canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } #endregion // Constructors #region ICommand Members [DebuggerStepThrough] public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void Execute(object parameter) { _execute(parameter); } #endregion // ICommand Members #region Fields readonly Action _execute; readonly Predicate _canExecute; #endregion // Fields } 

PS Ne me traite pas mal pour ces sources! Si je les avais hier, cela m’aurait sauvé quelques heures …

PPS Tous les commentaires ou suggestions sont les bienvenus.

J’ai utilisé des comportements attachés pour fermer la fenêtre. Liez une propriété “signal” sur votre ViewModel au comportement attaché (j’utilise un déclencheur). Quand il est défini sur true, le comportement ferme la fenêtre.

http://adammills.wordpress.com/2009/07/01/window-close-from-xaml/

Il y a beaucoup de commentaires en faveur du pour et du contre du MVVM ici. Pour moi, je suis d’accord avec Nir; il s’agit d’utiliser le modèle de manière appropriée et MVVM ne correspond pas toujours. Les gens semblent être prêts à sacrifier tous les principes les plus importants de la conception de logiciels pour les amener à s’adapter au MVVM.

Cela dit, je pense que votre cas pourrait être un bon ajustement avec un peu de refactoring.

Dans la plupart des cas que j’ai rencontrés, WPF vous permet de vous en sortir SANS plusieurs Window . Vous pourriez peut-être essayer d’utiliser Frame s et Page s au lieu de Windows avec DialogResult s.

Dans votre cas, je suggère que LoginFormViewModel gère la commande LoginCommand et, si la connexion est invalide, définit une propriété sur LoginFormViewModel sur une valeur appropriée ( false ou une valeur enum comme UserAuthenticationStates.FailedAuthentication ). Vous feriez la même chose pour une connexion réussie ( true ou une autre valeur enum). Vous utiliseriez alors un DataTrigger qui répond aux divers états d’authentification d’utilisateur et pourrait utiliser un simple Setter pour modifier la propriété Source du Frame .

Avoir votre fenêtre de connexion retourne un DialogResult je pense que c’est là que vous êtes confus; que DialogResult est vraiment une propriété de votre ViewModel. Dans mon expérience, certes limitée, avec WPF, quand quelque chose ne se sent pas bien parce que je pense à la manière dont j’aurais fait la même chose avec WinForms.

J’espère que cela pourra aider.

En supposant que votre boîte de dialog de connexion est la première fenêtre créée, essayez ceci dans votre classe LoginViewModel:

  void OnLoginResponse(bool loginSucceded) { if (loginSucceded) { Window1 window = new Window1() { DataContext = new MainWindowViewModel() }; window.Show(); App.Current.MainWindow.Close(); App.Current.MainWindow = window; } else { LoginError = true; } } 

La façon dont je le traiterais est d’append un gestionnaire d’événement dans mon ViewModel. Lorsque l’utilisateur s’est connecté avec succès, je déclenche l’événement. Dans mon sharepoint vue, je m’attacherais à cet événement et, à son licenciement, je fermerais la fenêtre.

Il s’agit d’une solution simple et propre: vous ajoutez un événement à ViewModel et indiquez à Window de se fermer lorsque cet événement est déclenché.

Pour plus de détails, voir l’article de mon blog, Fermer la fenêtre de ViewModel .

Voici ce que j’ai d’abord fait, qui fonctionne, mais il semble plutôt long et laid (tout ce qui est statique n’est jamais bon)

1: App.xaml.cs

 public partial class App : Application { // create a new global custom WPF Command public static readonly RoutedUICommand LoggedIn = new RoutedUICommand(); } 

2: LoginForm.xaml

 // bind the global command to a local eventhandler  

3: LoginForm.xaml.cs

 // implement the local eventhandler in codebehind private void OnLoggedIn( object sender, ExecutedRoutedEventArgs e ) { DialogResult = true; Close(); } 

4: LoginFormViewModel.cs

 // fire the global command from the viewmodel private void OnRemoteServerReturnedSuccess() { App.LoggedIn.Execute(this, null); } 

J’ai ensuite retiré tout ce code et le LoginFormViewModel appelé la méthode Close dans sa vue. Cela a fini par être beaucoup plus agréable et plus facile à suivre. IMHO le but des modèles est de donner aux gens un moyen plus facile de comprendre ce que fait votre application, et dans ce cas, MVVM le rendait beaucoup plus difficile à comprendre que si je ne l’avais pas utilisé, et était maintenant un anti- motif.

Pour info, j’ai rencontré ce même problème et je pense que j’ai trouvé un travail qui ne nécessite pas de globales ou de statique, même si ce n’est peut-être pas la meilleure réponse. Je laisse les gars décider pour vous.

Dans mon cas, le ViewModel qui instancie la fenêtre à afficher (appelons-le ViewModelMain) connaît également le LoginFormViewModel (en utilisant la situation ci-dessus à titre d’exemple).

J’ai donc créé une propriété sur le LoginFormViewModel de type ICommand (Permet de l’appeler CloseWindowCommand). Puis, avant d’appeler .ShowDialog () sur la fenêtre, je définis la propriété CloseWindowCommand du LoginFormViewModel sur la méthode window.Close () de la fenêtre que j’ai instanciée. Ensuite, à l’intérieur du LoginFormViewModel, tout ce que j’ai à faire est d’appeler CloseWindowCommand.Execute () pour fermer la fenêtre.

Je suppose que c’est un peu une solution de contournement / hack, mais cela fonctionne bien sans vraiment briser le pattern MVVM.

N’hésitez pas à critiquer ce processus autant que vous le souhaitez, je peux le prendre! 🙂

C’est probablement très tard, mais j’ai rencontré le même problème et j’ai trouvé une solution qui fonctionne pour moi.

Je n’arrive pas à comprendre comment créer une application sans dialogs (c’est peut-être juste un bloc mental). J’étais donc dans une impasse avec MVVM et en montrant un dialog. Je suis donc tombé sur cet article de CodeProject:

http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

Qui est un UserControl qui permet essentiellement à une fenêtre d’être dans l’arborescence visuelle d’une autre fenêtre (non autorisée dans xaml). Il expose également un DependencyProperty appelé IsShowing.

Vous pouvez définir un style comme dans un Resourcedictionary, qui affiche généralement la boîte de dialog lorsque la propriété Content du contrôle! = Null via les déclencheurs:

  

Dans la vue où vous voulez afficher la boîte de dialog, il vous suffit d’avoir ceci:

  

Et dans votre ViewModel, il suffit de définir la propriété sur une valeur (Note: la classe ViewModel doit prendre en charge INotifyPropertyChanged pour que la vue sache que quelque chose est arrivé).

ainsi:

 DialogViewModel = new DisplayViewModel(); 

Pour faire correspondre le ViewModel avec la vue, vous devez avoir quelque chose comme ceci dans un dictionnaire de ressources:

    

Avec tout cela, vous obtenez un code à un trait pour afficher la boîte de dialog. Le problème que vous rencontrez est que vous ne pouvez pas fermer le dialog avec le code ci-dessus. C’est pourquoi vous devez placer un événement dans une classe de base ViewModel dont DisplayViewModel hérite et à la place du code ci-dessus, écrivez ceci

  var vm = new DisplayViewModel(); vm.RequestClose += new RequestCloseHandler(DisplayViewModel_RequestClose); DialogViewModel = vm; 

Ensuite, vous pouvez gérer le résultat de la boîte de dialog via le rappel.

Cela peut sembler un peu complexe, mais une fois que les bases sont posées, c’est assez simple. Encore une fois c’est ma mise en œuvre, je suis sûr qu’il y en a d’autres 🙂

J’espère que ça aide, ça m’a sauvé.

Ok, donc cette question a presque 6 ans et je ne trouve toujours pas ici ce que je pense être la bonne réponse, alors permettez-moi de partager mes “2 cents” …

J’ai en fait deux façons de le faire: la première est la plus simple, la seconde la bonne, donc si vous cherchez la bonne, passez simplement à la première et passez à la deuxième :

1. Rapide et facile (mais pas complet)

Si j’ai juste un petit projet, je crée parfois un CloseWindowAction dans ViewModel:

  public Action CloseWindow { get; set; } // In MyViewModel.cs 

Et quiconque crée la vue ou dans le code de la vue derrière, je viens de définir la méthode que l’action appellera:

(rappelez-vous que MVVM concerne la séparation de View et de ViewModel … le code de la vue est toujours la vue et tant qu’il y a une séparation correcte, vous ne violez pas le modèle)

Si certains ViewModel créent une nouvelle fenêtre:

 private void CreateNewView() { MyView window = new MyView(); window.DataContext = new MyViewModel { CloseWindow = window.Close, }; window.ShowDialog(); } 

Ou si vous le voulez dans votre fenêtre principale, placez-le simplement sous le constructeur de votre View:

 public MyView() { InitializeComponent(); this.DataContext = new MainViewModel { CloseWindow = this.Close }; } 

Lorsque vous souhaitez fermer la fenêtre, appelez simplement l’action sur votre ViewModel.


2. la bonne façon

Maintenant, la bonne façon de le faire est d’utiliser Prism (IMHO), et tout cela se trouve ici .

Vous pouvez créer une demande d’interaction , la remplir avec les données dont vous avez besoin dans votre nouvelle fenêtre, la copier, la fermer et même recevoir des données . Tout cela encapsulé et MVVM approuvé. Vous obtenez même un état de fermeture de la fenêtre , par exemple si l’utilisateur a Canceled ou Accepted (bouton OK) la fenêtre et les données si vous en avez besoin . C’est un peu plus compliqué et la réponse n ° 1, mais c’est beaucoup plus complet et un modèle recommandé par Microsoft.

Le lien que j’ai donné contient tous les extraits de code et exemples, donc je ne prendrai pas de code ici, il suffit de lire l’article de téléchargement du Prism Quick Start et de l’exécuter, il est très simple de comprendre un peu plus ça marche, mais les avantages sont plus importants que de fermer une fenêtre.

Vous pouvez faire en sorte que ViewModel expose un événement auquel la vue est enregistrée. Ensuite, lorsque ViewModel décide de l’heure de fermeture de la vue, il déclenche cet événement qui provoque la fermeture de la vue. Si vous souhaitez qu’une valeur de résultat spécifique soit renvoyée, vous devez alors avoir une propriété dans ViewModel.

 public partial class MyWindow: Window { public ApplicationSelection() { InitializeComponent(); MyViewModel viewModel = new MyViewModel(); DataContext = viewModel; viewModel.RequestClose += () => { Close(); }; } } public class MyViewModel { //...Your code... public event Action RequestClose; public virtual void Close() { if (RequestClose != null) { RequestClose(); } } public void SomeFunction() { //...Do something... Close(); } } 

Pourquoi ne pas simplement passer la fenêtre en tant que paramètre de commande?

C #:

  private void Cancel( Window window ) { window.Close(); } private ICommand _cancelCommand; public ICommand CancelCommand { get { return _cancelCommand ?? ( _cancelCommand = new Command.RelayCommand( ( window ) => Cancel( window ), ( window ) => ( true ) ) ); } } 

XAML:

  

Juste pour append au nombre massif de réponses, je veux append ce qui suit. En supposant que vous avez une ICommand sur votre ViewModel et que vous voulez que cette commande ferme sa fenêtre (ou toute autre action), vous pouvez utiliser quelque chose comme ceci.

 var windows = Application.Current.Windows; for (var i=0;i< windows.Count;i++ ) if (windows[i].DataContext == this) windows[i].Close(); 

Ce n'est pas parfait et peut être difficile à tester (car il est difficile de se moquer / de stuber un statique) mais c'est plus propre (IMHO) que les autres solutions.

Erick

J’ai implémenté la solution de Joe White, mais j’ai rencontré des problèmes avec des erreurs occasionnelles ” DialogResult ne peut être défini qu’après la création de Window et son affichage en tant que dialog “.

Je gardais le ViewModel après la fermeture de la vue et, plus tard, j’ouvrais plus tard une nouvelle vue en utilisant la même machine virtuelle. Il semble que la fermeture de la nouvelle vue avant la récupération de l’ancienne vue entraîne l’ apparition de DialogResultChanged qui tente de définir la propriété DialogResult sur la fenêtre fermée, provoquant ainsi l’erreur.

Ma solution consistait à modifier DialogResultChanged pour vérifier la propriété IsLoaded de la fenêtre:

 private static void DialogResultChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d as Window; if (window != null && window.IsLoaded) window.DialogResult = e.NewValue as bool?; } 

Après avoir effectué cette modification, toutes les pièces jointes aux boîtes de dialog fermées sont ignorées.

Une autre solution consiste à créer une propriété avec INotifyPropertyChanged dans un modèle de vue tel que DialogResult, puis dans Code Behind, écrivez ceci:

 public class SomeWindow: ChildWindow { private SomeViewModel _someViewModel; public SomeWindow() { InitializeComponent(); this.Loaded += SomeWindow_Loaded; this.Closed += SomeWindow_Closed; } void SomeWindow_Loaded(object sender, RoutedEventArgs e) { _someViewModel = this.DataContext as SomeViewModel; _someViewModel.PropertyChanged += _someViewModel_PropertyChanged; } void SomeWindow_Closed(object sender, System.EventArgs e) { _someViewModel.PropertyChanged -= _someViewModel_PropertyChanged; this.Loaded -= SomeWindow_Loaded; this.Closed -= SomeWindow_Closed; } void _someViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == SomeViewModel.DialogResultPropertyName) { this.DialogResult = _someViewModel.DialogResult; } } } 

Le fragment le plus important est _someViewModel_PropertyChanged . DialogResultPropertyName peut être une chaîne de caractères publique dans SomeViewModel .

J’utilise ce genre de truc pour apporter des modifications dans les contrôles de vue au cas où cela serait difficile à faire dans ViewModel. OnPropertyChanged dans ViewModel, vous pouvez faire tout ce que vous voulez dans View. ViewModel est toujours “unit testable” et quelques petites lignes de code dans le code behind ne font aucune différence.

J’ai fini par mélanger la réponse de Joe White et un code de la réponse d’ Adam Mills , car je devais montrer un contrôle utilisateur dans une fenêtre créée par programmation. Donc le DialogCloser n’a pas besoin d’être sur la fenêtre, il peut être sur le contrôle utilisateur lui-même

  

Et le DialogCloser trouvera la fenêtre du contrôle utilisateur s’il n’était pas attaché à la fenêtre elle-même.

 namespace Wpf { public static class DialogCloser { public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached( "DialogResult", typeof(bool?), typeof(DialogCloser), new PropertyMetadata(DialogResultChanged)); private static void DialogResultChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d.GetWindow(); if (window != null) window.DialogResult = e.NewValue as bool?; } public static void SetDialogResult(DependencyObject target, bool? value) { target.SetValue(DialogResultProperty, value); } } public static class Extensions { public static Window GetWindow(this DependencyObject sender_) { Window window = sender_ as Window; return window ?? Window.GetWindow( sender_ ); } } } 

Je voudrais aller de cette façon:

 using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Messaging; // View public partial class TestCloseWindow : Window { public TestCloseWindow() { InitializeComponent(); Messenger.Default.Register(this, (msg) => Close()); } } // View Model public class MainViewModel: ViewModelBase { ICommand _closeChildWindowCommand; public ICommand CloseChildWindowCommand { get { return _closeChildWindowCommand?? (_closeChildWindowCommand = new RelayCommand(() => { Messenger.Default.Send(new CloseWindowMsg()); })); } } } public class CloseWindowMsg { } 

J’ai lu toutes les réponses mais je dois dire que la plupart d’entre elles ne sont tout simplement pas suffisantes ou même pires.

Vous pouvez gérer cela avec une classe DialogService dont la responsabilité est d’afficher la fenêtre de dialog et le résultat du dialog de retour. J’ai créé des exemples de projets démontrant leur implémentation et leur utilisation.

voici les parties les plus importantes:

 //we will call this interface in our viewmodels public interface IDialogService { bool? ShowDialog(object dialogViewModel, ssortingng caption); } //we need to display logindialog from mainwindow public class MainWindowViewModel : ViewModelBase { public ssortingng Message {get; set;} public void ShowLoginCommandExecute() { var loginViewModel = new LoginViewModel(); var dialogResult = this.DialogService.ShowDialog(loginViewModel, "Please, log in"); //after dialog is closed, do someting if (dialogResult == true && loginViewModel.IsLoginSuccessful) { this.Message = ssortingng.Format("Hello, {0}!", loginViewModel.Username); } } } public class DialogService : IDialogService { public bool? ShowDialog(object dialogViewModel, ssortingng caption) { var contentView = ViewLocator.GetView(dialogViewModel); var dlg = new DialogWindow { Title = caption }; dlg.PART_ContentControl.Content = contentView; return dlg.ShowDialog(); } } 

N’est-ce pas plus simple? plus simple, plus lisible et plus facile à déboguer que EventAggregator ou d’autres solutions similaires?

Comme vous pouvez le voir, dans mes modèles de vue, j’ai utilisé la première approche de ViewModel décrite dans mon post ici: Meilleures pratiques pour appeler View from ViewModel dans WPF

Bien sûr, dans la réalité, le DialogService.ShowDialog doit avoir plus d’options pour configurer le dialog, par exemple les boutons et les commandes à exécuter. Il y a différentes manières de le faire, mais c’est hors de propos 🙂

Bien que cela ne réponde pas à la question de savoir comment procéder via viewmodel, cela montre comment le faire en utilisant uniquement XAML + le SDK de fusion.

J’ai choisi de télécharger et d’utiliser deux fichiers du SDK Blend, que vous pouvez tous deux utiliser en tant que package Microsoft via NuGet. Les fichiers sont les suivants:

System.Windows.Interactivity.dll et Microsoft.Expression.Interactions.dll

Microsoft.Expression.Interactions.dll vous offre des fonctionnalités intéressantes telles que la possibilité de définir une propriété ou d’appeler une méthode sur votre viewmodel ou une autre cible, ainsi que d’autres widgets à l’intérieur.

Certains XAML:

        

Notez que si vous voulez simplement un comportement OK / Annuler simple, vous pouvez utiliser w / en utilisant les propriétés IsDefault et IsCancel tant que la fenêtre est affichée avec Window.ShowDialog ().
Personnellement, j’avais des problèmes avec un bouton dont la propriété IsDefault était définie sur true, mais elle était masquée lors du chargement de la page. Il n’a pas semblé vouloir jouer bien après son affichage, donc je ne fais que définir la propriété Window.DialogResult comme indiqué ci-dessus et cela fonctionne pour moi.

Here is the simple bug free solution (with source code), It is working for me.

  1. Derive your ViewModel from INotifyPropertyChanged

  2. Create a observable property CloseDialog in ViewModel

     public void Execute() { // Do your task here // if task successful, assign true to CloseDialog CloseDialog = true; } private bool _closeDialog; public bool CloseDialog { get { return _closeDialog; } set { _closeDialog = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName]ssortingng property = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } 

    }

  3. Attach a Handler in View for this property change

      _loginDialogViewModel = new LoginDialogViewModel(); loginPanel.DataContext = _loginDialogViewModel; _loginDialogViewModel.PropertyChanged += OnPropertyChanged; 
  4. Now you are almost done. In the event handler make DialogResult = true

     protected void OnPropertyChanged(object sender, PropertyChangedEventArgs args) { if (args.PropertyName == "CloseDialog") { DialogResult = true; } } 

Create a Dependency Property in your View /any UserControl (or Window you want to close). Comme ci-dessous:

  public bool CloseTrigger { get { return (bool)GetValue(CloseTriggerProperty); } set { SetValue(CloseTriggerProperty, value); } } public static readonly DependencyProperty CloseTriggerProperty = DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(ControlEventBase), new PropertyMetadata(new PropertyChangedCallback(OnCloseTriggerChanged))); private static void OnCloseTriggerChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) { //write Window Exit Code } 

And bind it from your ViewModel’s property :

  

Property In VeiwModel :

 private bool closeWindow; public bool CloseWindow { get { return closeWindow; } set { closeWindow = value; RaiseChane("CloseWindow"); } } 

Now sortinggger the close operation by changing the CloseWindow value in ViewModel. 🙂

Behavior is the most convenient way here.

  • From one hand, it can be binded to the given viewmodel (that can signal “close the form!”)

  • From another hand, it has access to the form itself so can subscribe to necessary form-specific events, or show confirmation dialog, or anything else.

Writing necessary behavior can be seen boring very first time. However, from now on, you can reuse it on every single form you need by exact one-liner XAML snippet. And if necessary, you can extract it as a separate assembly so it can be included into any next project you want.

Where you need to close the window, simply put this in the viewmodel:

ta-da

  foreach (Window window in Application.Current.Windows) { if (window.DataContext == this) { window.Close(); return; } } 
 Application.Current.MainWindow.Close() 

Thats enough!