In my solution I am using Autofac, and Prism as well. Below is a simplified project that explains what happens.
I am registering my views, view models and EventAggregator
in Autofac's container class like that:
public class BootStrapper
{
public IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<EventAggregator>()
.As<IEventAggregator>().SingleInstance();
builder.RegisterType<MainWindow>().AsSelf();
builder.RegisterType<ChildView1>().AsSelf();
builder.RegisterType<MainViewModel>().AsSelf();
builder.RegisterType<Child1ViewModel>().AsSelf();
return builder.Build();
}
}
Note, that when registering view models as a singletons, effect was the same. I am injecting EventAggregator
into my VM like that:
public class MainViewModel
{
private IEventAggregator _eventAggregator;
public MainViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
UpdateName("Name1");
}
public void UpdateName(string name)
{
ChildView1 win1 = new ChildView1(); //in the backend Child1ViewModel is assigend to its DataContext
win1.Show();
_eventAggregator.GetEvent<UpdateNameEvent>().Publish(name); //this does not work
}
}
Code above does not work. Because of some reason (I hope that you will tell me why), when executing UpdateName
method, this dependency does not work, and inside of Child1ViewModel class UpdateName
method is not executed:
public class Child1ViewModel : ViewModelBase
{
private IEventAggregator _eventAggregator;
public Child1ViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<UpdateNameEvent>().Subscribe(UpdateName);
}
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
OnPropertyChanged();
}
}
private void UpdateName(string name)
{
this.Name = name; //debug does not hit this code line
}
}
Constructor of Child1ViewModel is hiten during debug, just UpdateName
is not executed. BUT, if I use direct call of the EventAggregator
, like this:
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Subscribe(UpdateName);
or this:
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Publish(name);
it works! When assuming, that Utility class looks like:
public class Utility
{
public static EventAggregator EventAggregator { get; set; }
static Utility()
{
EventAggregator = new EventAggregator();
}
}
I suspect, that there is some problem with registering the aggregator in Autofac, but I have no idea what is the problem, I just used it as per odl exaples I found.
Resolving Child1ViewModel and MainViewModel:
public partial class ChildView1 : Window
{
public ChildView1()
{
var bootStrapper = new BootStrapper();
var container = bootStrapper.BootStrap();
Child1ViewModel vm = container.Resolve<Child1ViewModel>();
InitializeComponent();
DataContext = vm;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
var bootStrapper = new BootStrapper();
var container = bootStrapper.BootStrap();
MainViewModel vm = container.Resolve<MainViewModel>();
InitializeComponent();
DataContext = vm;
}
}
I'm assuming you are using Prism's ViewModelLocator mechanism. My assumption is based on that you are manually instantiating ChildView1 rather than resolving it with dependency injection container and state in the comment that viewModel is resolved in the background.
You must change the container of Prism ViewModelLocator used for resolving the ViewModel instances as shown below.
ViewModelLocationProvider.SetDefaultViewModelFactory(viewModelType) =>
{
return YourAutofacContainer.Resolve<viewModelType>();
});
For further information see Control how ViewModels are Resolved.
Keep in mind that for keeping single instance lifetime scope of object instances consistent throughout your whole application, you must use the same dependency injection container instance for resolving objects and this objects' parent objects all the way up to the root object.