この問題の解決策を見つけることができないようです。私はこれについていくつかの質問を見てきましたが、本当に解決策を与えるものはありません。私はAutofacにまったく慣れていないので、WPFとMVVMをあまり実行していませんが、基本は知っています。
Autofacを追加しようとしているWPFアプリケーション(ModernUI for WPFを使用)があり、コンテナーにアクセスできないため、すべてのビュー内でサービスを解決する方法を理解するのに苦労しています。私はメインビューを持っています。これは私のエントリーポイントであり、ここでコンテナーをセットアップします。
public partial class MainWindow : ModernWindow
{
IContainer AppContainer;
public MainWindow()
{
SetUpContainer();
this.DataContext = new MainWindowViewModel();
InitializeComponent();
Application.Current.MainWindow = this;
}
private void SetUpContainer()
{
var builder = new ContainerBuilder();
BuildupContainer(builder);
var container = builder.Build();
AppContainer = container;
}
private void BuildupContainer(ContainerBuilder builder)
{
builder.RegisterType<Logger>().As<ILogger>();
...
}
}
私が抱えている問題は、他のビュー内でロガーと他のサービスを解決する方法を理解することです。
public partial class ItemsView : UserControl
{
private ItemsViewModel _vm;
public ItemsView()
{
InitializeComponent();
IFileHashHelper fileHashHelper = new MD5FileHashHelper();
ILibraryLoader libraryLoader = new LibraryLoader(fileHashHelper);
ILogger logger = new Logger();
_vm = new ItemsViewModel(libraryLoader, logger);
this.DataContext = _vm;
}
}
一部のビューには、途方もない量の注入されたパラメーターがあり、ここでAutofacを使用して、クリーンアップを行います。
コンテナーをViewModelに渡し、それをViewModelBaseクラスのプロパティとして保存することを考えていましたが、これはアンチパターンであり、それでもオブジェクトが自動的に解決されるかどうかはわかりません他のViewModel内。
Autofacを使用して簡単なコンソールアプリケーションを作成できました
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Cleaner>().As<ICleaner>();
builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
ICleaner cleaner = container.Resolve<ICleaner>();
cleaner.Update(stream);
}
}
}
しかし、エントリポイントが1つしかないため、それは簡単でした。
AutofacをWPFアプリに追加する方法に関するアイデアが欲しいのですが。私は何か間違ったことをしていると確信しています。よろしくお願いします。
上記の私のコメントを拡張する:
私はすべてのWPF MVVMアプリケーションでAutofacを使用しています。これは、優れたDIフレームワークの1つだと思います。これは私の意見ですが、妥当だと思います。
また、私にとってPRISMは99%の時間で回避する必要があります。これは「問題を探す解決策」であり、ほとんどの人は動的に構成可能なものを構築しないためWPFのランタイムソリューションは必要ありません。きっと人々は同意しないでしょう。
すべてのアーキテクチャパターンと同様に、アプリケーションのライフサイクルにはセットアップ\構成フェーズがあります。最初のビュー(ウィンドウ)が表示される前に、単純に言えば、依存性注入、ロギング、例外処理、ディスパッチャの設定全体が行われます。スレッド管理、テーマなど.
AutofacをWPF\MVVMで使用するいくつかの例があります。いくつかを以下に示します。Simple.Wpf.Exceptionsの例を見てください。
https://github.com/oriches/Simple.Wpf.Exceptions
コンソールアプリケーションと同様の手法を使用できます。
_class Program
{
[STAThread]
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Cleaner>().As<ICleaner>();
builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();
// Add the MainWindowclass and later resolve
build.RegisterType<MainWindow>().AsSelf();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var main = scope.Resolve<MainWindow>();
main.ShowDialog();
}
}
}
_
Mainには必ず_[STAThread]
_を付けてください。次に、プロジェクトのプロパティの[アプリケーション]タブで、_Startup object
_をProgramクラスに設定します。
ただし、App.Run()
を実行しないことと、代わりにMainWindow.ShowDialog()
を実行することの影響については、私は確信が持てません。
App.Run()
を使用して同じことを行うには、次のようにします。
1)App.xamlから_StartupUri="MainWindow.xaml"
_を削除します
2)以下をApp.xaml.csに追加します
_protected override void OnStartup(StartupEventArgs e)
{
var builder = new ContainerBuilder();
builder.RegisterType<Cleaner>().As<ICleaner>();
builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();
// Add the MainWindowclass and later resolve
build.RegisterType<MainWindow>().AsSelf();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var window = scope.Resolve<MainWindow>();
window.Show();
}
}
_
WPFには、自然な構成ルートや簡単なDI統合がありません。 Prism は、これをブリッジするために特に意図されたかなり一般的なライブラリのセットです。
(これはAutofac固有ではありません-WPFアプリにDIを追加するための一般的なガイダンスです。)