C# 如何在WPF MVVM Catel应用程序中切换多个视图?

C# 如何在WPF MVVM Catel应用程序中切换多个视图?,c#,wpf,mvvm,catel,C#,Wpf,Mvvm,Catel,在MS VS 2015 Professional中,我使用Catel作为MVVM框架开发了C#WPF MVVM应用程序。我的问题是我不知道如何使用按钮在一个窗口中实现多个视图之间的切换。下面我简要介绍一下我的申请。主窗口有三个按钮 <catel:Window x:Class="FlowmeterConfigurator.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen

在MS VS 2015 Professional中,我使用Catel作为MVVM框架开发了C#WPF MVVM应用程序。我的问题是我不知道如何使用按钮在一个窗口中实现多个视图之间的切换。下面我简要介绍一下我的申请。主窗口有三个按钮

<catel:Window x:Class="FlowmeterConfigurator.Views.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:catel="http://catel.codeplex.com"
          ResizeMode="CanResize">

     <catel:StackGrid x:Name="LayoutRoot">
        <catel:StackGrid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto"/>
        </catel:StackGrid.RowDefinitions>

        <ToolBar>
            <Button Name="btnConnectDisconnect" Content="Connect/Disconnect"/>
            <Button Name="btnFieldSettings" Content="Field Settings"/>
            <Button Name="btnCalibration" Content="Flowmeter Calibration"/>
        </ToolBar>
    </catel:StackGrid>
</catel:Window>

应用程序主窗口有一个ViewModel。为了简单起见,我不在这里展示。除主窗口外,我的应用程序中还有三个视图:ConnectDisconnectView、CalibrationView和FieldSettingsView。为了简洁起见,我在这里只显示其中一个(FieldSettingsView),因为其他所有视图都是以相同的方式在catel:UserControl的基础上创建的

<catel:UserControl x:Class="FlowmeterConfigurator.Views.FieldSettingsView"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:catel="http://catel.codeplex.com">

    <catel:StackGrid>
        <catel:StackGrid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </catel:StackGrid.RowDefinitions>
        <catel:StackGrid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </catel:StackGrid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="Flowmeter Serial Number"/>
        <TextBox Name="SerialNumber" Grid.Row="0" Grid.Column="1"/>
    </catel:StackGrid>

</catel:UserControl>

每个视图都有一个模型。我在这里只展示其中一个模型,因为它们都是以相同的方式创建的

using Catel.Data;
namespace FlowmeterConfigurator.Models
{
    /// <summary>
    /// Field Settings Model.
    /// </summary>
    public class FieldSettingsModel : SavableModelBase<FieldSettingsModel>
    {
        /// <summary>
        /// Returns flowmeter serial number.
        /// </summary>
        public string SerialNumber
        {
            get { return GetValue<string>(SerialNumberProperty); }
            set { SetValue(SerialNumberProperty, value); }
        }

    /// <summary>
    /// Register SerialNumber property.
    /// </summary>
    public static readonly PropertyData SerialNumberProperty = RegisterProperty("SerialNumber", typeof(string), null);
    }
}
using Catel;
using Catel.Data;
using Catel.MVVM;
using FlowmeterConfigurator.Models;

namespace FlowmeterConfigurator.ViewModels
{
    /// <summary>
    /// Field settings ViewModel.
    /// </summary>
    public class FieldSettingsViewModel : ViewModelBase
    {
        /// <summary>
        /// Creates a FieldSettingsViewModel instance.
        /// </summary>
        /// <param name="fieldSettingsModel">Field settings Model.</param>
        public FieldSettingsViewModel(FieldSettingsModel fieldSettingsModel)
        {
            Argument.IsNotNull(() => fieldSettingsModel);
            FieldSettings = fieldSettingsModel;
        }

        /// <summary>
        /// Returns or sets Field Settings Model.
        /// </summary>
        [Model]
        public FieldSettingsModel FieldSettings
        {
            get { return GetValue<FieldSettingsModel>(FieldSettingsProperty); }
            set { SetValue(FieldSettingsProperty, value); }
        }

        /// <summary>
        /// Here I register FieldSettings property.
        /// </summary>
        public static readonly PropertyData FieldSettingsProperty = RegisterProperty("FieldSettings", typeof(FieldSettingsModel), null);

        /// <summary>
        /// Returns or sets flowmeter serial number.
        /// </summary>
        [ViewModelToModel("FieldSettings")]
        public string SerialNumber
        {
            get { return GetValue<string>(SerialNumberProperty); }
            set { SetValue(SerialNumberProperty, value); }
        }

