我在wpf中编写应用程序并使用mvvm模式。 我尝试使用ContentControl和DataTemplate实现单页面应用程序。 在我的应用程序中,我想根据子视图模型切换视图,如下所示: 我有一个主窗口,其内容控件的内容绑定到MainViewModel中的属性:
public BaseViewModel CurrentViewModel { get; set; }
在我写的consturctor中:
CurrentViewModel = new LoginViewModel();
在LoginViewModel中的我有一个获取名称和密码的函数,并检查细节是否正确。 如果没问题,我想将MainViewModel中的CurrentViewModel设置为NavigationViewModel。
但是当我查找示例时,我发现只能在主视图模型中直接切换viewmodel。 我该怎么办?
答案 0 :(得分:4)
如果我正确理解了您的问题,那么您是在询问登录完成后如何从service did not shut down properly after receiving a preshutdown control
内更改CurrentViewModel
?
你不应该这样做。 LoginViewModel
应该担心登录,并且不应该知道它的使用位置或应用程序的任何其他部分。
LoginViewModel
是拥有子VM并且编排应用程序流的人,因此MainViewModel
应该进行切换。
由于您希望在登录完成后切换视图,所以您需要MainViewModel
告诉您登录已完成确定。这样做的两个显而易见的方法是:
LoginViewModel
公开了LoginViewModel
订阅的LoginComplete
个事件,或MainViewModel
向MainViewModel
构造函数提供LoginComplete
Action
,LoginViewModel
在登录完成后调用。
LoginViewModel
答案 1 :(得分:2)
使用MvvmLight框架可以构建这样的怪物。
MainWindow.xaml
DataContext =“{Binding Source = {StaticResource Locator},Path = Main}”
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Content="BaseView" Height="25" Width="80" Command="{Binding SwitchToBaseCommand}"/>
<Button Grid.Row="1" Content="NavigationView" Height="25" Width="100" Command="{Binding SwitchToNavigationCommand}"/>
</Grid>
<ContentControl Grid.Column="1" Content="{Binding CurrentViewModel}"/>
</Grid>
BaseView.xaml
DataContext =“{Binding Source = {StaticResource Locator},Path = BaseViewModel}”
<Grid>
<Label Content="{Binding Message}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
NavigationView.xaml
DataContext =“{Binding Source = {StaticResource Locator},Path = NavigationViewModel}”
<Grid>
<Label Content="{Binding Message}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
的App.xaml
xmlns:Views =“clr-namespace:WpfApplication.Views”xmlns:ViewModels =“clr-namespace:WpfApplication.ViewModel”
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:WpfApplication233.ViewModel" />
<DataTemplate DataType="{x:Type ViewModels:BaseViewModel}">
<Views:BaseView/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:NavigationViewModel}">
<Views:NavigationView/>
</DataTemplate>
</ResourceDictionary>
</Application.Resources>
ViewModelLocator.cs
public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<BaseViewModel>();
SimpleIoc.Default.Register<NavigationViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public BaseViewModel BaseViewModel
{
get
{
return ServiceLocator.Current.GetInstance<BaseViewModel>();
}
}
public NavigationViewModel NavigationViewModel
{
get
{
return ServiceLocator.Current.GetInstance<NavigationViewModel>();
}
}
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}
MainViewModel.cs
public class MainViewModel : ViewModelBase
{
private ViewModelBase currentViewModel;
public ViewModelBase CurrentViewModel
{
get
{
return this.currentViewModel;
}
set
{
this.currentViewModel = value;
this.RaisePropertyChanged("CurrentViewModel");
}
}
public RelayCommand SwitchToBaseCommand
{
get
{
return new RelayCommand(() => SwitchToBase());
}
}
public RelayCommand SwitchToNavigationCommand
{
get
{
return new RelayCommand(() => SwitchToNavigation());
}
}
public void SwitchToBase()
{
CurrentViewModel = ServiceLocator.Current.GetInstance<BaseViewModel>();
}
public void SwitchToNavigation()
{
CurrentViewModel = ServiceLocator.Current.GetInstance<NavigationViewModel>();
}
}
BaseViewModel.cs
public class BaseViewModel :ViewModelBase
{
public string Message {get; set;}
public BaseViewModel()
{
Message = "Message from BaseViewModel View Model";
}
}
NavigationViewModel.cs
public class NavigationViewModel:ViewModelBase
{
public string Message { get; set; }
public NavigationViewModel()
{
Message = "Message from Navigation View Model";
}
}
答案 2 :(得分:0)
如果您想根据DataTemplates
动态切换Views
,则可以使用ViewModel
:
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModelA}">
<localControls:ViewAUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModelB}">
<localControls:ViewBUserControl/>
</DataTemplate>
<Window.Resources>
<ContentPresenter Content="{Binding CurrentView}"/>
</Window>
如果Window.DataContext
是ViewModelA
的实例,则会显示ViewA
,Window.DataContext
是ViewModelB
的实例,然后是ViewB
将会显示。
我见过并阅读过的最好的例子是Rachel Lim。 See the example.