MvvmCross usage of IMvxMessenger - c#

I want to use the IMvxMessenger Plugin, but i cant initialize a viewmodel where I want to use it.
my Core.ViewModels
public class DataViewModel : MvxNavigationViewModel
{
protected readonly IMvxMessenger _messenger;
public DataViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService, IMvxMessenger messenger)
: base(logProvider, navigationService)
{
this._messenger = messenger;
}
}
my WPFCore.ViewModels
public class DataViewModel : Core.ViewModels.DataViewModel
{
public DataViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService, IMvxMessenger messenger)
: base(logProvider, navigationService, messenger)
{}
protected new void SaveDyno()
{
var message = new Core.Models.MvxReloaderMessage(this, this.Dyno);
this._messenger.Publish(message);
}
}
my messenger model
public class MvxReloaderMessage
: MvxMessage
{
public DynoModel Dyno
{
get;
private set;
}
public MvxReloaderMessage(object sender, DynoModel dyno)
: base(sender)
{
this.Dyno = dyno;
}
}
The error
"Failed to resolve parameter for parameter messenger of type IMvxMessenger when creating WPFCore.ViewModels.DataViewModel. You may pass it as an argument"
I also tried some Initialization, but it doesnt work or show some errors;
Mvx.RegisterType<IMvxMessenger, MvxReloaderMessage>();
Mvx.IoCProvider.RegisterSingleton<MvvmCross.Plugin.Messenger.IMvxMessenger>(new Core.Models.MvxReloaderMessage());
Mvx.IoCProvider.Resolve<MvvmCross.Plugin.Messenger.IMvxMessenger>();

Please make sure the plugin has been loaded. You can do that by overriding LoadPlugins in Setup.cs and add:
pluginManager.EnsurePluginLoaded<MvvmCross.Plugin.Messenger.Plugin>();

Related

Activation error with IEventAggregator Prism

I am using Prism in my WPF. When I add IEventAggregator as a parameter to the ViewModel constructor I get this error: An exception of type 'Microsoft.Practices.ServiceLocation.ActivationException' occurred in Microsoft.Practices.ServiceLocation.dll.
Additional information: Activation error occurred while trying to get instance of type Object, key "CategoriesView"
The exception is triggered in this line:
private void NavigateToCategoriesRadioButton_Click(object sender, RoutedEventArgs e)
{
this.regionManager.RequestNavigate(RegionNames.ConfigurationContentRegion, categoriesViewUri);
}
where categoriesViewUri is:
private static Uri categoriesViewUri = new Uri("/CategoriesView", UriKind.Relative);
This is my view model class:
[Export]
public class CategoriesViewModel : BindableBase
{
private readonly IRegionManager regionManager;
private readonly IEventAggregator eventAggregator;
private readonly IConfigurationCategoriesService categoriesService;
private readonly ObservableCollection<Category> categoriesCollection;
private readonly ICollectionView categoriesView;
private readonly DelegateCommand<object> deleteCategoryCommand;
[ImportingConstructor]
public CategoriesViewModel(IEventAggregator eventAggregator, IConfigurationCategoriesService categoriesService, IRegionManager regionManager)
{
this.categoriesService = categoriesService;
this.regionManager = regionManager;
this.eventAggregator = eventAggregator;
this.deleteCategoryCommand = new DelegateCommand<object>(this.DeleteCategory, this.CanDeleteCategory);
this.categoriesCollection = new ObservableCollection<Category>(categoriesService.GetCategories());
this.categoriesView = new ListCollectionView(this.categoriesCollection);
this.categoriesView.CurrentChanged += (s, e) => this.deleteCategoryCommand.RaiseCanExecuteChanged();
}
public ICollectionView Categories
{
get { return this.categoriesView; }
}
public ICommand DeleteCategoryCommand
{
get { return this.deleteCategoryCommand; }
}
private void DeleteCategory(object ignored)
{
var category = this.categoriesView.CurrentItem as Category;
if (category != null)
{
categoriesService.DeleteCategory(category);
}
}
private bool CanDeleteCategory(object ignored)
{
return true;
}
}
It looks like CatagoriesViewModel cannot get an instance of IEventAggregator on the constructor but this is done automatically by Prism, isn't it? In the example I have from Prism Documentation (StockTraderRI_Desktop) I donĀ“t see anywhere where the EventAggregator is instantiated. Can anyone see what am I getting wrong? Thanks in advance
Editted:
The Navitagion item view is registerd in the CategoriesModule class:
[ModuleExport(typeof(CategoriesModule))]
public class CategoriesModule : IModule
{
[Import]
public IRegionManager regionManager;
public void Initialize()
{
this.regionManager.RegisterViewWithRegion(RegionNames.ConfigurationNavigationRegion, typeof(CategoriesNavigationItemView));
}
}
And CategoriesView code-behind is:
[Export("CategoriesView")]
public partial class CategoriesView : UserControl
{
public CategoriesView()
{
InitializeComponent();
}
[Import]
public IRegionManager regionManager;
[Import]
public CategoriesViewModel ViewModel
{
get { return this.DataContext as CategoriesViewModel; }
set { this.DataContext = value; }
}
}
I solved this issue adding the following using statement:
using Microsoft.Practices.Prism.PubSubEvents;
instead of
using Prism.Events;
I also switched to Unity instead of MEF by recommendation on this site.

