【发布时间】:2017-07-06 00:40:34
【问题描述】:
当虚拟机(以及视图)需要接受对象被异步初始化的构造函数参数时,我如何在视图/视图模型之间切换。或者,有没有更好的方法来为视图/虚拟机提供这些对象?
这是我之前在 View/VM 不使用构造函数参数时的实现。
MainWindow.xaml
当 ContentControl 发生变化时,使用 DataTemplates 在视图之间切换。
<Window.DataContext>
<viewModels:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:InitializerViewModel}">
<userControls:InitializerUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:GameListingViewModel}">
<views:GameListingView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:StreamListingViewModel}">
<views:StreamListingView />
</DataTemplate>
</Window.Resources>
<ContentControl x:Name="ContentSection" Content="{Binding CurrentViewModel, Mode=OneWay}">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="Loaded">
<interactivity:InvokeCommandAction Command="{Binding StartInitializationCommand}"/>
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
</ContentControl>
MainWindowViewModel.cs
创建新的 ViewModel,然后将 CurrentViewModel 设置为相关的 ViewModel。当这种情况发生变化时,DataTemplate 会根据上述 DataTemplate 切换视图。
public class MainWindowViewModel : BaseViewModel
{
private InitializerViewModel _initializerViewModel;
public ICommand StartInitializationCommand { get; set; }
public MainWindowViewModel()
{
StartInitializationCommand = new AwaitableDelegateCommand(InitializeAsync);
}
private async Task InitializeAsync()
{
_initializerViewModel = new InitializerViewModel();
CurrentViewModel = _initializerViewModel;
var initializationResult = await _initializerViewModel.InitializeAsync();
if (initializationResult)
{
GameListingViewModel = new GameListingViewModel(_initializerViewModel.MyObject1, _initializerViewModel.MyObject2);
CurrentViewModel = GameListingViewModel;
}
}
}
GameListingView.xaml(这是我切换进出的 VM 之一):
之前在其 xaml 中定义的 DataContext via:
<UserControl.DataContext>
<viewModels:GameListingViewModel />
</UserControl.DataContext>-->
上述所有工作都按预期工作。
现在,由于新功能,这些 ViewModel 需要接收 1 个或多个对象才能运行,所以我想将它们传递给构造函数。因此,我无法再在 xaml 中定义 DataContext,但我可以使用代码隐藏来创建它们。
public GameListingView(ConfigSettings configSettings, GameBoxHelper gameBoxHelper)
{
InitializeComponent();
DataContext = new GameListingViewModel(configSettings, gameBoxHelper);
}
问题是这需要 View 的构造函数也接受相关对象(否则我会从哪里获取这些对象?),这使得返回 MainWindow.xaml 的 DataTemplate 不再工作。
Xaml 错误消息:“类型 'GameListingView' 不能用作对象元素,因为它不是公共的或未定义公共无参数构造函数或类型转换器。未找到默认构造函数。”
重要的是,传递给这些 ViewModel 的对象并没有立即准备好; MainWindowViewModel 预先初始化它们,这是异步完成的。根据上述错误消息,我认为可以使用TypeConverter(将要传递的对象绑定到参数并在 xaml 中将它们分配为 TypeConverter 的参数),但我不知道这将如何工作,因为它们是没有立即准备好(异步初始化)。
供参考:目的是在加载应用程序时预先完成所有初始化(从文件系统读取配置设置,从 Web API 检索一些数据等),以便在需要时立即准备好应用程序的其余部分响应更快。我不希望将对象的异步初始化移至使用它们的 VM。
我不使用任何 MVVM 框架。
鉴于这一切,我的问题是如何继续切换我的视图/虚拟机,同时为它们提供提前异步初始化的对象?
【问题讨论】:
-
我认为您可以在视图中使用 DependancyProperty 并在视图模型发生更改时更新它们。
-
你能举个例子说明它是如何工作的吗?
-
考虑以视图模型为中心的设计,其中您的主视图模型具有子视图模型(或子视图模型的集合)作为属性,并且子视图模型可能具有它们自己的子 VM 属性。与其创建自己的视图模型的视图,不如使用
DataTemplates 将视图隐式分配给视图模型。<ContentControl Content="{Binding BlahVM}" />——无论BlahVM是什么类型,如果它有一个隐含的DataTemplate,你会在UI 中得到它。BlahVM可以声明为对象,它的父级可以整天切换不同的子虚拟机。 -
这不是我在前半部分已经在做的事情(已经运行的代码)吗?我遇到的问题是克服了创建虚拟机并将其附加到视图的障碍,当视图/虚拟机采用构造函数参数时(并且没有立即准备好)。
标签: c# .net wpf xaml datatemplate