2015-05-11 80 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和反思。

我會更新這個答案,如果我找到其他方法來減少我想要添加到應用程序中的每個視圖的位置數量。