WPF( MVVM): fermer une vue de Viewmodel?

Quelqu'un a-t-il trouvé un moyen intelligent de fermer une vue dans un modèle de vue en utilisant MVVM?

peut-être y a-t-il un moyen d'utiliser binding pour signaler la vue (fenêtre) à fermer?

j'apprécierais vraiment tout ce que quelqu'un a à dire.

fondamentalement j'ai un loginView qui est lié à un loginViewModel, dans le viewmodel (en utilisant la liaison sur une commande) je teste pour voir si le login est réussi et si c'est je charge fondamentalement une nouvelle vue (mainview) et joindre son texte de données...

mais j'ai toujours le loginView affiché - donc je dois le signaler pour décharger..

j'espérais aussi une solution générique parce que je suis sûr que je vais devoir faire ce genre de chose dans d'autres situations

des idées?

46
demandé sur mark smith 2009-09-27 23:17:00

11 réponses

Edit: Voir mon blog pour une explication plus détaillée.

quand j'ai besoin d'y arriver, J'utilise une interface IRequestCloseViewModel que j'ai créée.

cette interface ne contient qu'un seul événement: RequestClose. Cet événement est soulevé par le ViewModel (qui hérite d'une classe ViewModelBase et implémente IRequestCloseViewModel) quand il veut fermer sa vue associée.

dans mon application, toutes les fenêtres héritent d'une application de classe abstraite Window. Cette classe abstraite est notifiée chaque fois que le DataContext a changé et dans le gestionnaire vérifie si le DataContext supporte le nouveau modèle Irequestcloseview. Si c'est le cas, un gestionnaire d'événement est mis en place pour fermer la Fenêtre lorsque l'événement est déclenché.

alternativement, comme Kent a dit, Vous pouvez utiliser le contrôleur d'écran qui gère ce mecanisme dans une classe externe.

35
répondu japf 2009-09-30 07:06:29

Je ne suis pas sûr du cadre MVVM que vous utilisez, mais la plupart contiennent une sorte de solution de messagerie / notification qui est facile avoir des choses s'enregistrer pour les messages qui sont envoyés. Il n'y a aucune raison que je puisse imaginer que votre vue ne pourrait pas s'enregistrer pour un message tel que "CloseWindowsBoundTo" et le modèle de vue en tant qu'expéditeur. Alors à votre avis, vous pouvez simplement vous inscrire pour ce message, et de comparer votre datacontext à l'expéditeur. Si elles correspondent, fermez la fenêtre.

Simple, et garde votre vue abstraite de votre modèle de vue.

Voici mon approche en utilisant MVVM-Light toolkit:

dans le modèle de vue:

public void notifyWindowToClose()
{
    Messenger.Default.Send<NotificationMessage>(
        new NotificationMessage(this, "CloseWindowsBoundToMe")
    );
}

et dans la vue:

Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
    if (nm.Notification == "CloseWindowsBoundToMe")
    {
        if (nm.Sender == this.DataContext)
            this.Close();
    }
});
22
répondu Ryan from Denver 2014-05-06 07:51:15

généralement, vous utiliserez une sorte de contrôleur/présentateur/service pour piloter l'activation/désactivation de l'écran. MVVM n'est pas censé être le un modèle pour les diriger tous . Vous aurez besoin de le combiner avec d'autres modèles dans toute application non-triviale.

cela dit, dans certaines situations, il est logique d'avoir un modèle de vue qui gère le cycle de vie des modèles de vue de l'enfant. Par exemple, vous pourriez avoir un EditorViewModel qui gère un collection de modèles de vues d'enfants - un pour chaque document en cours d'édition. Dans ce cas, le simple fait d'Ajouter/Supprimer à/de cette collection peut entraîner l'activation/désactivation de la vue. Mais cela ne sonne pas comme il convient à votre cas d'utilisation.

8
répondu Kent Boogaart 2011-09-27 15:17:39

