Reputation: 89
i have a problem with EventAggregator, on how make it work, i show a sample application where i have 4 projects:
-Shell -Module 'Order' -Module 'Customer' -Module 'Customer references' -Shared (global event aggregator)
Assume that i want to add a new Order, inside my order form (Module.Order) i have a combobox with customers, and a button that open another form to create a customer (Module.Customer) and i want that when i create my customer, the combobox inside the order form reload
I can manage this with that
OrderForm
private void AddCustomerExecute(object Dialog)
{
DialogVisibility = System.Windows.Visibility.Collapsed;
_unityContainer.RegisterInstance<string>("RegionName", M_G_O_ListModule._RegionDialog);
_eventAggregator.GetEvent<UIX_GlobalEvent.PassParameter>().Subscribe(ReloadCustomers);
_moduleManager.LoadModule("M_T_S_CustomersModule");
_shellService.ShowDialogUser(M_G_O_ListModule._RegionDialog, "M_T_S_CustomersModule_Add");
}
CustomerForm
private void SaveExecute()
{
Customer.CustomerCollection.LogAdded = DateTime.Now;
Customer.CustomerCollection.LogUserID = _userCompany.User.UserID;
_customerRepository.InsertCollection(Customer.CustomerCollection);
_shellService.CloseDialogUser(_regionName, M_T_S_CustomersModule._viewAdd);
_eventAggregator.GetEvent<UIX_GlobalEvent.PassParameter>().Publish(Customer.CustomerCollection.CustomerID);
}
The problem is when from the CustomerForm, i want to add a Reference (Module.CustomerReference) because, if i use the same process, when i save the CustomerReference it reload the combobox inside the order form, because the global event is subscribed
Someone know how can i manage this? Thank you
Upvotes: 0
Views: 605
Reputation: 3811
I'm going to restate the question so I make sure I understood it properly. Bear with me.
You have a Customer Form, (Modules.Customer
) in which you can both 1) Add a new Customer and 2) Add a new Customer Reference.
When you create a new Customer, it fires an Event (UIX_GlobalEvent.PassParameter>().Publish()
)
Both Modules.Orders
and Modules.CustomerReference
subscribe to this event.
So your problem is, when you use add a new Customer Reference, that global event tells your Module.Orders
to reload the combo box containing the Customers
and you don't want that behavior.
Is that correct? If so...
You should not need to 'reload' your combo boxes. That should be the job of data binding and implementing INotifyPropertyChanged
on your view model.
Check out the ViewModelBase
base class included with Prism Library.
When SaveExecute()
; is called on the CustomerForm, you add the Customer
to the CustomerCollection
. And it fires a global event.
In your OrderView
, Your ComboBox should be bound to an ObservableCollection<Customer>
defined in your OrderViewModel
(**Or ObservableDictionary<int, string>
, you shouldn't really store the entire Customer)
In your OrderViewModel
in the global event handler you should:
ObservableCollection<Customer>
How this solves your problem:
When you add a new CustomerReference
(I'm assuming the Customer
must already exist.) and your OrderViewModel
receives the event, you can check if the Customer
exists in the CustomerCollection
, and if it does exist, the CustomerCollection
is not changed, and your combo box will not 'reload'.
Also, When you add a new Customer, it's only asking for 1 customer by Id, instead of all customers to update your ComboBox.
Let's use the new simplified example provided from the comments and apply the same logic as above.
public class OrdersViewModel : ViewModelBase
{
private IProductsDataProvider _dataProvider;
private IEventAggregator _eventAggregator;
private ObservableCollection<Product> _productsComboBox;
public ObservableCollection<Product> ProductsComboBox
{
get { return _productsComboBox; }
set { _productsComboBox = value; OnPropertyChanged(); }
}
public OrdersViewModel(IProductsDataProvider dataProvider, IEventAggregator eventAggregator)
{
_dataProvider = dataProvider;
_eventAggregator = eventAggregator;
ComboBoxItems = new ObservableCollection<Product>();
_eventAggregator.GetEvent<GlobalUIX.ProductCreatedEvent>().Subscribe(OnProductCreatedEventHandler);
}
public void Initialize()
{
//Logic to load combo box with data from the database
var products = _dataProvider.GetAllProducts();
ProductsComboBox.AddRange(products);
}
private void OnProductCreatedEventHandler(int eventPayloadProductId)
{
var isProductInComboBox = ProductsComboBox.SingleOrDefault(p => p.Id == eventPayloadProductId);
if (isProductInComboBox == null) {
var existingProduct = _dataProvider.GetProductById(eventPayloadProductId);
ProductsComboBox.Add(newProduct);
}
}
}
OrdersModule
is instantiated.IProductsDataProvider
, which is this ViewModels gateway to the database in the Data Access layer.ObservableCollection()
;Load()
method to initialize the combo box from products from the database (Really, this should just be a Dictionary<int, string>()
so you don't load the entire Product)_eventAggregator
subscribes to the ProductCreatedEvent
ProductCreatedEvent
fires, OnProductCreatedEventHandler
is called..OnPropertyChanged();
is fired from the setter of ProductsComboBox
INotifyPropertyChanged
tells the UI to update.Duplicate this exactly for UnitsOfMeasureModule.
Which will give you 2 separate modules, that will each have a combo box that is updated from a single event, but does not reload the entire combo box when the event is fired.
Upvotes: 1
Reputation: 12276
You could forget eventaggregator entirely.
Register your observablecollection as singleton with unity.
or
Put it in application.current.resources if that doesn't suit for some reason.
One way or another, share the same observablecollection.
When you add in one window then it's the same collection bound in the other and you get the new customer there too.
or
You could add an event to whatever _customerrepository is so it says it's dirty to anything subscribing.
That then tells the subscriber to read the data again.
You have an awful lot of decoupling going on there.
If you don't really need it then the cost of the overhead created to make stuff work despite the decoupling is likely to exceeed the benefit.
Of course you might really need it and then you have no option.
Upvotes: 0