简体   繁体   中英

How do I switch views in child user controls in WPF?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM