如何在 WPF 的子用户控件中切换视图?
How do I switch views in child user controls in WPF?
我完全理解当视图由顶级 VM(如 MainWindowVM)管理时,如何使用命令和数据模板在 WPF 中实现视图切换。我正在努力解决的问题是我有一个 MainWindow,它有一个 ContentControl 绑定到一个 CurrentView 属性,我想从 windows 内容控件和用户控件 inside 视图中的视图更新视图。在加载时,我将 CurrentView 设置为我的 MainMenuVm 的一个实例,给我两个按钮。我想要的是从这个 UserControl 更新按钮命令的视图,但我不知道如何更新 CurrentView 属性,因为它驻留在 MainWindowVm 中,而 UserControl 的数据上下文是 MainMenuVm,如设置的在数据模板中。
我已经尝试连接事件,并获取 MainWindow 的数据上下文,但我无法让它工作。我有一个可用于实例化 ICommand 属性的 relayCommand class,我只需要帮助将命令从 userControl 传递到 MainWindow。
感谢所有帮助,如果需要,我可以 post 编写代码。
我已尝试提供一些我的代码示例来阐明:
ViewModelBase
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainWindowVm
public class MainWindowVm : ViewModelBase
{
private ViewModelBase _currentView;
public ViewModelBase CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
NotifyPropertyChanged();
}
}
public MainWindowVm()
{
CurrentView = new MainMenuVm();
}
}
主窗口xaml
<Window.DataContext>
<vm:MainWindowVm/>
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type vm:MainMenuVm}">
<uc:MainMenuUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:NewJobVm}">
<uc:NewJobUserControl/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<ContentControl Style="{DynamicResource PanelInnerStyle}"
Grid.Row="1"
Grid.Column="1"
Content="{Binding CurrentView}"
HorizontalContentAlignment="Center"/>
</Grid>
</Window>
主菜单用户控制
<UserControl x:Class="Invoice.UserControls.MainMenuUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Invoice.UserControls"
xmlns:vm="clr-namespace:Invoice.ViewModels"
mc:Ignorable="d"
HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<Button Width="120"
Height="120"
Margin="5"
ToolTip="Add New Job">
<Image Source="/Resources/Add_Green.png"
Height="32"
Width="32"/>
</Button>
<Button Width="120"
Height="120"
Margin="5"
ToolTip="Load Jobs">
<Image Source="/Resources/Folder.png"
Height="32"
Width="32"/>
</Button>
</StackPanel>
</UserControl>
一种简单的方法是让 MainWindowVm 为其嵌套的视图模型提供委托:
public enum MenuCommands
{
NEXT_PAGE = 0,
PREVIOUS_PAGE = 1
}
public class MainMenuVm : ViewModelBase
{
public MainMenuVm ( Action<MenuCommands> menuCommand )
{
_menuCommands = menuCommand;
}
private Action<MenuCommands> _menuCommands;
/// <summary>
/// Command binded from MainMenuUserControl.xaml
/// </summary>
public ICommand NextPageCommand
{
get { return _nextPageCommand ?? ( _nextPageCommand = new DelegateCommand ( NextPage ) ); }
}
private ICommand _nextPageCommand;
private void NextPage ( )
{
// lets ask our MainWindowVM to switch the view
_menuCommands ( MenuCommands.NEXT_PAGE );
}
}
public class MainWindowVm : ViewModelBase
{
/* ... */
public MainWindowVm ( )
{
CurrentView = new MainMenuVm ( Navigate );
}
private void Navigate ( MenuCommands command )
{
// Implement your view switching logic here, like:
switch ( command )
{
case MenuCommands.NEXT_PAGE:
// CurrentView = new SomeOtherViewModel ( );
break;
case MenuCommands.PREVIOUS_PAGE:
// CurrentView = new SomeOtherViewModel ( );
break;
default:
break;
}
}
}
我完全理解当视图由顶级 VM(如 MainWindowVM)管理时,如何使用命令和数据模板在 WPF 中实现视图切换。我正在努力解决的问题是我有一个 MainWindow,它有一个 ContentControl 绑定到一个 CurrentView 属性,我想从 windows 内容控件和用户控件 inside 视图中的视图更新视图。在加载时,我将 CurrentView 设置为我的 MainMenuVm 的一个实例,给我两个按钮。我想要的是从这个 UserControl 更新按钮命令的视图,但我不知道如何更新 CurrentView 属性,因为它驻留在 MainWindowVm 中,而 UserControl 的数据上下文是 MainMenuVm,如设置的在数据模板中。
我已经尝试连接事件,并获取 MainWindow 的数据上下文,但我无法让它工作。我有一个可用于实例化 ICommand 属性的 relayCommand class,我只需要帮助将命令从 userControl 传递到 MainWindow。
感谢所有帮助,如果需要,我可以 post 编写代码。
我已尝试提供一些我的代码示例来阐明:
ViewModelBase
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainWindowVm
public class MainWindowVm : ViewModelBase
{
private ViewModelBase _currentView;
public ViewModelBase CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
NotifyPropertyChanged();
}
}
public MainWindowVm()
{
CurrentView = new MainMenuVm();
}
}
主窗口xaml
<Window.DataContext>
<vm:MainWindowVm/>
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type vm:MainMenuVm}">
<uc:MainMenuUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:NewJobVm}">
<uc:NewJobUserControl/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<ContentControl Style="{DynamicResource PanelInnerStyle}"
Grid.Row="1"
Grid.Column="1"
Content="{Binding CurrentView}"
HorizontalContentAlignment="Center"/>
</Grid>
</Window>
主菜单用户控制
<UserControl x:Class="Invoice.UserControls.MainMenuUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Invoice.UserControls"
xmlns:vm="clr-namespace:Invoice.ViewModels"
mc:Ignorable="d"
HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<Button Width="120"
Height="120"
Margin="5"
ToolTip="Add New Job">
<Image Source="/Resources/Add_Green.png"
Height="32"
Width="32"/>
</Button>
<Button Width="120"
Height="120"
Margin="5"
ToolTip="Load Jobs">
<Image Source="/Resources/Folder.png"
Height="32"
Width="32"/>
</Button>
</StackPanel>
</UserControl>
一种简单的方法是让 MainWindowVm 为其嵌套的视图模型提供委托:
public enum MenuCommands
{
NEXT_PAGE = 0,
PREVIOUS_PAGE = 1
}
public class MainMenuVm : ViewModelBase
{
public MainMenuVm ( Action<MenuCommands> menuCommand )
{
_menuCommands = menuCommand;
}
private Action<MenuCommands> _menuCommands;
/// <summary>
/// Command binded from MainMenuUserControl.xaml
/// </summary>
public ICommand NextPageCommand
{
get { return _nextPageCommand ?? ( _nextPageCommand = new DelegateCommand ( NextPage ) ); }
}
private ICommand _nextPageCommand;
private void NextPage ( )
{
// lets ask our MainWindowVM to switch the view
_menuCommands ( MenuCommands.NEXT_PAGE );
}
}
public class MainWindowVm : ViewModelBase
{
/* ... */
public MainWindowVm ( )
{
CurrentView = new MainMenuVm ( Navigate );
}
private void Navigate ( MenuCommands command )
{
// Implement your view switching logic here, like:
switch ( command )
{
case MenuCommands.NEXT_PAGE:
// CurrentView = new SomeOtherViewModel ( );
break;
case MenuCommands.PREVIOUS_PAGE:
// CurrentView = new SomeOtherViewModel ( );
break;
default:
break;
}
}
}