WPF Dynamic UserControl Container - c#

I have been tasked with creating a UI container in which different UI's will be automatically loaded from DLL's. These UI's or views, will adhere to a common interface. In the assembly will also be information about settings that is to be displayed as treeview. What would be the best practices for creating such a solution in c# with WPF? Prism seems like the way to go - do you agree?

Advantage of prism is, that it's well known and if you follow the practices, you can refer to prism documentation. I would say, the advatages end here.
You can use IoC container like Unity, or MEF to load your modules and inject some IApplicationContext implementation to module. You module will then inject stuff to ApplicationContext. No need for prism here.
let's assume you module is identified by IModuleImplementation:
public interface IModule
{
void Initialize(IApplicationContext applicationContext);
}
In your application bootstrapp your modules:
public void Bootstrap()
{
var applicationContext = new ApplicationContext();
IModule[] modules = LoadModulesFromDirectoryAssemblies();
foreach (var module in modules)
{
module.Initialize(applicationContext);
}
}
and the modules will inject whatever needed:
public class Module1 : IModule
{
public void Initialize(IApplicationContext applicationContext)
{
//inject Module1 services, views, menuitems, command etc. to applicationContext.
}
}
You shell window will then get injected stuff in application context and reflect it in UI.

Related

WPF MVVM Dependency Injection for UserControls

I'm developing a WPF .Net Core 5 Application using MVVM Pattern, and I'm trying to use Dependency Injection to learn something new.
I've just modified the App.xaml.cs class as follows and after initial login, I can reach MainWindow showing as expected:
public partial class App : Application
{
private readonly ServiceProvider _serviceProvider;
public App()
{
ServiceCollection services = new ServiceCollection();
ConfigureServices(services);
_serviceProvider = services.BuildServiceProvider();
}
private void ConfigureServices(ServiceCollection services)
{
services.AddTransient<frmSQLConnection>();
services.AddTransient<frmLogin>();
services.AddSingleton<MainWindow>();
}
protected override void OnStartup(StartupEventArgs e)
{
if ((SuccessfullyConnected || _serviceProvider.GetService<frmSQLConnection>().ShowDialog() == true) && _serviceProvider.GetService<frmLogin>().ShowDialog() == true)
{
_serviceProvider.GetService<MainWindow>().Show();
}
else
{
Shutdown();
}
}
}
My doubts come now because MainWindow.xaml will be composed by a RibbonMenu on the top and a TabControl right below, like this example:
enter image description here
My question is what would be a good implementation of Dependency Injection for UserControls?
I've read some articles speaking about Composite Application but it seemed to be more useful for nested UserControls than in my case.
Any suggestion?
Thanks in advance for availability
If you are conforming to the MVVM pattern, then you would set up ViewModels for each user control and use DI in the constructor or method bodies to inject the 'services' you need. Then you can use something like PRISM (MVVM Framework) to trigger events that other ViewModels can subscribe to. It also provides mechanisms for navigation within an MVVM application as well.
EDIT:
You may also want to look into using a 'shell' view and then user controls inside. This will enable you to swap/navigate to different user controls within the 'shell' view. Which can have its own view model and global events, etc.
PRISM Resources: https://prismlibrary.com/docs/index.html

C# WPF Prism - Share a same object between different modules(project)

I have multiple modules(each module in a different project) in my prism project. And I would like to share a same object between each module.
For example, let say I have Order class and I would like to access this Order object in my modules.
Currently, I implemented an interface and registered it with container in my Prism project.
public interface ICommonService{
Order GetData();
}
public class CommonService : ICommonService{
public Order MyOrder{ get; set; }
public Order GetData(){
return MyOrder;
}
public void SetData(Order order){
MyOrder = order;
}
}
I am using it in every module where it need MyOrder.
Is this a correct way of sharing a same object between modules?
Also, my View Models classes contains several Manager classes.
Should only View Model classes use ICommonService or can my Manager classes also use it?
I am trying to write clean and manageable code.
Thank you.
Is this a correct way of sharing a same object between modules?
Yes.
Should only View Model classes use ICommonService or can my Manager classes also use it?
The manager classes are fine to use the service.
Notes:
You should include a means of notifying other consumers of ICommonService when MyOrder changes. Examples: implement INotifyPropertyChanged or publish a MyOrderChanged event through the event aggregator
Normally, anyone who can access a service (read: knows the interface), should be allowed to do so. It's better to restrict the accessibility of the interface (by putting it in a separate assembly) than restricting accessibility of the service (by documentation), because the former is enforced by the compiler.
You can use Event Aggregation
The Prism Library provides an event mechanism that enables communications between loosely coupled components in the application. This mechanism, based on the event aggregator service, allows publishers and subscribers to communicate through events and still do not have a direct reference to each other.
Link Communicating Between Loosely Coupled Components
Prism
Sample
When you define your module, you should specify an dependencies in the constructor for that module. For example:
public class SomeModule : IModule
{
public SomeModule(ICommonService commonService)
{
// commonService will be shared object
}
}
In your Bootstrapper, when you add the module to the catalog, it will look through the DI container to look up the type. If you have it set to global reference, it will use the same object for all references to ICommonService.
class Bootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
RegisterTypeIfMissing(typeof(ICommonService),
typeof(CommonService), true); // true for register as singleton
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog module_catalog = (ModuleCatalog)this.ModuleCatalog;
module_catalog.AddModule(typeof(SomeModule));
}
}

