根据子视图模型更改wpf单页应用程序中的视图
本文关键字:视图 应用程序 单页 wpf 模型 | 更新日期: 2023-09-27 18:27:03
我用wpf和mvvm模式编写了一个应用程序。我尝试使用ContentControl和DataTemplate实现一个单页应用程序。在我的应用程序中,我想根据子视图模型切换视图,如下所示:我有一个带有内容控件的主窗口,它的内容绑定到MainViewModel:中的属性
public BaseViewModel CurrentViewModel { get; set; }
在我写的consturator中:
CurrentViewModel = new LoginViewModel();
在LoginViewModel中,我有一个函数可以获取名称和密码,并检查详细信息是否正确。如果可以的话,我想将MainViewModel中的CurrentViewModel设置为NavigationViewModel。
但当我查找示例时,我发现只直接在主视图模型中切换视图模型。我该怎么做???
如果我正确理解您的问题,您会问登录完成后如何从LoginViewModel
中更改CurrentViewModel
?
你不应该这么做。LoginViewModel
应该担心登录,不应该知道它在哪里使用,也不应该知道应用程序的任何其他部分。
MainViewModel
是拥有子VM并协调应用程序流的人,因此应该由MainViewModel
进行切换。
由于您想在登录完成OK后切换视图,因此需要LoginViewModel
来告诉您登录已完成OK
LoginViewModel
公开MainViewModel
订阅的LoginComplete
事件,或者MainViewModel
向LoginViewModel
构造函数提供LoginComplete
Action
,LoginViewModel
在登录完成时调用该构造函数
public class MainViewModel
{
//INPC omitted for brevity
public object CurrentViewModel { get; private set; }
public void MainViewModel()
{
this.CurrentViewModel = new LoginViewModel(LoginComplete);
}
private void LoginComplete()
{
this.CurrentViewModel = new NavigationViewModel();
}
}
public class LoginViewModel
{
private Action loginCompleteAction;
public void LoginViewModel(Action loginCompleteAction)
{
this.loginCompleteAction = loginCompleteAction;
}
private void UserHasLoggedIn()
{
this.loginCompleteAction();
}
}
使用MvvmLight框架可以构建这样的怪物。
主窗口.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名称空间:WpfApplication.Views"xmlns:ViewModels="clr-namespace:WpfApplication.WiewModel"
<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";
}
}
如果您想根据ViewModel
:动态切换Views
,则使用DataTemplates
是合适的
<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做的。请参见示例。