【发布时间】:2015-05-11 16:53:10
【问题描述】:
我目前正在开发一个 C# WPF 应用程序并尝试遵循 MVVM 设计模式。
它现在的工作方式是我在主窗口中使用ContentControl 并将其绑定到CurrentViewModel,并在App.xaml 中声明我的数据模板。当我想更改主窗口中的当前视图时,我所要做的就是更改主窗口视图模型中的CurrentViewModel 属性,效果很好。另外,为了不直接引用视图模型(通过在视图模型中执行new blablaViewModel()),我有一个在ICommand 函数中调用的单例FlowManager 类,并且实例化在那个类而不是视图模型。
这种方法的问题在于,对于我添加到应用程序的每个视图,我必须在App.xaml 中添加一个数据模板,在我的FlowManager 类中添加一个enum 条目,在我的类中添加一个新的case switch() 在ChangePage() 函数中,在我的MainViewModel 中添加一个新的ICommand,添加实际视图的代码并创建它自己的视图模型。
以下是我如何处理应用程序流程的示例:
在 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 中,我列出了所有视图的所有数据模板:
<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>
就像我说的,这很好用,但我可以看到一些可伸缩性问题,因为我必须修改我的代码的几个部分才能在应用程序中添加一个视图。有没有更好的方法可以在不使用任何框架的情况下做到这一点?
【问题讨论】:
-
您可以查看我的导航源代码:github.com/Maxikq/WKFramework#navigation-for-wpf
-
@WojciechKulik 感谢您的建议,我会研究一下!
标签: c# wpf mvvm navigation datatemplate