2015-05-11 46 views
0

我目前正在开发一个C#WPF应用程序,并试图遵循MVVM设计模式。处理WPF MVVM中ContentControls之间导航的更好方法?

它现在的工作方式是我在我的主窗口中使用ContentControl并将其绑定到CurrentViewModel,并在我的数据模板中声明App.xaml。当我想在主窗口中更改当前视图时,我所要做的就是在主窗口的视图模型中更改CurrentViewModel属性,这非常合适。此外,为了不直接引用视图模型(在视图模型中通过执行new blablaViewModel()),我有一个单例FlowManager类,我在ICommand函数中调用,并且实例化在该类中完成,而不是在视图中完成模型。

这种方法的问题,是因为我添加到我的应用程序的每个观点,我要补充一个DataTemplate在App.xaml,在我FlowManager类的enum条目,并在我的switch()caseChangePage()功能,新的ICommand在我的MainViewModel中,除了添加实际视图的代码并创建它自己的视图模型之外。

下面是我如何处理我的申请流程为例:

MainWindow.xaml,我有以下布局:

<Window x:Class="EveExcelMineralUpdater.Views.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:viewModels="clr-namespace:EveExcelMineralUpdater.ViewModels" 
     Title="MainWindow" Height="720" Width="1280"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="15*"/> 
      <ColumnDefinition Width="auto"/> 
      <ColumnDefinition Width="85*"/> 
     </Grid.ColumnDefinitions> 

     <StackPanel Grid.Column="0"> 
      <Button>MarketStat Request</Button> 
      <Button Command="{Binding ChangeToQuickLookCommand}">QuickLook Request</Button> 
      <Button>History Request</Button> 
      <Button>Route Request</Button> 
      <Button>Settings</Button> 
     </StackPanel> 

     <Separator Grid.Column="1" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> 

     <ContentControl Grid.Column="2" Content="{Binding CurrentViewModel}" /> 
    </Grid> 
</Window> 

App.xaml.cs我通过创建主窗口并设置其启动应用程序DataContextMainViewModel属性:

MainWindow mainWindow = new MainWindow(); 
MainViewModel mainViewModel = new MainViewModel(); 
mainWindow.DataContext = mainViewModel; 
mainWindow.ViewModel = mainViewModel; 

FlowManager.Instance.AppWindow = mainWindow; 

mainWindow.Show(); 

MainViewModel.cs,我处理一个按钮请求与ICommand想换个CurrentView属性如下:

private void ChangeToQuickLook(object param) 
{ 
    FlowManager.Instance.ChangePage(FlowManager.Pages.QuickLook); 
} 
... 
public ICommand ChangeToQuickLookCommand 
{ 
    get { return new RelayCommand(ChangeToQuickLook); } 
} 

FlowManager.cs,我有一个enum,列出所有页面(视图)在我的应用程序,并实际ChangePage()功能,这将改变CurrentViewModel财产在我MainViewModel

// Only one view is implemented for now, the rest are empty for now 
public void ChangePage(Pages page) 
{ 
    IViewModel newViewModel = null; 

    switch (page) 
    { 
     case Pages.MarketStat: 
      break; 
     case Pages.QuickLook: 
      newViewModel = new QuickLookRequestViewModel(); 
      break; 
     case Pages.History: 
      break; 
     case Pages.Route: 
      break; 
     case Pages.Settings: 
      break; 
    } 

    AppWindow.ViewModel.CurrentViewModel = newViewModel; 
} 
... 
public enum Pages 
{ 
    MarketStat, 
    QuickLook, 
    History, 
    Route, 
    Settings 
} 

最后,在App.xaml中,我有我所有的DataTemplates我所有的意见的清单:

<Application x:Class="EveExcelMineralUpdater.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:viewModels="clr-namespace:EveExcelMineralUpdater.ViewModels" 
      xmlns:views="clr-namespace:EveExcelMineralUpdater.Views" 
      Startup="App_OnStartup"> 
    <Application.Resources> 
     <!-- Pages DataTemplates --> 
     <DataTemplate DataType="{x:Type viewModels:QuickLookRequestViewModel}"> 
      <views:QuickLookRequestView /> 
     </DataTemplate> 
    </Application.Resources> 
</Application> 

就像我说的,这个效果很好,但我可以看到一些可扩展性问题,因为我有修改我的代码的几个部分,以便在应用程序中添加视图。没有使用任何框架,有没有更好的方法来做到这一点?

+1

您可以查看我的导航源代码:https://github.com/Maxikq/WKFramework#navigation-for-wpf –

+0

@WojciechKulik感谢您的建议,我会研究它! – Choub890

回答

0

看完@WojciechKulik评论后,我在我的FlowManager中想出了以下更改。CS类:

public class FlowManager 
{ 
    private static FlowManager _instance; 

    private MainWindow _mainWindow; 
    private ICollection<IViewModel> _viewModels; 

    private FlowManager() 
    { 
     ViewModels = new List<IViewModel>(); 
    } 

    public void ChangePage<TViewModel>() where TViewModel : IViewModel, new() 
    { 
     // If we are already on the same page as the button click, we don't change anything 
     if (AppWindow.ViewModel.CurrentViewModel == null || 
      AppWindow.ViewModel.CurrentViewModel.GetType() != typeof(TViewModel)) 
     { 
      foreach (IViewModel viewModel in ViewModels) 
      { 
       // If an instance of the viewmodel already exists, we switch to that one 
       if (viewModel.GetType() == typeof(TViewModel)) 
       { 
        AppWindow.ViewModel.CurrentViewModel = viewModel; 
        return; 
       } 
      } 

      // Else, we create a new instance of the viewmodel 
      TViewModel newViewModel = new TViewModel(); 
      AppWindow.ViewModel.CurrentViewModel = newViewModel; 
      ViewModels.Add(newViewModel); 
     } 
    } 

    public static FlowManager Instance 
    { 
     get 
     { 
      if (_instance == null) 
      { 
       _instance = new FlowManager(); 
      } 

      return _instance; 
     } 
    } 

    public MainWindow AppWindow { get; set; } 

    public ICollection<IViewModel> ViewModels { get; private set; } 
} 

这样一来,我增加对保持我的每个视图的视图模型的状态,和我通过使用功率在我的应用程序每个视图我有一个入口摆脱我enumGenerics和反思。

我会更新这个答案,如果我找到其他方法来减少我想要添加到应用程序中的每个视图的位置数量。