3 回答

TA貢獻1841條經(jīng)驗 獲得超3個贊
我一直在使用Ninject,發(fā)現(xiàn)與我合作很愉快。一切都在代碼中設置,語法非常簡單,并且有一個很好的文檔。
所以基本上它是這樣的:
創(chuàng)建視圖模型,并將IStorage接口作為構(gòu)造函數(shù)參數(shù):
class UserControlViewModel
{
? ? public UserControlViewModel(IStorage storage)
? ? {
? ? }
}
使用視圖屬性的get屬性創(chuàng)建一個ViewModelLocator,該模型從Ninject加載視圖模型:
class ViewModelLocator
{
? ? public UserControlViewModel UserControlViewModel
? ? {
? ? ? ? get { return IocKernel.Get<UserControlViewModel>();} // Loading UserControlViewModel will automatically load the binding for IStorage
? ? }
}
在App.xaml中使ViewModelLocator成為應用程序范圍的資源:
<Application ...>
? ? <Application.Resources>
? ? ? ? <local:ViewModelLocator x:Key="ViewModelLocator"/>
? ? </Application.Resources>
</Application>
將UserControl的DataContext綁定到ViewModelLocator中的相應屬性。
<UserControl ...
? ? ? ? ? ? ?DataContext="{Binding UserControlViewModel, Source={StaticResource ViewModelLocator}}">
? ? <Grid>
? ? </Grid>
</UserControl>
創(chuàng)建一個繼承NinjectModule的類,該類將設置必要的綁定(IStorage和viewmodel):
class IocConfiguration : NinjectModule
{
? ? public override void Load()
? ? {
? ? ? ? Bind<IStorage>().To<Storage>().InSingletonScope(); // Reuse same storage every time
? ? ? ? Bind<UserControlViewModel>().ToSelf().InTransientScope(); // Create new instance every time
? ? }
}
在應用程序啟動時使用必要的Ninject模塊(目前上面的模塊)初始化IoC內(nèi)核:
public partial class App : Application
{? ? ? ?
? ? protected override void OnStartup(StartupEventArgs e)
? ? {
? ? ? ? IocKernel.Initialize(new IocConfiguration());
? ? ? ? base.OnStartup(e);
? ? }
}
我使用了靜態(tài)IocKernel類來保存IoC內(nèi)核的應用程序范圍的實例,因此可以在需要時輕松訪問它:
public static class IocKernel
{
? ? private static StandardKernel _kernel;
? ? public static T Get<T>()
? ? {
? ? ? ? return _kernel.Get<T>();
? ? }
? ? public static void Initialize(params INinjectModule[] modules)
? ? {
? ? ? ? if (_kernel == null)
? ? ? ? {
? ? ? ? ? ? _kernel = new StandardKernel(modules);
? ? ? ? }
? ? }
}
此解決方案確實使用了靜態(tài)ServiceLocator(IocKernel),通常將其視為反模式,因為它隱藏了類的依賴項。但是,避免對UI類進行某種形式的手動服務查找非常困難,因為它們必須具有無參數(shù)的構(gòu)造函數(shù),而且您無論如何也無法控制實例化,因此無法注入VM。至少通過這種方式,您可以隔離地測試VM,這是所有業(yè)務邏輯所在的位置。

TA貢獻1951條經(jīng)驗 獲得超3個贊
在您的問題中,您設置了DataContextXAML中視圖屬性的值。這要求您的視圖模型具有默認的構(gòu)造函數(shù)。但是,正如您已經(jīng)指出的那樣,這與要在構(gòu)造函數(shù)中注入依賴項的依賴項注入不能很好地配合。
因此,您無法DataContext在XAML中設置屬性。相反,您還有其他選擇。
如果您的應用程序基于簡單的分層視圖模型,則可以在應用程序啟動時構(gòu)造整個視圖模型分層結(jié)構(gòu)(您必須StartupUri從App.xaml文件中刪除屬性):
public partial class App {
protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
var container = CreateContainer();
var viewModel = container.Resolve<RootViewModel>();
var window = new MainWindow { DataContext = viewModel };
window.Show();
}
}
這基于植根于的視圖模型的對象圖,RootViewModel但是您可以將一些視圖模型工廠注入父視圖模型,從而允許它們創(chuàng)建新的子視圖模型,因此不必固定對象圖。這也希望回答您的問題想我需要的實例,SomeViewModel從我的cs代碼,我應該怎么辦呢?
class ParentViewModel {
public ParentViewModel(ChildViewModelFactory childViewModelFactory) {
_childViewModelFactory = childViewModelFactory;
}
public void AddChild() {
Children.Add(_childViewModelFactory.Create());
}
ObservableCollection<ChildViewModel> Children { get; private set; }
}
class ChildViewModelFactory {
public ChildViewModelFactory(/* ChildViewModel dependencies */) {
// Store dependencies.
}
public ChildViewModel Create() {
return new ChildViewModel(/* Use stored dependencies */);
}
}
如果您的應用程序本質(zhì)上更具動態(tài)性,并且可能是基于導航的,那么您將不得不加入執(zhí)行導航的代碼。每次導航到新視圖時,都需要創(chuàng)建一個視圖模型(從DI容器中),視圖本身并將DataContext該視圖的設置為該視圖模型。您可以先執(zhí)行此視圖,然后再根據(jù)視圖選擇視圖模型,也可以先執(zhí)行視圖模型視圖模型確定使用哪個視圖。MVVM框架通過某種方式提供了此關鍵功能,您可以將DI容器掛接到視圖模型的創(chuàng)建中,但也可以自己實現(xiàn)。我在這里有點含糊,因為根據(jù)您的需要,此功能可能會變得非常復雜。這是您從MVVM框架獲得的核心功能之一,但是在簡單的應用程序中滾動自己的功能將使您很好地了解MVVM框架提供的功能。
由于無法DataContext在XAML中聲明,因此失去了一些設計時支持。如果您的視圖模型包含一些數(shù)據(jù),它將在設計時出現(xiàn),這可能非常有用。幸運的是,您也可以在WPF中使用設計時屬性。一種方法是將以下屬性添加到<Window>元素或<UserControl>XAML中:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MyViewModel, IsDesignTimeCreatable=True}"
視圖模型類型應具有兩個構(gòu)造函數(shù),默認構(gòu)造函數(shù)用于設計時數(shù)據(jù),另一個構(gòu)造函數(shù)用于依賴項注入:
class MyViewModel : INotifyPropertyChanged {
public MyViewModel() {
// Create some design-time data.
}
public MyViewModel(/* Dependencies */) {
// Store dependencies.
}
}
這樣,您可以使用依賴項注入并保留良好的設計時支持。
- 3 回答
- 0 關注
- 1119 瀏覽
添加回答
舉報