2016-07-13 5 views
0

Ich versuche, MVVM zu lernen, aber es ist ein Alptraum, der versucht, zu verstehen, wie man zwischen Ansichten in einer Anwendung mit MVVM korrekt navigiert. Nach einiger Zeit Recherche und Versuch, verschiedene Techniken zu verstehen, bin ich auf einen Ansatz von Rachel Lim's blog gestoßen. Diese Technik verwendet ein ViewModel für die Anwendung selbst und verfolgt den Anwendungsstatus wie die aktuelle Seite. Ich denke, das wäre ein guter Ansatz für meine Bewerbung.So ändern Sie die Hauptfensteransicht von einem Popup-Fenster

Jetzt auf mein Problem zu bewegen ..

Was ich

Ich möchte eine Anwendung erreichen wollen, die eine eine Hauptansicht hat, die eine Loginview und ein Homeview als Datatemplates gespeichert werden und haben eine Inhaltssteuerung, die das LoginView als die Ansicht festlegt, die beim Start der Anwendung angezeigt wird. Die LoginView verfügt über eine Schaltfläche, die bei Betätigung ein weiteres Fenster mit einer Schaltfläche öffnet. Wenn die Schaltfläche im Popup-Fenster gedrückt wird, möchte ich die Ansicht im Hauptanwendungsfenster von LoginView auf HomeView ändern.

Was ich bisher haben

Ich habe die ApplicationView eingerichtet, die gut funktioniert.

<Window x:Class="WPF_Navigation_Practice.Views.ApplicationView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:ignore="http://www.galasoft.ch/ignore" 
     xmlns:vm="clr-namespace:WPF_Navigation_Practice.ViewModels" 
     xmlns:views="clr-namespace:WPF_Navigation_Practice.Views" 
     mc:Ignorable="d ignore" 
     DataContext="{StaticResource ApplicationViewModel}"> 

    <Window.Resources> 
     <DataTemplate DataType="{x:Type vm:LoginViewModel}"> 
      <views:LoginView /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type vm:HomeViewModel}"> 
      <views:HomeView /> 
     </DataTemplate> 
    </Window.Resources> 

    <Grid> 
     <ContentControl Content="{Binding CurrentPageViewModel}" /> 
    </Grid> 
</Window> 

Und haben das ApplicationViewModel wie folgt eingerichtet. Einstellen der aktuellen Seite auf das LoginViewModel.

using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Input; 
using GalaSoft.MvvmLight; 
using GalaSoft.MvvmLight.Command; 
using WPF_Navigation_Practice.Interfaces; 

namespace WPF_Navigation_Practice.ViewModels 
{ 
    /// <summary> 
    /// This class contains properties that a View can data bind to. 
    /// <para> 
    /// See http://www.galasoft.ch/mvvm 
    /// </para> 
    /// </summary> 
    public class ApplicationViewModel : ViewModelBase 
    { 
     #region Fields 

     private ICommand _changePageCommand; 

     private IPageViewModel _currentPageViewModel; 
     private List<IPageViewModel> _pageViewModels; 

     #endregion 

     public ApplicationViewModel() 
     { 
      // Add available pages 
      PageViewModels.Add(new LoginViewModel()); 
      PageViewModels.Add(new HomeViewModel()); 
      PageViewModels.Add(new CodeViewModel()); 


      // Set starting page 
      CurrentPageViewModel = PageViewModels[0]; 
     } 

     #region Properties/Commands 

     public ICommand ChangePageCommand 
     { 
      get 
      { 
       if (_changePageCommand == null) 
       { 
        _changePageCommand = new RelayCommand<object>(
         p => ChangeViewModel((IPageViewModel)p), 
         p => p is IPageViewModel); 
       } 

       return _changePageCommand; 
      } 
     } 

     public List<IPageViewModel> PageViewModels 
     { 
      get 
      { 
       if (_pageViewModels == null) 
        _pageViewModels = new List<IPageViewModel>(); 

       return _pageViewModels; 
      } 
     } 

     public IPageViewModel CurrentPageViewModel 
     { 
      get 
      { 
       return _currentPageViewModel; 
      } 
      set 
      { 
       if (_currentPageViewModel != value) 
       { 
        _currentPageViewModel = value; 
        RaisePropertyChanged("CurrentPageViewModel"); 
       } 
      } 
     } 


     #endregion 

     #region Methods 

     private void ChangeViewModel(IPageViewModel viewModel) 
     { 
      if (!PageViewModels.Contains(viewModel)) 
       PageViewModels.Add(viewModel); 

      CurrentPageViewModel = PageViewModels 
       .FirstOrDefault(vm => vm == viewModel); 
     } 

     #endregion 
    } 
} 

Wenn ich die Anwendung ausführen wird es mein Hauptfenster angezeigt werden, die die Loginview anzeigt, die ein Benutzersteuerelement ist und als currentPageViewModel mit Content gesetzt.

