web-dev-qa-db-fra.com

Comment ouvrir une nouvelle fenêtre à l'aide de MVVM Light Toolkit

J'utilise MVVM Light toolkit dans mon application WPF. Je voudrais savoir quelle est la meilleure approche pour ouvrir une nouvelle fenêtre à partir d'une fenêtre existante. J'ai ce MainViewModel, qui est responsable du MainWindow de ma candidature. Maintenant dans le MainView, sur un clic de bouton, je voudrais ouvrir une deuxième fenêtre au dessus. J'ai RelayCommmand lié à ButtonCommand. Dans la méthode RelayCommand, je peux créer un nouvel objet fenêtre et appeler simplement Show(), quelque chose comme ceci:

var view2 = new view2()
view2.Show()

mais je ne pense pas que le ViewModel devrait être responsable de la création du nouveau view2 objet. J'ai lu cet article WPF MVVM Get Parent from VIEW MODEL où Bugnion a suggéré de passer un message au view1 du viewmodel1 puis view1 devrait créer le nouveau view2. Mais je ne sais pas vraiment ce qu'il veut dire en passant le message au view1? Comment le view1 gérer le message? Dans son code ou quoi?

Cordialement, Nabeel

46
nabeelfarid

Passer un message de ViewModel1 à View1 signifie utiliser capacités de messagerie dans MVVM Light Toolkit .

Par exemple, votre ViewModel1 pourrait avoir une commande appelée ShowView2Command, puis il enverrait un message pour afficher la vue.

public class ViewModel1 : ViewModelBase
{
    public RelayCommand ShowView2Command { private set; get; }

    public ViewModel1() : base()
    {
        ShowView2Command = new RelayCommand(ShowView2CommandExecute);
    }

    public void ShowView2CommandExecute()
    {
        Messenger.Default.Send(new NotificationMessage("ShowView2"));
    }
}

View1 s'inscrirait pour recevoir des messages dans son code derrière et afficherait View2 lorsqu'il recevra le message correct.

public partial class View1 : UserControl
{
    public View1()
    {
        InitializeComponent();
        Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
    }

    private void NotificationMessageReceived(NotificationMessage msg)
    {
        if (msg.Notification == "ShowView2")
        {
            var view2 = new view2();
            view2.Show();
        }
    }
}
56
Matt Casto

Pourquoi choisissez-vous cette voie? C'est simple. Si vous remplacez votre bouton par un bouton à bascule, ou un lien hypertexte, ou tout autre nombre de contrôles de type bouton, vous n'avez pas besoin de mettre à jour votre "code derrière" - c'est un principe de base du modèle MVVM. Dans votre nouveau toggleButton (ou autre), vous finissez toujours par vous lier à la même commande exacte.

