根据子视图模型更改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。

但当我查找示例时,我发现只直接在主视图模型中切换视图模型。我该怎么做???

根据子视图模型更改wpf单页应用程序中的视图

如果我正确理解您的问题,您会问登录完成后如何从LoginViewModel中更改CurrentViewModel

你不应该这么做。LoginViewModel应该担心登录,不应该知道它在哪里使用,也不应该知道应用程序的任何其他部分。

MainViewModel是拥有子VM并协调应用程序流的人,因此应该由MainViewModel进行切换。

由于您想在登录完成OK后切换视图,因此需要LoginViewModel来告诉您登录已完成OK

  1. LoginViewModel公开MainViewModel订阅的LoginComplete事件,或者
  2. MainViewModelLoginViewModel构造函数提供LoginComplete ActionLoginViewModel在登录完成时调用该构造函数

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.DataContextViewModelA的实例,则显示ViewA,而Window.DataContextViewModelB的实例,那么显示ViewB

我看过和读过的最好的例子是Rachel Lim做的。请参见示例。