        /// <summary>
        /// Here I register SerialNumber property.
        /// </summary>
        public static readonly PropertyData SerialNumberProperty = RegisterProperty("SerialNumber", typeof(string), null);
    }
}
使用类别数据;
命名空间FlowMeterConfiguration.Models
{
/// 
///字段设置模型。
/// 
公共类字段设置模型:SavableModelBase
{
/// 
///返回流量计序列号。
/// 
公共字符串序列号
{
获取{返回GetValue(SerialNumberProperty);}
set{SetValue(SerialNumberProperty,value);}
}
/// 
///寄存器序列号属性。
/// 
公共静态只读属性data SerialNumberProperty=RegisterProperty(“SerialNumber”,typeof(string),null);
}
}
每个视图都有一个ViewModel。我在这里只显示其中一个ViewModel,因为它们都是以相同的方式创建的

using Catel.Data;
namespace FlowmeterConfigurator.Models
{
    /// <summary>
    /// Field Settings Model.
    /// </summary>
    public class FieldSettingsModel : SavableModelBase<FieldSettingsModel>
    {
        /// <summary>
        /// Returns flowmeter serial number.
        /// </summary>
        public string SerialNumber
        {
            get { return GetValue<string>(SerialNumberProperty); }
            set { SetValue(SerialNumberProperty, value); }
        }

    /// <summary>
    /// Register SerialNumber property.
    /// </summary>
    public static readonly PropertyData SerialNumberProperty = RegisterProperty("SerialNumber", typeof(string), null);
    }
}
using Catel;
using Catel.Data;
using Catel.MVVM;
using FlowmeterConfigurator.Models;

namespace FlowmeterConfigurator.ViewModels
{
    /// <summary>
    /// Field settings ViewModel.
    /// </summary>
    public class FieldSettingsViewModel : ViewModelBase
    {
        /// <summary>
        /// Creates a FieldSettingsViewModel instance.
        /// </summary>
        /// <param name="fieldSettingsModel">Field settings Model.</param>
        public FieldSettingsViewModel(FieldSettingsModel fieldSettingsModel)
        {
            Argument.IsNotNull(() => fieldSettingsModel);
            FieldSettings = fieldSettingsModel;
        }

        /// <summary>
        /// Returns or sets Field Settings Model.
        /// </summary>
        [Model]
        public FieldSettingsModel FieldSettings
        {
            get { return GetValue<FieldSettingsModel>(FieldSettingsProperty); }
            set { SetValue(FieldSettingsProperty, value); }
        }

        /// <summary>
        /// Here I register FieldSettings property.
        /// </summary>
        public static readonly PropertyData FieldSettingsProperty = RegisterProperty("FieldSettings", typeof(FieldSettingsModel), null);

        /// <summary>
        /// Returns or sets flowmeter serial number.
        /// </summary>
        [ViewModelToModel("FieldSettings")]
        public string SerialNumber
        {
            get { return GetValue<string>(SerialNumberProperty); }
            set { SetValue(SerialNumberProperty, value); }
        }

        /// <summary>
        /// Here I register SerialNumber property.
        /// </summary>
        public static readonly PropertyData SerialNumberProperty = RegisterProperty("SerialNumber", typeof(string), null);
    }
}
使用Catel;
使用类别数据;
使用Catel.MVVM;
使用流量计配置器。模型;
命名空间FlowMeterConfiguration.ViewModels
{
/// 
///字段设置视图模型。
/// 
公共类字段设置视图模型:视图模型库
{
/// 
///创建FieldSettingsViewModel实例。
/// 
///字段设置模型。
公共字段设置查看模型(字段设置模型字段设置模型)
{
参数.IsNotNull(()=>fieldSettingsModel);
FieldSettings=fieldSettingsModel;
}
/// 
///返回或设置字段设置模型。
/// 
[型号]
公共字段设置模型字段设置
{
获取{返回GetValue(FieldSettingsProperty);}
设置{SetValue(FieldSettingsProperty,value);}
}
/// 
///我在这里注册FieldSettings属性。
/// 
公共静态只读属性Data FieldSettingsProperty=RegisterProperty(“FieldSettings”,类型为(FieldSettingsModel),null);
/// 
///返回或设置流量计序列号。
/// 
[视图模型模型(“字段设置”)]
公共字符串序列号
{
获取{返回GetValue(SerialNumberProperty);}
set{SetValue(SerialNumberProperty,value);}
}
/// 
///这里我注册SerialNumber属性。
/// 
公共静态只读属性data SerialNumberProperty=RegisterProperty(“SerialNumber”,typeof(string),null);
}
}
加载应用程序后,必须立即显示ConnectDisconnectView。然后用户可以使用主窗口工具栏上的按钮随意切换视图。视图之间的切换必须以以下方式进行:如果(例如)当前显示的视图是“ConnectDisconnectView”,并且用户按下“Field Settings”(字段设置)按钮,则“ConnectDisconnectView”(连接断开视图)视图必须从主窗口消失,“FieldSettingsView”(字段设置视图)视图必须出现,并且必须显示在主窗口中。等等也就是说,当按下主窗口工具栏中的相应按钮(例如“流量计校准”)时,必须在主窗口中显示相应的视图(校准视图),而不能显示其他视图。如何在应用程序中实现此功能?我们将非常感谢你的帮助


