简体   繁体   中英

Change the User Control of a Window dynamically in WPF (MVVM)

I'm new with WPF and I was just doing a simple menu using MVVM with bindings and commands but I think I'm doing something wrong. I just want to change all the Window Content importing a new UserControl I defined, everytime I press a Menu Button. That means I want to disappear the menu and show a new content (the UserControls I mentioned before).

Well I have the main window (ControlPanel):

<Window x:Class="OfficeMenu.Views.Menu.ControlPanel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Control Panel" Height="800" Width="800">
<Grid>

    <ContentControl Content="{Binding contentWindow}"/>

</Grid>
</Window>

This one of the UserControls that provides a Menu of buttons to the Main Window when I run the project:

<UserControl x:Class="OfficeMenu.Views.ButtonsMenu"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
    <!-- One style for each *type* of control on the window -->
    <Style TargetType="Button">
        <Setter Property="Margin" Value="5"/>
    </Style>

</UserControl.Resources>
 <Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <Button Command="{Binding OpenUsersCommand}">BUTTON 1</Button>
    <Button Grid.Column="1">BUTTON 2</Button>
    <Button Grid.Column="1" Grid.Row="2" >BUTTON 3</Button>
    <Button Grid.Row="1">BUTTON 4</Button>
</Grid>
</UserControl>

This is the ViewModel Im using for it:

class MenuViewModel : ViewModelBase
{
    RandomModel _model;  <!-- It does nothing important -->
    private UserControl _content;

    public ICommand OpenUsersCommand { get; private set; }

    public UserControl Content
    {
        get { return _content; }
        set {
            _content = value;
            NotifyPropertyChanged("contentWindow");
        }
    }

    public MenuViewModel(RandomModel model )
    {
        this._model= model;
        OpenUsersCommand = new RelayCommand(OpenUsers,null);
    }

    private void OpenUsers()
    {
        Content = new UsersPanel();  //This is the UserControl we need to load dinamically
    }
}

In App.xaml.cs we load the main window:

public partial class App : Application
{

    private void OnStartup(object sender, StartupEventArgs e)
    {
        ControlPanel view = new ControlPanel();
        view.ShowDialog();
    }
}

Now, the controlPanel.xaml.cs:

public ControlPanel()
    {
        InitializeComponent();

        ModelRandom model = new ModelRandom(); <!-- It does nothing yet -->
        MenuViewModel viewmodel = new MenuViewModel(model);
        Content = new BottonsMenu();  <!-- We load a default UserControl when we run the program -->
        this.DataContext = viewmodel;
    }
}

Thank you very much.

I think the problem is that you are trying to change the Content property of ContentControl, not the property of your ViewModel. You have connected your ViewModel to the host ControlPanel, but also you need the separate view models for user controls that will be hosted there. I've added class for user control view model and changed host's view model property name for the clarity sake. Correct your code as follows.

//host view model
class MainModel : ViewModelBase
{
    private UserControl _content;

    public MainModel() { }

    internal void SetNewContent(UserControl _content)
    {
        ContentWindow = _content;
    }

    public UserControl ContentWindow
    {
        get { return _content; }
        set
        {
            _content = value;
            OnPropertyChanged("ContentWindow");
        }
    }
}

//user contol's view model
class MenuViewModel : ViewModelBase
{
    MainModel _mainModel;
    RandomModel _model; // <!-- It does nothing important -->

    public ICommand OpenUsersCommand { get; private set; }


    public MenuViewModel(MainModel mainModel, RandomModel model )
    {
        this._mainModel = mainModel;
        this._model = model;
        OpenUsersCommand = new RelayCommand(OpenUsers, CanOpenUsers);
    }

    private void OpenUsers(object _param)
    {
        UsersPanelViewModel upmodel = new UsersPanelViewModel(_mainModel, _model);
        UsersPanel up = new UsersPanel();
        up.DataContext = upmodel;
        _mainModel.SetNewContent(up);
    }

    private bool CanOpenUsers(object _param)
    {
        return true;
    }
}

    //main window function
    public ControlPanel()
    {
        InitializeComponent();

        //create main view model for host
        MainModel mainModel = new MainModel();

        RandomModel model = new RandomModel(); //<!-- It does nothing yet -->

        //create view model for user controls
        MenuViewModel viewmodel = new MenuViewModel(mainModel, model);
        ButtonsMenu bm = new ButtonsMenu(); // <!-- We load a default UserControl when we run the program -->
        bm.DataContext = viewmodel;

        //set host's property in our user control
        mainModel.ContentWindow = bm;
        this.DataContext = mainModel;
    }

main window XAML

<Window x:Class="WpfApplication1.ControlPanel"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ContentControl Content="{Binding ContentWindow}"/>
    </Grid>
</Window>

Hope it's quite understandable.

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