[英]How can I switch around Views/ViewModels that are provided objects which are asychronously initialized ahead of time?
當VM(因此需要Views)需要接受其對象被異步初始化的構造函數參數時,如何在Views / ViewModels之間切換。 或者,是否有更好的方法為視圖/ VM提供這些對象?
當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將根據上述DataTemplates切換視圖。
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:
<UserControl.DataContext>
<viewModels:GameListingViewModel />
</UserControl.DataContext>-->
以上所有工作均符合預期。
現在,由於具有新功能,這些ViewModel需要接收1個或多個對象才能起作用,因此我想將它們傳遞給構造函數。 結果,我不再可以在xaml中定義DataContext,但是可以使用背后的代碼來創建它們。
public GameListingView(ConfigSettings configSettings, GameBoxHelper gameBoxHelper)
{
InitializeComponent();
DataContext = new GameListingViewModel(configSettings, gameBoxHelper);
}
問題在於,這要求View的構造函數也要接收相關的對象(否則我將從何處獲取這些對象?),這使得DataTemplate回到MainWindow.xaml
不再起作用。
Xaml錯誤消息: “類型'GameListingView'不能用作對象元素,因為它不是公共的或未定義公共的無參數構造函數或類型轉換器。找不到默認的構造函數。”
重要的是,傳遞給這些ViewModels的對象還沒有立即准備好。 MainWindowViewModel會事先對其進行初始化,這是異步進行的。 根據以上錯誤消息,我認為可以使用TypeConverter
(將要傳遞的對象綁定到參數,並在xaml中將它們分配為TypeConverter的參數),但是我看不到它將如何工作,因為它們不是立即准備好(異步初始化)。
供參考:目的是在加載應用程序時,所有初始化都預先完成(從文件系統中讀取配置設置,從Web API中檢索一些數據,等等),以便在需要時可以立即進行其余操作。應用程序響應速度更快。 我寧願不要將對象的異步初始化移動到使用它們的VM。
我不使用任何MVVM框架。
考慮到所有這些,我的問題是如何繼續為我的視圖/虛擬機切換,同時為它們提供提前異步初始化的對象?
當應用程序啟動時,您不能在App.xaml.cs
或bootstrapper類中創建依賴項,然后將它們作為構造函數參數傳遞給MainViewModel
嗎?
從App.xaml中的“ Application
根元素中刪除StartupUri
屬性,並覆蓋App.xaml.cs中的OnStartup
方法:
public partial class App : Application
{
protected async override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var yourDependency = await YourClass.CreateAsync();
MainWindowViewModel vm = new MainWindowViewModel(yourDependency);
MainWindow mainWindow = new WpfApplication4.MainWindow() { DataContext = vm };
mainWindow.Show();
}
}
然后, MainViewModel
類將負責注入它創建的其他視圖模型,以及由App類注入的依賴項。
或者,如果您希望在MainViewModel
類內部初始化依賴項,則可以在App
類中初始化該依賴項,即MainViewModel
。
請參閱Stephen Cleary的博客文章,以獲取有關異步工廠方法和異步構造的更多信息: http : //blog.stephencleary.com/2013/01/async-oop-2-constructors.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.