Je n'arrive pas à trouver une solution à ce problème. J'ai vu plusieurs questions à ce sujet, mais aucune ne m'a vraiment apporté de solution. Je suis totalement nouveau chez Autofac et je n’ai pas vraiment fait beaucoup de WPF + MVVM, mais je connais les bases.
J'ai une application WPF (avec ModernUI for WPF) à laquelle j'essaie d'ajouter Autofac, et j'ai du mal à comprendre comment résoudre mes services dans toutes les vues, car ils n'ont pas accès à mon conteneur. J'ai une vue principale, qui est mon point d'entrée, où je configure mon conteneur:
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>();
...
}
}
Le problème que je rencontre est de savoir comment résoudre mon enregistreur et d'autres services au sein de mes autres vues, où j'injecte toutes mes dépendances via le constructeur ViewModel, comme suit:
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;
}
}
Certaines vues contiennent une quantité ridicule de paramètres injectés, et c’est là que je souhaite que Autofac entre en jeu et m’aide à nettoyer les choses.
Je pensais passer le conteneur au ViewModel et le stocker en tant que propriété de ma classe ViewModelBase, mais j'ai lu qu'il s'agirait d'un anti-motif et je ne sais même pas si cela résoudrait automatiquement mes objets. dans les autres ViewModels.
J'ai réussi à mettre en place une application console simple en utilisant 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);
}
}
}
mais c'était simple, car il n'y a qu'un seul point d'entrée.
J'aimerais quelques idées sur la façon d'ajouter Autofac à mon application WPF. Je suis sûr que je fais quelque chose de mal. Votre aide est appréciée.
En développant mon commentaire ci-dessus:
J'utilise Autofac avec toutes mes applications MVF WPF, je pense que c'est l'un des meilleurs frameworks de DI - c'est mon opinion, mais je pense que c'est valide.
Aussi, pour moi, PRISM devrait être évité 99% du temps, c’est une 'solution à la recherche d’un problème' et, comme la plupart des gens ne construisent pas de solutions d’exécution dynamiques composables de manière dynamique dans WPF, ce n’est pas nécessaire, je suis sûr que les gens serait en désaccord.
Comme tous les modèles architecturaux, il existe une phase d'installation/configuration dans le cycle de vie de l'application, avant que la première vue (fenêtre) ne s'affiche, il y aura toute une configuration effectuée pour Dependency Injection, Logging, Exception Handling, Dispatcher. gestion des threads, thèmes etc.
J'ai plusieurs exemples d'utilisation d'Autofac avec WPF\MVVM. Quelques exemples sont énumérés ci-dessous. Je vous suggère de regarder l'exemple Simple.Wpf.Exceptions:
https://github.com/oriches/Simple.Wpf.Exceptions
Vous pouvez utiliser une technique similaire à celle de votre application console:
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();
}
}
}
Assurez-vous de marquer principal avec [STAThread]
. Ensuite, dans les propriétés du projet, sous l'onglet Application, définissez le Startup object
sur la classe Program.
Cependant, je ne suis pas certain des conséquences de ne pas exécuter App.Run()
et d’exécuter MainWindow.ShowDialog()
à la place.
Pour faire la même chose avec App.Run()
, procédez comme suit:
1) supprimer StartupUri="MainWindow.xaml"
de App.xaml
2) Ajoutez ce qui suit à 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 n'a pas de racine de composition naturelle ni d'intégration facile de DI. Prism est un ensemble assez commun de bibliothèques spécialement conçues pour établir un pont entre elles.
(Ce n'est pas spécifique à Autofac - c'est une directive générale pour ajouter DI aux applications WPF.)