je sais que c'est une vieille question, mais j'ai une bonne façon de le faire donc j'ai pensé que je partagerais pour n'importe qui d'autre en trébuchant à travers ceci. Je l'habitude d'utiliser le comportement joint dialogcloser, mais je trouve la solution ci-dessous plus facile où je peux l'utiliser. L'exemple ci-dessous prend un exemple de bouton de fermeture sur la fenêtre pour la simplicité.

passez la fenêtre comme paramètre de commande.

dans le bouton xaml pour la vue:

CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"

dans la méthode de commande execute dans le modèle view:

if (parameter is System.Windows.Window)
{
    (parameter as System.Windows.Window).Close();
}
8
répondu cjmurph 2014-02-27 03:37:47

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

<Style.Triggers> <DataTrigger Binding="{Binding CloseSignal}" Value="true"> <Setter Property="Behaviours:WindowCloseBehaviour.Close" Value="true" /> </DataTrigger> </Style>

7
répondu Adam Mills 2010-07-19 16:13:10

vous pouvez faire une commande qui se fixe à la fenêtre et quand exécuté ferme la fenêtre. Ensuite, vous pouvez lier votre commande à une propriété sur votre modèle de vue, et exécuter la commande quand vous voulez fermer la fenêtre.

4
répondu 2009-12-14 18:51:57

j'utiliserais un ApplicationController qui instancie le LoginViewModel et affiche le LoginView. Lorsque l'utilisateur passe à l'écran login, le ApplicationController ferme la LoginView et affiche la MainView avec son Modèlecentral.

la façon de procéder est illustrée dans les exemples de demandes du projet WPF Application Framework (WAF) .

2
répondu jbe 2009-10-02 17:54:24

Cette réponse montre une autre façon de le faire:

comment le modèle de vue doit-il fermer le formulaire?

il utilise une propriété attachée pour lier la propriété DialogResult window à une propriété ViewModel. Lorsque vous définissez la valeur de DialogResult à true ou false, la vue est fermée.

2
répondu Jorge Vargas 2017-05-23 11:54:43

juste fermer dans un EventHandler en code derrière et gérer tout le reste dans le modèle de vue où vous pouvez utiliser une liaison de commande.

2
répondu Tarion 2012-06-30 18:37:52

vous pouvez également faire cela en utilisant l'événement. Bien que vous ayez besoin de 3 lignes de codes dans votre vue code derrière (certains puristes MVVM n'aiment pas cela);

dans votre viewmodel, vous créez un événement auquel la vue peut souscrire:

    public event CloseEventHandler Closing;
    public delegate void CloseEventHandler();
    private void RaiseClose()
    {
        if (Closing != null)
            Closing();
    }

dans votre, Voir vous vous abonnez à l'événement après votre méthode initializecomponent comme ci-dessous:

        public View
        {
           *//The event can be put in an interface to avoid direct dependence of the view on the viewmodel. So below becomes
            //ICloseView model = (ICloseView)this.DataContext;*
            ProgressWindowViewModel model = (ProgressWindowViewModel)this.DataContext;
            model.Closing += Model_Closing;
        }
        private void Model_Closing()
        {
             this.Close();
        }

vous appelez simplement RaiseClose () quand vous êtes prêt à fermer la vue de la ViewModel.

Vous pouvez même utiliser cette méthode pour envoyer un message à la vue du viewmodel.

L'événement peut être mis dans une interface afin d'éviter la dépendance directe de la vue sur le viewmodel.

1
répondu falopsy 2017-08-11 11:38:38

pour fermer la vue de viewmodel, j'ai utilisé le GalaSoft MVVM Light Toolkit que vous pouvez télécharger ici: http://www.mvvmlight.net/

  1. créez une classe comme celle-ci: demande de fermeture de classe publique: base de messages {}

  2. ajoutez ceci à votre vue constructeur: Messenger.Défaut.S'inscrire(ce, vm, msg=> Close());

  3. fermez la fenêtre de votre: Messenger.Défaut.Envoyer(nouveau ClosingRequested(), this);

0
répondu Mick3y 2015-07-28 15:58:17