MEF and plugins using IOC - c#

I'm currently using WPF and .NET 4.5, my purpose is to build a desktop app that supports plugins using MVVM.
Using MEF, I can import plugins with
pluginLoader = new PluginLoader<IPlugin>(path);
IPlugin is the interface that expose the method that app itself should use, plus the view object that app dinamically shows on the main window.
public interface IPlugin
{
[...]
object View { get; }
}
Here's my doubts:
How can I use IoC with this architecture? I'm currently using TinyIOC and there's no reason to change it so far.
By the way, since I'm using MVVM, I need both viewmodel and view components.
For this purpose, I thought about exposing IPlugin so made:
public interface IPlugin
{
object View { get; }
object ViewModel { get; } // called after Init()
void Init(); // called after plugin resolution
}
public class MyPlugin : IPlugin
{
MyViewModel vm;
MyView view;
void Init()
{
// use TinyIOC to init service and resolve viewmodel
}
object ViewModel
{
get
{
return vm;
}
}
object View
{
get
{
return view;
}
}
}
What do you think about this? Can it works?

Related

Using MvvmLight.Messaging.Messenger to instantiate new View + ViewModel (Window)

I have my MainView and an associated MainViewViewModel which are linked by ViewModelLocator.
Within MainViewViewModel there is a command which should trigger a new Window to open which has it's own View and ViewModel (NewView and NewViewViewModel).
In a lot of the examples I've seen it is suggested to use Mvvmlight's Messenger to do something like this:
public class MainViewViewModel
{
private void OpenNewWindow()
{
Messenger.Default.Send(new NotificationMessage("NewView"));
}
}
And then register the NewViewViewModel and handle the message like this:
public class NewViewViewModel
{
public NewViewViewModel()
{
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
private void NotificationMessageReceived(NotificationMessage obj)
{
if (obj.Notification == "NewView")
{
NewView view = new NewView();
view.Show();
}
}
}
However, this doesn't work because the NewViewViewModel isn't yet instantiated (so isn't registered with Messenger). Additionally, this doesn't fit with MVVM because NewViewViewModel is responsible for creating NewView.
What is the correct way to achieve a simple command which instantiates and opens a new View and ViewModel pair which are linked via ViewModelLocator and setting of DataContext="{Binding NewView, Source={StaticResource Locator}}" in NewView.xml?
Use a window service:
MVVM show new window from VM when seperated projects
You may either inject the view model to with an IWindowService implementation or use a static WindowService class:
public static class WindowService
{
public static void OpenWindow()
{
NewView view = new NewView();
view.Show();
}
}
Dependency injection is obviously preferable for being able to unit test the view model(s) and switch implementations of IWindowService at runtime.

Getting around circular dependency

Could I get help with a little issue I am encountering regarding splitting projects into different tiers. In my ViewModel logic I have code where I create a new instance of a window when a button is clicked (I use ICommand interface for that)
The problem is however, that this requires my View folder which is in the presentation layer, I can’t reach it as my presentation layer is dependent on my ViewModel in the logic layer.
I would just move the code that deals with the creation of the pages to the view code behind but I also pass the current instance of a viewmodel as a parameter for that new window being created (for eventhandling purposes).
Any help is much appreciated! Thanks.
A view model shouldn't create instances of windows. What you could do is to inject your view model with a service that is responsible for creating windows, e.g.:
public class MainWindowViewModel
{
private readonly IWindowService _windowService;
public MainWindowViewModel(IWindowService windowService)
{
_windowService = windowService;
CreateWindowCommand = new DelegateCommand(() =>
{
_windowService.CreateWindow(new SomeViewModel());
});
}
public ICommand CreateWindowCommand { get; }
}
Define the IWindowService interface in the view model project and the concrete implementation of it in the view/presentation project:
public class WindowService : IWindowService
{
public void CreateWindow(SomeViewModel vm)
{
Window win = new Window();
win.DataContext = vm;
win.Show();
}
}

Modern UI wpf, how to add ContentSource page with constructor injection as view model

Im pretty new to modern ui framework. I'm adding new page(usercontroller) as ContentSource page.
Im using IOC framework (IviewModels and ViewModels). I'm getting error saying no maching constructor found. because usercontroll default constructor injected with Iviewmodel object.
i'm pretty stuck here, it would be great some one can help this matter
thanks
this is my main window code + this is my usercontroll cs file
this is the error
As you found out, you can't use parameterized constructors because they break the framework.
Navigation use just the page URI, no other extra parameters.
So, how do you use IoC without parameterized constructors?
You should use a Dependency Injection Container.
Something like this:
public partial class MyPage: UserControl
{
private MyViewModel: IViewModel;
public MyPage()
{
MyViewModel = MyViewModelFactory.Create(IViewModel);
InitializeComponent();
}
}
MyVewModelFactory is an object which create other objects.
You dont have to code it by yourself.
Some common IoC containers are:
Unity
MEF
Using Unity your code would be:
public partial class MyPage: UserControl
{
private MyViewModel: IViewModel;
public MyPage()
{
MyViewModel = container.Resove<IViewModel>();
InitializeComponent();
}
}
Using MEF your code would be:
public partial class MyPage: UserControl
{
[Import(GetType(IViewModel))]
private MyViewModel: IViewModel;
public MyPage()
{
InitializeComponent();
}
}

Register all viewmodel and services in ViewModelLocator

I am developing a new MVVM light Wpf application.I have 25 View and ViewModels and 25 DataService Interface and its implementations (One implementation for Design time Data service and one for realtime dataservice).
For Eg, Here is a my DataService Interface for my SupplierViewModel:
interface ISupplierDataService
{
ObservableCollection<Tbl_Supplier> GetAllSuppliers();
int GetSupplierCount(string supplierNameMatch);
}
and Here is its implementation for design time :
class SupplierDataServiceMock : ISupplierDataService
{
public ObservableCollection<Tbl_Supplier> GetAllSuppliers()
{
.....
}
public int GetSupplierCount(string supplierNameMatch)
{
....
}
}
class SupplierDataService : ISupplierDataService
{
public ObservableCollection<Tbl_Supplier> GetAllSuppliers()
{
....
}
public int GetSupplierCount(string supplierNameMatch)
{
....
}
}
In ViewModelLocator is I need to register all my 25 ViewModels and its 25 DataService and its implementations like this :
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<ISupplierDataService, SupplierDataServiceMock>();
SimpleIoc.Default.Register<ICustomerDataService, CustomerDataServiceMock>();
....
}
else
{
SimpleIoc.Default.Register<ISupplierDataService, SupplierDataService>();
SimpleIoc.Default.Register<ICustomerDataService, CustomerDataService>();
....
}
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<SupplierViewModel>();
SimpleIoc.Default.Register<CustomerViewModel>();
....
}
My question is do I need to register all my 25 ViewModels and its 25 DataService in my ViewModelLocator ?
Another possibility would be to write a factory class ViewModelResolver this can then be injected by SimpleIoc (given you have an IViewModelResolver).
The main purpuse is to deliver a ViewModel. You can do it based on conventions, by string, by type, whatever fits best for you.
So for example ViewModelResolver.GetViewModelFor("Namespace.CustomerView");
This could be done per convention and reflection for example to return a new Instance of CustomViewModel...
With this you do also have control whether you like to retrieve a cached view model (always the same) or generate a new on each request...
This is just example to get you the idea... The implementation depends on your requirements...
HTM