Multiple viewmodel using Caliburn Micro and MEF

I am designing a WPF application with several ViewModels, and I am using Caliburn Micro and MEF. Unfortunately, I am absolutely new to MEF and IoC, and can't solve a problem.
The application is supposed to have a MainView, where several options are enlisted, like: Create a new record, Edit older records, View reports, etc. So, for each of those units, I have different classes for ViewModels like CreateRecordViewModel, EditRecordsViewModel, ViewReportsViewModel, and Usercontrols for Views like CreateRecordView, EditRecordsView, ViewReportsView etc.
Now, the MainViewModel is a Conductor, and I am using code like this:
public class ShellViewModel : Conductor<object>
{
public void ShowCreateRecord()
{
ActivateItem(new CreateRecordViewModel(...Dependencies...));
}
public void ShowEditRecords()
{
ActivateItem(new EditRecordsViewModel(...Dependencies...));
}
...
}
Since the MEF container resides in Bootstrapper, I am a bit lost about how to use Constructor Injection in this MainViewModel. And my second concern is about GC. How can I test if the created ViewModels are properly disposed of?
I know these questions might seem a bit asinine, but I would really appreciate a solution. Should I decorate my Property setters with [Import] instead of going for Constructor Injection?
I am not familiar with MEF myself, but most of the DIs work in a similar idea.
You have to inject the container's (MEF container) into the view models, and resolve the appropriate viewmodels using the container.
You're not supposed to instantiate viewmodels by yourself, instead, in the main vm, inject the container resolving service, via constructor or property injection (again - not so familiar with MEF), then call ActivateItem(_DependencyService.Resolve<CreateRecordViewModel>());.
And BTW, the Main VM itself should also be instantiated by the container, so you obviously don't need to manually inject the container to the main vm.
IoC is just about trusting the container to resolve anything for you, otherwise, its the container registered types that are misregistered:
public class ShellViewModel : Conductor<object>
{
private readonly IMefDependencyContainer _container;
public ShellViewModel(IMefDependencyContainer container) {
_container = container;
}
public void ShowCreateRecord()
{
ActivateItem(_container.Resolve<CreateRecordViewModel>());
}
}
Replace IMefDependencyContainer and Resolve with its names in MEF.

Correctly use Dependency Injection pattern [duplicate]

