I fully understand how to implement view switch in WPF using commands and data templates when the view is managed by a top level VM, like a MainWindowVM. What I am struggling with is where I have a MainWindow which has a ContentControl bound to a CurrentView property and I want to update the view from views inside the windows content control, and user controls insid ethe views. On loadup I set the CurrentView to an instance of my MainMenuVm, giving me two buttons. What I want is to update the view on a button command from this UserControl, but I can't figure out how to update the CurrentView property as it resides in MainWindowVm, and the UserControl's data context is to MainMenuVm, as set in the DataTemplate.
I have tried hooking up events, and getting the data context of the MainWindow but I can't get it to work. I have a relayCommand class that I can use to instantiate ICommand properties, I just need help with passing the commands from the userControl to the MainWindow.
All help appreciated, I can post code if needed.
I have tried to provide some examples of my code to clarify:
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();
}
}
MainWindow 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>
MainMenuuserontrol
<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>
A simple way to do it would be for the MainWindowVm to give a delegate to its nested viewmodels:
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;
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.