2016-01-22 50 views
2

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

<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> 

应用程序MainWindow有一个ViewModel。为简洁起见,我不在这里展示。除了MainWindow之外,我的应用程序中还有三个视图: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); 
    } 
} 

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

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); 
    } 
} 

直接在我的应用程序加载后,必须显示ConnectDisconnectView。然后用户可以使用MainWindow工具栏上的按钮随意切换视图。视图之间的切换必须按照以下方式进行:如果(例如)当前显示的视图是“ConnectDisconnectView”,并且用户按下了“Field Settings”按钮,则“MainDisconnectView”视图必须从MainWindow消失并且必须出现“FieldSettingsView”视图,必须显示在MainWindow中。等等。即在MainWindow工具栏中按下适当的按钮(例如“流量计校准”)时,必须在MainWindow中显示相应的视图(CalibrationView),并且不能显示其他视图。我怎样才能在我的应用程序中实现这种功能?您的帮助将非常感激。

P.S.当然,正如您所看到的,为了简洁明了,视图的数量和内容在此缩小。在现实世界中,我的应用程序中的视图数量约为20 - 25,并且它们必须包含复杂的图形和表格信息。

+0

帮你一个忙,并使用Catel.Fody。然后,您可以将Catel属性编写为常规属性。 –

+0

我的视图切换任务可以通过Catel.Foby解决吗? – user3769902

回答

1

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

+0

不幸的是我之前从未使用Prism。如果有人给我一个在我的情况下在多个视图间切换的案例,我将非常感激。 – user3769902

+0

是否在NET4.6中提供了Prism扩展附带的UI组合功能? – user3769902

+0

我尝试使用Catel.Extensions.Prism时出现以下错误:“无法找到类型或命名空间名称'IUCompositionService'(您是否缺少using指令或程序集引用?)“ – user3769902

4

首先我告诉你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(); 
    } 
} 

当你启动应用程序当前页是用来装载数据上下文ConnectViewModel()。然后使用按钮中的命令,您可以更改另一个视图模型的日期上下文。

+0

不要忘记将我的答案标记为已选中如果它对你有好处。 – evelikov92