MVVM light, send message via Messenger from ViewModel to new child window, which is not initialized yet

I've following architecture:
desktop application, .Net 4.5, C#, WPF, MVVM Light, Messenger, IoC - ViewModel locator, so ViewModels doen't know anyhing about Views.
I have main view with data grid of some elements, and I want to display details of each individual element in new/child windows after double click on data grid.
I've bind event double click on main view to main view model. From this event handler in main view model, message is sent via Messanger.
New view (new/child window) is created in main view via delegate of also double click.
New/child window is a view which locate his view model and this view model register to the specific message in his constructor.
The problem is that new/child window (new view, and view model so on) is created too late, because message is already sent when new view model register for it.
Do you know maybe some patterns for such architecture. Any ideas will be appreciated.
It would help to know exactly what you try to do.
If your problem is just to display a detailed Window when double click on a row, I would say: create only one childWindow at start, and play with its visbility when required.
If you really need a new window each time, you could create it from your viewModel with an injected service for example.
In any case, you never has to create your window from main view! Either you create one window at start, either you dynamically create it from view model.
You cannot hope to create it from view and send the message in your view model.
Edit about the injected service, you could use something like that:
public interface IWindowService
{
void Open<TWindow>(ViewModelBase viewModel)
where TWindow : Window;
}
public class WindowService : IWindowService
{
private readonly IUIDispatcher _dispatcher;
public WindowService(IUIDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void Open<TWindow>(ViewModelBase viewModel)
where TWindow : Window
{
_dispatcher.Run(() => OpenThreadSafe<TWindow>(viewModel));
}
private static void OpenThreadSafe<TWindow>(ViewModelBase viewModel) where TWindow : Window
{
var view = (TWindow) Activator.CreateInstance(typeof(TWindow), viewModel);
view.Show();
}
}
public class UIDispatcher : IUIDispatcher
{
public void Run(Action action)
{
var dispatcher = DispatcherHelper.UIDispatcher;
if (dispatcher == null)
{
action();
return;
}
DispatcherHelper.CheckBeginInvokeOnUI(action);
}
Note this DispatcherHelper come from MVVMlight, but you could erplace it easily.
Hope it helps.
The problem is that the ViewModel Locator creates the viewmodel instance only when it is needed (lazy loading).
just configure the ViewModelLocator to instantiate the viewmodel eager instead of lazy. This is done by passing the parameter "true" to the IoC Container.
Sample:
namespace Administration.ViewModel
{
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
//Eager Loading
SimpleIoc.Default.Register<UserManagementViewModel>(true);
//Lazy Loading
SimpleIoc.Default.Register<InformationManagementViewModel>();
}
public UserManagementViewModel UserManagementViewModel
{
get
{
return ServiceLocator.Current.GetInstance<UserManagementViewModel>();
}
}
public InformationManagementViewModel InformationManagementViewModel
{
get
{
return ServiceLocator.Current.GetInstance<InformationManagementViewModel>();
}
}
public static void Cleanup()
{
SimpleIoc.Default.Unregister<UserManagementViewModel>();
SimpleIoc.Default.Unregister<InformationManagementViewModel>();
}
}
}

Categories

Resources