当然,如你所见,为了简洁明了,这里减少了视图的数量和内容。在现实世界中,我的应用程序中的视图数量约为20-25,它们必须包含复杂的图形和表格信息。

解决此问题的一种方法是使用Prism中的区域。因此,您可以在特定区域激活视图模型。

首先,我向您展示xaml代码:

<catel:Window.Resources>
    <catel:ViewModelToViewConverter x:Key="ViewModelToViewConverter" />
</catel:Window.Resources>

<catel:StackGrid x:Name="LayoutRoot">
    <ContentControl Content="{Binding CurrentPage, Converter={StaticResource ViewModelToViewConverter}}" />

    <ToolBar>
    <Button Name="btnConnectDisconnect" Command={Binding Connect} Content="Connect/Disconnect"/>
        <Button Name="btnFieldSettings" Command={Binding Field} Content="Field Settings"/>
        <Button Name="btnCalibration" Command={Binding Calibration} Content="Flowmeter Calibration"/>
    </ToolBar>
</catel:StackGrid>

然后在c代码中,您需要:

using Catel.Data;
using Catel.MVVM;
using System.Threading.Tasks;

public class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        this.Connect = new Command(HandleConnectCommand);
        this.Field = new Command(HandleFieldCommand);
        this.Calibration = new Command(HandleCalibrationCommand);

        this.CurrentPage = new ConnectViewModel();
    }

    /// <summary>
    /// Gets or sets the CurrentPage value.
    /// </summary>
    public IViewModel CurrentPage
    {
        get { return GetValue<IViewModel>(CurrentPageProperty); }
        set { SetValue(CurrentPageProperty, value); }
    }

    /// <summary>
    /// Register the CurrentPage property so it is known in the class.
    /// </summary>
    public static readonly PropertyData CurrentPageProperty = RegisterProperty("CurrentPage", typeof(IViewModel), null);

    public Command Connect { get; private set; }

    public Command Field { get; private set; }

    public Command Calibration { get; private set; }

    protected override async Task InitializeAsync()
    {
        await base.InitializeAsync();
        // TODO: subscribe to events here
    }

    protected override async Task CloseAsync()
    {
        // TODO: unsubscribe from events here
        await base.CloseAsync();
    }

    private void HandleCalibrationCommand()
    {
        this.CurrentPage = new CalibrationViewModel();
    }

    private void HandleFieldCommand()
    {
        this.CurrentPage = new FieldViewModel();
    }

    private void HandleConnectCommand()
    {
        this.CurrentPage = new ConnectViewModel();
    }
}
使用类别数据;
使用Catel.MVVM;
使用System.Threading.Tasks;
公共类MainWindowViewModel:ViewModelBase
{
公共主窗口视图模型()
{
this.Connect=新命令(HandleConnectCommand);
this.Field=新命令(HandleFieldCommand);
此.校准=新命令(HandleCalibrationCommand);
this.CurrentPage=新的ConnectViewModel();
}
/// 
///获取或设置CurrentPage值。
/// 
公共IViewModel当前页面
{
获取{返回GetValue(CurrentPageProperty);}
set{SetValue(CurrentPageProperty,value);}
}
/// 
///注册CurrentPage属性,使其在类中已知。
/// 
公共静态只读属性Data CurrentPageProperty=RegisterProperty(“CurrentPage”,类型为(IViewModel),null);
公共命令Connect{get;private set;}
公共命令字段{get;private set;}
公共命令校准{get;private set;}
受保护的重写异步任务InitializeAsync()
{
wait base.InitializeAsync();
//TODO:在此处订阅活动
}
受保护的覆盖异步任务CloseAsync()
{
//TODO:取消订阅此处的活动
等待base.CloseAsync();
}
私有void HandleCalibrationCommand()
{