简体   繁体   中英

How to switch Usercontrol(s) in MainWindow.xaml using ICommand Mvvm pattern?

Please -- I do not want to employ/use outside frameworks like MVVMlite (etc) at this time. I need to do this manually so that I can see the full process.

I have seen various articulations of the question which I am asking, but I have not seen any versions of my question which bind a command to a usercontrol to change out a usercontrol in MainWindow.xaml. In the following code I demonstrate the effort/attempt I have tried to make a Wpf/Mvvm application for switching out usercontrols in MainWindow.xaml. The question/request is what steps I need to take to follow through with this project?

In my project I have the standard Models/ViewModels/Views folders, 3 usercontrol views that I want to switch around in MainWindow.xaml (MainWindow.xaml resides in the root folder of the project) -- BlueView, OrangeView, RedView. The only content these views/usercontrols have is that Blueview has a blue background grid, OrangeView has an orange background grid, RedView has a red background grid. I have 3 buttons in a stackpanel to the left in MainWindow.xaml and a content control where I want to load/switch the usercontrols in the right of MainWindow.xaml. I have 3 corresponding ViewModels, BlueViewModel, OrangeViewModel, RedViewModel. I also have a MainViewModel for tying up these 3 viewModels, and RelayCommand.cs in the Models folder. But I don't know where to go from there.

Here is my code -- note: I'm only going to add MainWindow.xaml, RelayCommand.cs, MainViewModel and BlueViewModle/BlueView since the other views/ViewModels are the same except for the background grid color . What do I need to do/add so that I can load/switch the usercontrols in the content control in MainWindow.xaml? I can't show a usercontrol - so I don't have a show/display method in MainViewModel.cs How do I load the usercontrols? Do I need methods in the ViewModels?

--MainWindow.xaml -- resides in the project root folder

<Window x:Class="ViewChangerFromICommand.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ViewChangerFromICommand"
        xmlns:viewmodels="clr-namespace:ViewChangerFromICommand.ViewModels"
        xmlns:views="clr-namespace:ViewChangerFromICommand.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <DataTemplate x:Name="redViewTemplate" DataType="{x:Type viewmodels:RedViewModel}">
            <views:RedView DataContext="{Binding}"/>
        </DataTemplate>
        <DataTemplate x:Name="BlueViewTemplate" DataType="{x:Type viewmodels:BlueViewModel}">
            <views:BlueView DataContext="{Binding}"/>
        </DataTemplate>
        <DataTemplate x:Name="OrangeViewTemplate" DataType="{x:Type viewmodels:OrangeViewModel}">
            <views:OrangeView DataContext="{Binding}"/>
        </DataTemplate>
    </Window.Resources>

        <Window.DataContext>
            <viewmodels:MainViewModel />
        </Window.DataContext>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <DockPanel Background="Gray" Grid.Row="0" Grid.Column="0" Grid.RowSpan="5">
            <StackPanel>
                <Button Content="Red View"/>
                <Button Content="Blue View"/>
                <Button Content="Orange View"/>
            </StackPanel>
        </DockPanel>
        <ContentControl Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="4" Grid.RowSpan="5" Content="{Binding}"/>
    </Grid>
</Window>

