我目前正在开发一个C#WPF应用程序,并试图遵循MVVM设计模式。处理WPF MVVM中ContentControls之间导航的更好方法?
它现在的工作方式是我在我的主窗口中使用ContentControl
并将其绑定到CurrentViewModel
,并在我的数据模板中声明App.xaml
。当我想在主窗口中更改当前视图时,我所要做的就是在主窗口的视图模型中更改CurrentViewModel
属性,这非常合适。此外,为了不直接引用视图模型(在视图模型中通过执行new blablaViewModel()
),我有一个单例FlowManager
类,我在ICommand
函数中调用,并且实例化在该类中完成,而不是在视图中完成模型。
这种方法的问题,是因为我添加到我的应用程序的每个观点,我要补充一个DataTemplate在App.xaml
,在我FlowManager
类的enum
条目,并在我的switch()
新case
在ChangePage()
功能,新的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我通过创建主窗口并设置其启动应用程序DataContext
和MainViewModel
属性:
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>
就像我说的,这个效果很好,但我可以看到一些可扩展性问题,因为我有修改我的代码的几个部分,以便在应用程序中添加视图。没有使用任何框架,有没有更好的方法来做到这一点?
您可以查看我的导航源代码:https://github.com/Maxikq/WKFramework#navigation-for-wpf –
@WojciechKulik感谢您的建议,我会研究它! – Choub890