简体   繁体   English

如何使用ICommand Mvvm模式在MainWindow.xaml中切换Usercontrol?

[英]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. 请-我现在不希望使用/使用MVVMlite等外部框架。 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. 我已经看到过我所提问题的各种表达方式,但是我还没有看到我的问题的任何版本,这些版本将命令绑定到用户控件以更改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. 在下面的代码中,我演示了我试图制作一个Wpf / Mvvm应用程序以切换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. 在我的项目中,我有标准的Models / ViewModels / Views文件夹,想要在MainWindow.xaml中切换的3个用户控件视图(MainWindow.xaml位于项目的根文件夹中)-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. 这些视图/用户控件的唯一内容是Blueview具有蓝色背景网格,OrangeView具有橙色背景网格,RedView具有红色背景网格。 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. 我在MainWindow.xaml左侧的堆栈面板中有3个按钮,在内容控件中要加载/切换MainWindow.xaml右侧的用户控件。 I have 3 corresponding ViewModels, BlueViewModel, OrangeViewModel, RedViewModel. 我有3个相应的ViewModels,BlueViewModel,OrangeViewModel,RedViewModel。 I also have a MainViewModel for tying up these 3 viewModels, and RelayCommand.cs in the Models folder. 我也有一个MainViewModel,用于绑定这3个viewModel和Models文件夹中的RelayCommand.cs。 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 . 这是我的代码-注意:我将只添加MainWindow.xaml,RelayCommand.cs,MainViewModel和BlueViewModle / BlueView,因为除背景网格颜色外,其他视图/ ViewModels相同。 What do I need to do/add so that I can load/switch the usercontrols in the content control in MainWindow.xaml? 我需要做什么/添加什么才能在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? 我无法显示用户控件-因此MainViewModel.cs中没有show / display方法。如何加载用户控件? Do I need methods in the ViewModels? 我是否需要ViewModels中的方法?

--MainWindow.xaml -- resides in the project root folder --MainWindow.xaml-驻留在项目根文件夹中

<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 --RelayCommand.cs-驻留在Models文件夹中

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 --MainViewModel.cs-驻留在ViewModels文件夹中

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 --BlueViewModel.cs-驻留在ViewModels文件夹中

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 --BlueView.xaml-位于Views文件夹中

<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. 在MainViewModel中,创建“ Selected”属性,该属性将反映您要查看的ViewModel / View。 Setup RelayCommands to assign desired view model to the 'Selected' property. 设置RelayCommands,以将所需的视图模型分配给“ Selected”属性。

In view (Window), bind Content of the ContentControl to 'Selected' and setup command bindings. 在视图(窗口)中,将ContentControl的Content绑定到“ Selected”并设置命令绑定。

MainViewModel also needs to implement INotifyPropertyChanged for change to 'Selected' property to be recognized by the view. MainViewModel还需要实现INotifyPropertyChanged,以将“ Selected”属性更改为视图可识别的属性。

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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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