2016-07-13 4 views
0

Я пытаюсь изучить MVVM, но нахожу это кошмаром, пытаясь понять, как правильно перемещаться между представлениями в приложении с помощью MVVM. Через некоторое время, исследуя и пытаясь понять разные методы, я столкнулся с подходом от Rachel Lim's blog. Этот метод использует ViewModel для самого приложения и отслеживает состояние приложения, такое как текущая страница. Я считаю, что это будет хороший подход для моего приложения.Как изменить вид главного окна из всплывающего окна

Теперь перейти на мою проблему ..

То, что я хочу достичь

Я хочу, чтобы приложение, которое имеет один главный вид приложения, который будет хранить LoginView и HomeView как DataTemplates и иметь контроль содержимого, который устанавливает LoginView как представление, отображаемое при запуске приложения. В LoginView будет кнопка, которая при нажатии откроет другое окно с кнопкой. Когда кнопка во всплывающем окне нажата, я хочу изменить вид в главном окне приложения из LoginView в HomeView.

То, что я до сих пор

У меня есть набор вверх ApplicationView, который работает отлично.

<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> 

И установили ApplicationViewModel следующим образом. Установка текущей страницы в 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 
    } 
} 

При запуске приложения оно будет отображаться мое главное окно приложения, которое отображает LoginView, который является UserControl и устанавливается как currentPageViewModel с ContentPresenter.

Когда нажата кнопка в UserView UserControl, она откроет другое окно. Как показано на рисунке ниже.

enter image description here

Вот XAML для этого окна.

<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> 

Моя проблема

То, что я хочу достичь, когда кнопка «Ok» в окне secondView нажата, я хочу, чтобы изменить currentPageViewModel в ApplicationView окна из LoginView, чтобы отобразить HomeView, но я смущен тем, как я буду добиваться этого. Любая помощь будет принята с благодарностью.

+1

Я могу дать loginview событие LoggedIn, на которое подписывается основной вид. Затем, когда это поднято, основное представление может сообщить о том, что кто-то вошел в систему, установив для него свойство (это == приложение vm), вызывая метод, что угодно. Должна быть One Viewmodel для правильного использования всех, кто принимает решение о том, что делать, когда пользователь входит в систему. Я предполагаю, что это модель представления приложения. –

+1

MVVM честно не хорошо разработан для создания нескольких окон (включая диалоги и т. Д.). Если возможно, используйте одно окно и подключите различные UserControls (каждый из них считается View). – Jai

+0

Любые проблемы с передачей главного окна в качестве параметра конструктору всплывающего окна и установка вида из него с использованием свойства главного окна. – AnjumSKhan

ответ

0

Я вижу, что вы уже используете MVVMLight. Существует класс Messenger, который может помочь вам здесь. Зарегистрируйтесь к мессенджеру в вашем ApplicationViewModel Constructor, а в обработчике кода нажмите кнопку в CodeViewModel, чтобы отправить сообщение. В действии, которое вы переходите на регистрацию, меняются режимы просмотра, как вы пожелаете.

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

Я не MVVMLight писать вам пример кода.Я написал ViewModelMessenger с нуля, и у меня это так:

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; 
    } 
} 

Используется как:

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

и

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); 
      } 
     } 
    } 
} 

Используется как:

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

и в ChangeViewModelAction вы можете проверьте имена ViewModel и измените CurrentPageViewModel на одно с соответствующим именем.

Смежные вопросы