I'm currently working on a WinForms system (I know) where there's a lot of Constructor Injection when creating forms, but if those forms/views need to open another form, I find the DI container has been injected too so that we can locate the implementation of the desired view interface at runtime. e.g.
public partial class MyView : Form, IMyView
{
private readonly IDIContainer _container;
public MyView(IDIContainer container)
{
InitializeComponent();
_container = container;
}
public OpenDialogClick(object sender, EventArgs e)
{
var dialog = container.Resolve<IDialogView>();
dialog.ShowDialog(this);
}
}
I'm aware that this is basically using the container as a service locator. I've been repeatedly told that this is considered an anti-pattern so I'd like to avoid this usage.
I could probably inject the view as part of the constructor like this :
public partial class MyView : Form, IMyView
{
private readonly IDialogView _dialog;
public MyView(IDialogView dialog)
{
InitializeComponent();
_dialog = dialog;
}
public OpenDialogClick(object sender, EventArgs e)
{
dialog.ShowDialog(this);
}
}
But what if the dialog view is quite expensive to instantiate?
It's been suggested that we create some kind of form factory which internally uses the DI container, but to me this seems like simply creating a wrapper around another service locator.
I know that at some point, something has to know how to create an IDialogView, so I'm thinking that either it's resolved when the composite root is created (probably not ideal if there are many forms and some or all are expensive to create), or the composite root itself has a way to resolve the dependency. In which case the composite root has to have a service-locator-like dependency? But then how would child forms create dialogs like this? Would they call up to the composite via, say, events, to open dialogs like this?
One particular problem I keep running up against is that the container is almost impossible to mock easily. This is partly what keeps me thinking about the form factory idea, even though it would just be a wrapper around the container. Is that a sensible reason?
Have I thought myself into a knot? Is there a simple way through this? Or do I just cut the knot and find something that works for me?
Or do I just cut the knot and find something that works for me?
Factory class:
public interface IDialogFactory {
IDialogView CreateNew();
}
// Implementation
sealed class DialogFactory: IDialogFactory {
public IDialogView CreateNew() {
return new DialogImpl();
}
}
// or singleton...
sealed class SingleDialogFactory: IDialogFactory {
private IDialogView dialog;
public IDialogView CreateNew() {
if (dialog == null) {
dialog = new DialogImpl();
}
return dialog;
}
}
Your code:
public partial class MyView : Form, IMyView {
private readonly IDialogFactory factory;
public MyView(IDialogFactory factory) {
InitializeComponent();
//assert(factory != null);
this.factory = factory;
}
public OpenDialogClick(object sender, EventArgs e) {
using (var dialog = this.factory.CreateNew()) {
dialog.ShowDialog(this);
}
}
}
Registration with SimpleInjector
container.RegisterSingle<IDialogFactory, DialogFactory>();
or using singleton version
container.RegisterSingle<IDialogFactory, SingleDialogFactory>();
container.RegisterSingle<IMyView, MyView>();
A local factory, satisfied with an implementation that uses the container and set up in the composition root is not a service locator, it is a dependency resolver.
The difference is as follows: the locator is defined and satisfied somewhere near the definition of the container. In a separate project, to use the locator, you need an external reference to the container infrastructure. This causes the project to rely on external dependency (the locator).
On the other hand, the dependency resolver is local to the project. It is used to satisfy dependencies in its close neighbourhood but it doesn't depend on anything external.
The composition root should not be used to resolve actual specific dependencies such as the one you are concerned about. Instead, the compositon root should set up implementations of all these local dependency resolvers that are used throughout the application. The more local resolver, the better - the MVC's constructor factory is a good example. On the other hand, WebAPI's resolver handles quite few of different services and it is still a good resolver - it is local in the webapi infrastructure, it doesn't depend on anything (rather - other webapi services depend on it) and it can be implemented in any possible way and set up in the Composition Root.
Some time ago I wrote a blog entry about it
http://www.wiktorzychla.com/2012/12/di-factories-and-composition-root.html
There you will find your issue discussed and an example of how you set up a factory aka resolver.
You definitely do not want to pass your DI container around your application. Your DI container should only be part of your Composition Root. You could, however, have a factory that uses the DI container within the Composition Root. So if Program.cs is where you are wiring everything up, you could simply define that factory class there.
WinForms was not designed with DI in mind; forms are generated and therefore need default constructors. This may or may not be an issue depending on which DI container you use.
I think in this case, the pain of using constructor injection in WinForms is greater than the pain of any pitfalls you may encounter while using a service locator. There's no shame in declaring a static method in your Composition Root (Program.cs) that wraps a call to your DI container to resolve your references.
I know this problem very well. Everything I learned about solution to this (and I learned A LOT) is more or less camouflaging service locator.

C# ASP.NET Dependency Injection with IoC Container Complications