Par exemple, je crée un projet pour un client qui veut avoir 2 interfaces utilisateur - une va être fondamentalement différente dans tous les sens, en termes de présentation. Onglets horizontaux vs RadPanelBar vertical (pensez à l'accordéon) pour la navigation. Ces deux vues peuvent pointer vers le même viewModel - lorsqu'un utilisateur clique sur l'onglet Ordre de travail dans la vue 1, il déclenche le même "WorkOrderCommand" qui est déclenché dans l'en-tête de l'ordre de travail dans la barre du panneau.

Dans un modèle code-behind, vous devez coder deux événements distincts. Ici, il vous suffit d'en coder un.

En outre, il permet à un concepteur utilisant Blend de créer la mise en page de son choix. Tant qu'ils ont les crochets (contrôle EventToCommand) en place, moi (en tant que développeur) ne me soucie pas à quoi ressemble le produit final.

Le couplage lâche est incroyablement puissant.

4
Scott Silvi

Vous pouvez faire de cette manière comme vous devez créer des événements et les enregistrer dans view et les appeler dans view model.and ouvrir cette fenêtre pop-up.

Comme cet exemple

public class Mainclass : MainView
{
    public delegate abc RegisterPopUp(abc A);
    public RegisterPopUp POpUpEvent ;

    public RelayCommand ShowCommand { private set; get; }  


    public void ShowCommand() 
    { 
        ShowCommand("Your parameter");
    } 
}

à l'intérieur de la vue MainView mn=new MainView();

Enregistrez l'événement ici comme thake mn.POpUpEvent += Puis cliquez deux fois sur le bouton de l'onglet

et dans les registres, la méthode contextuelle permet de saisir le code pour ouvrir la fenêtre contextuelle.

3
Hoshiyar

Sauf si je manque le point ici - si je devais utiliser le code derrière, alors pourquoi ne pas implémenter directement l'événement button_click et ouvrir la deuxième vue?

Ce que Bugnion semble suggérer est view1 -> clic sur le bouton -> commande de relais -> viewmodel1 -> message -> view1 -> view1.cs -> open view 2.

Vous allez de toute façon sacrifier la testabilité en écrivant du code, alors pourquoi prendre un chemin aussi long?

2
Pratz

Vous pouvez résumer les fonctionnalités spécifiques de la vue dans des services à l'aide d'une interface générique. Dans la couche de vue, vous pouvez fournir des instances concrètes de ces services et créer des modèles de vue à l'aide du conteneur IoC et de la technique d'injection de dépendances.

Dans votre cas, vous pouvez créer une interface IWindowManager ou quelque chose de similaire qui a la méthode requise. Cela peut être implémenté dans votre couche de vue. J'ai récemment écrit un petit article de blog montrant comment faire abstraction du comportement de dialogue hors du modèle de vue. Une approche similaire peut être utilisée pour tout service lié à l'interface utilisateur comme la navigation, les boîtes de message, etc.

Ce lien pourrait vous être utile http://nileshgule.blogspot.com/2011/05/silverlight-use-dialogservice-to.html

De nombreuses personnes utilisent également l'approche de déclenchement d'événements à partir de modèles de vue qui sont abonnés au fichier view.cs et à partir de là, la MessageBox ou toute autre action liée à l'interface utilisateur est effectuée. Personnellement, j'aime l'approche d'injection de services, car vous pouvez alors fournir plusieurs implémentations du même service. Un exemple simple serait la façon dont la navigation est gérée dans les applications Silverlight et Windows Phone 7. Vous pouvez utiliser le même modèle de vue mais injecter différentes implémentations du service de navigation en fonction du type d'application.

2
Nilesh Gule

Je trouve que la meilleure façon d'aborder cela, c'est d'ouvrir et de fermer la fenêtre du ViewModel. Comme le suggère this link,

  1. Créer une classe DialogCloser
 public static class DialogCloser 
 {
 public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached ("DialogResult", typeof (bool?), typeof (DialogCloser), nouveau PropertyMetadata (DialogResult) ); 
 
 privé statique vide DialogResultChanged (DependencyObject d, DependencyPropertyChangedEventArgs e) 
 {
 var window = d as Window; 
 if (window! = null) window.Close (); 
} 
 
 public static void SetDialogResult (Window target, bool? value) 
 {
 target. SetValue (DialogResultProperty, valeur); 
} 
} 
  1. Créez un ViewModel de base héritant de GalaSoft.MvvmLight.ViewModelBase avec là des membres supplémentaires. Une fois cela fait, utilisez ce viewmodel comme base pour d'autres viewmodels.
 bool? _closeWindowFlag; 
 bool public? CloseWindowFlag 
 {
 Get {return _closeWindowFlag; } 
 définissez 
 {
 _closeWindowFlag = valeur; 
 RaisePropertyChanged ("CloseWindowFlag"); 
} 
} 
 
 public virtual void CloseWindow (bool? result = true) 
 {
 Application.Current.Dispatcher.BeginInvoke (DispatcherPriority.Background, 
 new Action (() => 
 {
 CloseWindowFlag = CloseWindowFlag == null? True:! CloseWindowFlag; 
})); 
}
  1. Dans la vue, liez le DialogCloser.DialogResult propriété de dépendance avec la propriété CloseWindowFlag dans le modèle de vue de base.

Ensuite, vous pouvez ouvrir/fermer/masquer la fenêtre du modèle d'affichage.

0
Touhid Alam