【发布时间】:2016-07-13 01:48:34
【问题描述】:
我正在尝试学习 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,并设置为带有 ContentPresenter 的 currentPageViewModel。
当点击 LoginView UserControl 中的按钮时,它将打开另一个窗口。根据下图。
这是该窗口的 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>
我的问题
我想要实现的是,当单击 secondView 窗口中的“确定”按钮时,我想将 ApplicationView 窗口中的 currentPageViewModel 从 LoginView 更改为显示 HomeView,但我对如何实现这一点感到困惑.任何帮助将不胜感激。
【问题讨论】:
-
我可能会给登录视图一个主视图订阅的 LoggedIn 事件。然后,当它出现时,主视图可以告诉应用程序视图模型有人登录,方法是在其上设置一个属性(it == app vm),调用一个方法,等等。应该有一个视图模型来统治他们所有人,谁来决定用户登录时要做什么——我假设那是应用程序视图模型。
-
MVVM 确实不适合拥有多个窗口(包括对话框等)。如果可能,使用单个窗口,并插入不同的用户控件(每个都被视为一个视图)。
-
将主窗口作为参数传递给弹出窗口的构造函数并使用主窗口的属性从那里设置视图的任何问题。