I apologise for the length, and I know there are some answers on this but I searched a lot and haven't found the right solution,
so please bear with me.
I am trying to create a framework for legacy applications to use DI in ASP.NET webforms. I will probably use Castle Windsor
as the framework.
These legacy applications will use in part an MVP pattern in some places.
A presenter would look something like this:
class Presenter1
{
public Presenter1(IView1 view,
IRepository<User> userRepository)
{
}
}
Now the ASP.NET Page would look something like this:
public partial class MyPage1 : System.Web.UI.Page, IView1
{
private Presenter1 _presenter;
}
Before using DI I would instantiate the Presenter as follows in the OnInit of the page:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
_presenter = new Presenter1(this, new UserRepository(new SqlDataContext()));
}
So now I want to use DI.
First I must create a handler factory to override the construction of my page.
I found THIS really good answer to help:
How to use Dependency Injection with ASP.NET Web Forms
Now I can easily set up my containers in my composition root as Mark Seeman suggest to use the Global.asax
(This means though to create a static container that must be thread safe and sealed not to be able to add further registrations)
Now I can go and declare the constructor injection on the page
public MyPage1() : base()
{
}
public MyPage1(Presenter1 presenter) : this()
{
this._presenter = presenter;
}
Now we run into the first problem, I have a circular dependency.
Presenter1 depends on IView1, But the page depends on the presenter.
I know what some will say now that the design is probably incorrect when you have circular dependencies.
First I dont think the Presenter design is incorrect, by it taking a dependency in the constructor to the View, and I can say this
by looking at plenty of MVP implementations.
Some may suggest changing the Page to a design where Presenter1 becomes a property and then using Property injection
public partial class MyPage1 : System.Web.UI.Page, IView1
{
[Dependency]
public Presenter1 Presenter
{
get; set;
}
}
Some may even suggest removing the dependency to presenter completely and then simply Wiring up via a bunch of events, But this is
not the design I wanted and frankly dont see why I need to make this change to accomodate it.
Anyway regardless of the suggestion, another problem exists:
When the Handler factory gets a page request only a type is available (NOT THE VIEW INTERFACE):
Type pageType = page.GetType().BaseType;
now using this type you can resolve the Page via IoC and its dependencies:
container.Resolve(pageType)
This will then know that there is a property called Presenter1 and be able to inject it.
But Presenter1 needs IView1, but we never resolved IView1 through the container, so the container won't know
to provide the concrete instance the handler factory just created as it was created outside of container.
So we need to hack our handler factory and replace the view interface:
So where the handler factory resolves the page:
private void InjectDependencies(object page)
{
Type pageType = page.GetType().BaseType;
// hack
foreach (var intf in pageType.GetInterfaces())
{
if (typeof(IView).IsAssignableFrom(intf))
{
_container.Bind(intf, () => page);
}
}
// injectDependencies to page...
}
This poses another problem, most containers like Castle Windsor will not allow you to reregister this interface
to the instance it is pointing to now. Also with the container being registered in the Global.asax, it is not thread-safe to
do as the container should be read only at this point.
The other solution is to create a function to rebuild the container on each web request, and then check to see
if the container contains the component IView if not set the instance. But this seems wasteful and goes against suggested use.
The other solution is to create a special Factory called
IPresenterFactory and put the dependency in the page constructor:
public MyPage1(IPresenter1Factory factory) : this()
{
this._presenter = factory.Create(this);
}
The problem is that you now need to create a factory for each presenter and then make a call to the container
to resolve other dependencies:
class Presenter1Factory : IPresenter1Factory
{
public Presenter1Factory(Container container)
{
this._container = container;
}
public Presenter1 Create(IView1 view)
{
return new Presenter1(view, _container.Resolve<IUserRepository>,...)
}
}
This design also seems cumbersome and over complicated, does any one have ideas for a more elegant solution?
Perhaps I misunderstand your problems, but the solution seems fairly simple to me: promote the IView to a property on the Presenter1:
class Presenter1
{
public Presenter1(IRepository<User> userRepository)
{
}
public IView1 View { get; set; }
}
This way you can set the presenter on the view like this:
public Presenter1 Presenter { get; set; }
public MyPage1()
{
ObjectFactory.BuildUp(this);
this.Presenter.View = this;
}
Or without property injection, you can do it as follows:
private Presenter1 _presenter;
public MyPage1()
{
this._presenter = ObjectFactory.Resolve<Presenter1>();
this._presenter.View = this;
}
Constructor injection in Page classes and user controls will never really work. You can get it to work in full trust (as this article shows), but it will fail in partial trust. So you will have to call the container for this.
All DI containers are thread-safe, as long as you don't manually add registrations yourself after the initialization phase and with some containers even that is thread-safe (some containers even forbid registering types after initialization). There would never be a need to do this (except for unregistered type resolution, which most containers support). With Castle however, you need to register all concrete types upfront, which means it needs to know about your Presenter1, before you resolve it. Either register this, change this behavior, or move to a container that allows resolving concrete types by default.

Categories

Resources