Event sourcing implementation with autofac (register/resolve handlers)

I implemented Event Sourcing, but i am not sure that i am registering and using the autofac IoC correctly to register and resolve my handlers.
My code:
Example event:
public class AddressChanged : IDomainEvent
{
public AddressChanged(string address)
{
Address = address;
}
public string Address { get; set; }
}
Example event handler:
internal class AddressChangedEventHandler : IEventHandler<AddressChanged>
{
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void Handle(AddressChanged #event)
{
Log.Info($"Address updated to {#event.Address}");
}
}
Here is how i register my handlers:
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof(IEventHandler<>));
And here is my EventDispatcher class:
public class EventDispatcher : IEventDispatcher
{
private readonly IComponentContext _context;
public EventDispatcher(IComponentContext context)
{
_context = context;
}
public void Dispatch<TEvent>(TEvent #event) where TEvent : IDomainEvent
{
dynamic handler = _context.Resolve(typeof(IEventHandler<>).MakeGenericType(#event.GetType()));
handler.Handle((dynamic)#event);
}
}
Is this the right way to resolve the handlers with autofac?
Yes it was, or at least it worked.

Passing data from one VM to another VM, using Unity and prism EventAggregator

Trying to pass data from one ViewModel to another using prism EventAggregator, but when I debug on the subscriber, the data is null.
Using version 5.0 of prism.
Update
Okay, I have tried implement the EventAggregator using prism 5.0 version. It still dosen't work, but here is what I have done.
1: Create event class
public class RoomsSelectedEvent : PubSubEvent<ObservableCollection<Room>>
{
}
2: Inject IEventAggregator on publisher ViewModel (BookingViewModel)
public class BookingViewModel : INotifyPropertyChanged, IViewBookingViewModel
{
//aggregator
protected readonly IEventAggregator _eventAggregator;
//commands
public ICommand ContinueCommand { get; set; }
public ObservableCollection<Room> RoomsList { get; private set; }
public ObservableCollection<RoomList> DropDownRooms { get; private set; }
public ObservableCollection<CustomerList> DropDownCustomers { get; private set; }
//enities
private readonly IDialogService<ContactDetailsView> _dialogServiceContactView;
private readonly IGetRoomsService _getRoomsService;
public BookingViewModel(IDialogService<ContactDetailsView> dialogServiceContactview, IGetRoomsService GetRoomsService, IEventAggregator eventAggregator)
{
// Injection
_dialogServiceContactView = dialogServiceContactview;
_getRoomsService = GetRoomsService;
_eventAggregator = eventAggregator;
//commands
ContinueCommand = new RelayCommand(ContinueCommand_DoWork, () => true);
}
// Continue Command
public void ContinueCommand_DoWork(object obj)
{
ObservableCollection<Room> RoomsSelected = new ObservableCollection<Room>();
RoomsSelected = _getRoomsService.FilterSelectedRooms(RoomsList);
//Publish event:
_eventAggregator.GetEvent<RoomsSelectedEvent>().Publish(RoomsSelected);
// Open new dialog
_dialogServiceContactView.ShowDialog();
}
}
3: Inject IEventAggregator in subscriber viewModel (ContactViewModel)
public class ContactViewModel : IViewContactViewModel, INotifyPropertyChanged
{
//aggregator
protected readonly IEventAggregator _eventAggregator;
//properties
public ObservableCollection<Room> SelectedRooms { get; set; }
public ContactViewModel(IEventAggregator eventAggregator)
{
//Injection
_eventAggregator = eventAggregator;
//Subscripe to event
_eventAggregator.GetEvent<RoomsSelectedEvent>()
.Subscribe((data) => { SelectedRooms = data; });
}
public ObservableCollection<Room> Rooms
{
get { return SelectedRooms; }
set { SelectedRooms = value; NotifyPropertyChanged(); }
}
}
I have read it's maybe because of the IEventAggregator is not the same in both ViewModels. I'm using Unity to inject it like this code:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//view & viewModels
_container = new UnityContainer();
_container.RegisterType<IViewMainWindowViewModel, MainWindow>();
_container.RegisterType<IViewMainWindowViewModel, MenuViewModel>();
_container.RegisterType<IViewBookingViewModel, BookingView>();
_container.RegisterType<IViewBookingViewModel, BookingViewModel>();
_container.RegisterType<IViewContactViewModel, ContactDetailsView>();
_container.RegisterType<IViewContactViewModel, ContactViewModel>();
_container.RegisterType<IGetRoomsService, GetRoomsService>();
_container.RegisterType<IPostReservationService, PostReservationService>();
_container.RegisterType<IGetReservationsListService, GetReservationsListService>();
//types
_container.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());
_container.RegisterType(typeof(IDialogService<>), typeof(DialogService<>));
_container.Resolve<MainWindow>().Show();
}
Found that I need to add the ContainerControlledLifetimeManager, but it still wont work.
When I debug in the subscriber viewModel, I can see that there is an event inside the instance, like on the image:
It wont catch it , thats the problem :(
Today I tried delete all packages I installed (prism 5.0) and go for the Prism.Core (6.1 version)
That resulted in the same, I can see when I debug that the event in published, but when I subscribe, it's still null.

Unity + EntityFramework + PRISM - "Resolution of the dependency failed"

Im new on Unity/EF world and im getting a Error when i execute my test new project.
I have a Prism bootstrap first:
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return new Shell();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
this.Container
.RegisterType<IDataContextAsync, SistemaContext>(new ContainerControlledLifetimeManager())
.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new ContainerControlledLifetimeManager())
.RegisterType<IRepositoryAsync<Cliente>, Repository<Cliente>>()
.RegisterType<IClienteService, ClienteService>();
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
moduleCatalog.AddModule(typeof(CadastroModule.CadastroModule));
}
}
And other project "CadastroModule" with the CadastroModule:
public class CadastroModule : IModule
{
private readonly IRegionManager regionManager;
public CadastroModule(IRegionManager regionManager)
{
this.regionManager = regionManager;
}
public void Initialize()
{
this.regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.CadastroCliente));
}
}
Thats my EF Context:
public class SistemaContext : Sistema.Common.Repository.DataContext
{
static SistemaContext()
{//I dont know what to do here!
//Database.SetInitializer<SistemaContext>(new MigrateDatabaseToLatestVersion<SistemaContext, Sistema.DataAccess.Migrations.Configuration>());
}
public SistemaContext()
: base("Name=ContactsDb")
{
}
public DbSet<Cliente> Cliente { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new Sistema.DataAccess.Mapping.ClienteConfig());
modelBuilder.Configurations.Add(new Sistema.DataAccess.Mapping.EnderecoConfig());
}
}
I need the "MigrateDatabaseToLatestVersion" for automatic migrations.
The View:
public partial class CadastroCliente : UserControl
{
private readonly IClienteService _clienteService;
private readonly IUnitOfWork _unitOfWork;
public CadastroCliente()
{
InitializeComponent();
}
public CadastroCliente(IClienteService clienteService, IUnitOfWork unitOfWork)
{
_clienteService = clienteService;
_unitOfWork = unitOfWork;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
dgv.DataContext = _clienteService.ClienteOrdenadoNome();
}
}
UPDATE 1 IF i take out the IUnitOfWork it runs!:
public partial class CadastroCliente : UserControl
{
private readonly IClienteService _clienteService;
private readonly IUnitOfWork _unitOfWork;
public CadastroCliente()
{
InitializeComponent();
}
public CadastroCliente(IClienteService clienteService)
{
_clienteService = clienteService;
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
dgv.DataContext = _clienteService.ClienteOrdenadoNome();
}
}
Im using a Generic unit of Work repository located here: Link
And the Error is this:
At the time of the exception, the container was:
Resolving CadastroModule.Views.CadastroCliente,(none)
Resolving parameter \"unitOfWork\" of constructor CadastroModule.Views.CadastroCliente(Sistema.Service.IClienteService clienteService, Sistema.Common.Repository.UoW.IUnitOfWork unitOfWork)
Resolving Sistema.Common.Repository.UoW.IUnitOfWork,(none)
I detected when the UnitOfWork is taking the context
public class UnitOfWork : UnitOfWorkAsync
public UnitOfWork(IDataContextAsync dataContext) { _dataContext = dataContext; }
The dataContext return a internal exception exception:
The context cannot be used while the model is being created.
This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently.
Note that instance members of DbContext and related classes are not guaranteed to be thread safe
What im doing wrong?
Problem resolved after many days...
Internaly of the RepositoryFramework that im using, the EntityClasses need to inherit from a class named Entity:
public abstract class Entity : IObjectState
{
[NotMapped]
public ObjectState ObjectState { get; set; }
}
A child "Complex"(Entity framework Mapping ComplexTypeConfiguration<*>) class, was not inherited.
The error was not the UNIT/PRISM, was the repository itself that im using.
To resolve that i created a new project using no Modularity PRISM to be more simple to find where the error is comming.
So... my problem was resolved by putting the ": Entity" on my Child class:
public class Endereco : Entity //HERE
{
public string Rua { get; set; }
public int Numero { get; set; }
}