--RelayCommand.cs -- resides in Models folder

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace ViewChangerFromICommand.Models
{
    public class RelayCommand : ICommand
    {
        readonly Action _execute;
        readonly Func<bool> _canExecute;

        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new NullReferenceException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        public RelayCommand(Action execute) : this(execute, null)
        {

        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

        public void Execute(object parameter)
        {
            _execute.Invoke();
        }
    }
}

--MainViewModel.cs -- resides in ViewModels folder

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ViewChangerFromICommand.Models;
using ViewChangerFromICommand.Views;

namespace ViewChangerFromICommand.ViewModels
{
    public class MainViewModel
    {
        public BlueViewModel blueVM { get; set; }

        public OrangeViewModel orangeVM { get; set; }

        public RedViewModel redVM { get; set; }

        public MainViewModel()
        {
            blueVM = new BlueViewModel();
            orangeVM = new OrangeViewModel();
            redVM = new RedViewModel();

        }        
    }
}

--BlueViewModel.cs -- resides in ViewModels folder

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ViewChangerFromICommand.Models;
using ViewChangerFromICommand.Views;

namespace ViewChangerFromICommand.ViewModels
{
    public class BlueViewModel
    {
        public BlueViewModel()
        {
        }        
    }
}

--BlueView.xaml -- resides in Views folder

<UserControlx:Class="ViewChangerFromICommand.Views.BlueView"
    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:ViewChangerFromICommand.Views"
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300">

    <Grid Background="Blue">

    </Grid>
</UserControl>

Consider the following approach.

In MainViewModel create 'Selected' property, which will reflect which ViewModel/View you want to see. Setup RelayCommands to assign desired view model to the 'Selected' property.

In view (Window), bind Content of the ContentControl to 'Selected' and setup command bindings.

MainViewModel also needs to implement INotifyPropertyChanged for change to 'Selected' property to be recognized by the view.

View model:

public class MainViewModel:INotifyPropertyChanged  //Look into using Prism and BindableBase instead of INotifyPropertyChanged
{
    private BlueViewModel blueVM;

    private OrangeViewModel orangeVM;

    private RedViewModel redVM;

    public event PropertyChangedEventHandler PropertyChanged=delegate { };

    object selectedView;
    public object SelectedView
    {
        get { return selectedView; }
        private set
        {
            selectedView = value;
            RaisePropertyChanged("SelectedView");
        }
    }

    public ICommand SelectBlueViewCommand { get; private set; }
    public ICommand SelectOrangeViewCommand { get; private set; }
    public ICommand SelectRedViewCommand { get; private set; }

    public MainViewModel()
    {
        blueVM = new BlueViewModel();
        orangeVM = new OrangeViewModel();
        redVM = new RedViewModel();
        SelectBlueViewCommand = new RelayCommand(() => SelectedView = blueVM);
        SelectOrangeViewCommand = new RelayCommand(() => SelectedView = orangeVM);
        SelectRedViewCommand = new RelayCommand(() => SelectedView = redVM);
    }

    void RaisePropertyChanged(string property)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
}

View/Window

<Window x:Class="WpfApp1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:local="clr-namespace:ViewChangerFromICommand"
    xmlns:viewmodels="clr-namespace:ViewChangerFromICommand.ViewModels"
    xmlns:views="clr-namespace:ViewChangerFromICommand.Views"  

           Title="Window1" Height="650" Width="750">
<Window.Resources>
    <DataTemplate x:Name="redViewTemplate" DataType="{x:Type viewmodels:RedViewModel}">
        <views:RedView DataContext="{Binding}"/>
    </DataTemplate>
    <DataTemplate x:Name="BlueViewTemplate" DataType="{x:Type viewmodels:BlueViewModel}">
        <views:BlueView DataContext="{Binding}"/>
    </DataTemplate>
    <DataTemplate x:Name="OrangeViewTemplate" DataType="{x:Type viewmodels:OrangeViewModel}">
        <views:OrangeView DataContext="{Binding}"/>
    </DataTemplate>
</Window.Resources>

<Window.DataContext>
    <viewmodels:MainViewModel />
</Window.DataContext>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <DockPanel Background="Gray" Grid.Row="0" Grid.Column="0" Grid.RowSpan="5">
        <StackPanel>
            <Button Content="Red View" Command="{Binding SelectBlueViewCommand}"/>
            <Button Content="Blue View" Command="{Binding SelectOrangeViewCommand}"/>
            <Button Content="Orange View" Command="{Binding SelectRedViewCommand}"/>
        </StackPanel>
    </DockPanel>
    <ContentControl Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="4" Grid.RowSpan="5" 
                    Content="{Binding SelectedView}"/>
</Grid>

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