Wenn der Button im LoginView UserControl angeklickt wird, öffnet sich ein weiteres Fenster. Wie auf dem Bild unten. Hier

enter image description here

ist das XAML für das Fenster.

<Window x:Class="WPF_Navigation_Practice.Views.CodeView" 
    x:Name="CodeWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:ignore="http://www.galasoft.ch/ignore" 
    xmlns:z="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:viewModels="clr-namespace:WPF_Navigation_Practice.ViewModels" 
    mc:Ignorable="d ignore" 
    d:DesignWidth="623.224" d:DesignHeight="381.269" 
    DataContext="{Binding CodeViewModel, Source={StaticResource ApplicationViewModel}}"> 

<Grid> 
    <Button Content="Ok" 
      HorizontalAlignment="Left" 
      Margin="235,166,0,0" 
      VerticalAlignment="Top" 
      Width="138" 
      FontSize="20" 
      Height="67"/> 
    <Label Content="Second Window" HorizontalAlignment="Left" Margin="166,56,0,0" VerticalAlignment="Top" FontSize="36"/> 
</Grid> 

Mein Problem

Was ich will, ist zu erreichen, wenn die ‚OK‘ Taste im secondView Fenster geklickt wird, möchte ich von der die currentPageViewModel im ApplicationView Fenster ändern LoginView, um den HomeView anzuzeigen, bin aber verwirrt darüber, wie ich das erreichen würde. Jede Hilfe würde sehr geschätzt werden.

+1

Ich könnte der Loginansicht ein LoggedIn-Ereignis geben, das die Hauptansicht abonniert. Wenn dies ausgelöst wird, kann die Hauptansicht dem Anwendungsansichtsmodell mitteilen, dass sich jemand angemeldet hat, indem Sie eine Eigenschaft (it == app vm) festlegen und eine Methode aufrufen, was auch immer. Es sollte ein Viewmodel geben, um alle zu regeln, wer Entscheidungen darüber trifft, was zu tun ist, wenn sich der Benutzer anmeldet - ich gehe davon aus, dass dies das Anwendungsansichtsmodell ist. –

+1

MVVM ist ehrlich gesagt nicht gut für mehrere Fenster (einschließlich Dialoge usw.) ausgelegt. Verwenden Sie nach Möglichkeit ein einzelnes Fenster und schließen Sie verschiedene Benutzersteuerelemente an (jeweils eine Ansicht). – Jai

+0

Probleme beim Übergeben des Hauptfensters als Parameter an den Konstruktor des Popup-Fensters und Festlegen der Ansicht von dort aus mit der Eigenschaft des Hauptfensters. – AnjumSKhan

Antwort

0

Ich sehe, dass Sie bereits MVVMLight verwenden. Es gibt eine Messenger-Klasse, die dir hier helfen kann. Melden Sie sich beim Messenger in Ihrem ApplicationViewModel-Konstruktor an, und verwenden Sie im Code, der die Schaltfläche behandelt, den Mausklick im CodeViewModel, um eine Nachricht zu senden. In der Aktion, die Sie zur Registrierung weitergeben, ändern Sie die Ansichtsmodelle wie gewünscht.

Siehe http://www.mvvmlight.net/help/WP8/html/9fb9c53a-943a-11d7-9517-c550440c3664.htm und Use MVVM Light's Messenger to Pass Values Between View Model

Ich habe keine MVVMLight Sie einen Beispielcode zu schreiben.Ich habe eine ViewModelMessenger von Grund auf neu geschrieben und mir ist so:

public static void Register(string actionName, object registerer, Action<object, object> action) 
{ 
    var actionKey = new Tuple<string, object>(actionName, registerer); 
    if (!RegisteredActions.ContainsKey(actionKey)) 
    { 
     RegisteredActions.Add(actionKey, action); 
    } 
    else 
    { 
     RegisteredActions[actionKey] = action; 
    } 
} 

gebraucht wie:

VMMessenger.Register("ChangeViewModel",this,ChangeViewModelAction) 

und

public static void SendMessage(string messageName, object message, object sender) 
{ 
    var actionKeys = RegisteredActions.Keys.ToList(); 
    foreach (Tuple<string, object> actionKey in actionKeys) 
    { 
     if (actionKey.Item1 == messageName) 
     { 
      Action<object, object> action; 
      if (RegisteredActions.TryGetValue(actionKey, out action)) 
      { 
       action?.Invoke(message, sender); 
      } 
     } 
    } 
} 

gebraucht wie:

VMMessenger.SendMessage("ChangeViewModel","HomeViewModel",this); 

und in ChangeViewModelAction können Sie Suchen Sie nach ViewModel-Namen und ändern Sie das CurrentPageViewModel in eins mit einem übereinstimmenden Namen.