Caliburn micro ViewModel is not picking up a message from another ViewModel

Following my learning of MVVM using Caliburn.micro framework... I'm trying to communicate two viewModels sending data through the EventAggregator like this (code with "no sense", just for test):
MainWindowViewModel.cs
namespace TOP
{
[Export(typeof(MainWindowViewModel))]
public class MainWindowViewModel : Conductor<IScreen>.Collection.OneActive
{
readonly IWindowManager windowManager;
private readonly IEventAggregator events;
private bool _Logged;
[ImportingConstructor]
public MainWindowViewModel(IWindowManager windowManager, IEventAggregator events)
{
DisplayName = "TOP";
this.events = events;
events.Subscribe(this);
this.windowManager = windowManager;
windowManager.ShowDialog(new LoginViewModel(events));
}
public bool Logged
{
get { return _Logged; }
set
{
_Logged = value;
if(_Logged== true)
InitiateApp();
}
}
public void Handle(LoginEvent message)
{
Logged = message.Logged;
}
private void InitiateApp() {
ActivateItem(new TwoWindowViewModel());
}
}
}
LoginViewModel.cs
namespace TOP{
[Export(typeof(IScreen))]
public class LoginViewModel : Screen
{
private readonly IEventAggregator _events;
[ImportingConstructor]
public LoginViewModel(IEventAggregator events)
{
DisplayName = "Login";
_events = events;
Login();
}
public void Login()
{
_events.Publish(new LoginEvent(true));
}
}
}
LoginEvent.cs
namespace TOP
{
public class LoginEvent
{
public LoginEvent(bool logged)
{
Logged = logged;
}
public bool Logged { get; private set; }
}
}
Why the Handle method of MainWindowViewModel is not picking up the published message from LoginViewModel?
Thank you for your responses.
Your MainWindowViewModel needs to implement IHandle<LoginEvent>. You already defined the method with the correct signature, so you only are missing the part where you actually tell the compiler that you implement the interface:
public class MainWindowViewModel
: Conductor<IScreen>.Collection.OneActive, IHandle<LoginEvent>
More info can be found in the documentation.

Categories