WPF, Prism, MEF. Register region adapter within a module? - wpf

Is it possible to register a region adapter within a module?
I have a ContentControl in my Shell.xaml set to region "MainRegion" that currently gets populated with a module containing the AvalonDock control. I currently have the AvalonDock region adapter in my Shell app but would like to place it in the module and register itself. I want to keep this program flexible so that if we decide to use something other than AvalonDock, I can easily use another module without having to modify my Shell assembly (removing the avalondock region adapter).
I imagine something like this is possible. Has anyone done this before?
In bootstrapper right now is:
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
var regionBehaviorFactory = Container.GetExportedValue<IRegionBehaviorFactory>();
var regionManager = Container.GetExportedValue<IRegionManager>();
mappings.RegisterMapping(typeof(Pane), new AvalonRegionAdapter(regionBehaviorFactory, regionManager));
return mappings;
}
This is what I would like to perform in the Module instead of the Shell bootstrapper.

Answer is here from codeplex http://compositewpf.codeplex.com/discussions/250892
The scenario you're describing is
possible. Although custom region
adapters are intended to be registered
in the RegionAdapterMappings in the
Bootstrapper's
ConfigureRegionAdapterMappings method,
it is possible to register a custom
region adapter from within a module.
You could, for example, obtain a
reference to the RegionAdapterMappings
in your Module class by using
constructor injection, and call the
RegisterMapping method there. This is
possible since there is a class named
MefRegionAdapterMappings, which
exports the RegionAdapterMappings as a
shared export. Note that you should be
aware of the timing issues that may
arise due to this. You should be
careful to register the custom mapping
before attempting to create a region
which uses that adapter.

Related

How to add internal dependencies from Modules in Prism using Autofac?

Using the instructions from http://www.milosev.com/98-c/wpf/373-autofac-and-prism-together#dependencyInjection I tried to setup my module's dependencies (eg. ViewModel requires some IServices to be constructed). The only thing I haven't used is that MEF thing but as far as I understood it is something alternative to Unity or Autofac.
I couldn't find any proper place to put the registration of types that are specific to my Module. Temporarily I use static method from my module class that is called from Bootstrapper's ConfigureContainerBuilder()
protected override void ConfigureContainerBuilder(ContainerBuilder containerBuilder)
{
base.ConfigureContainerBuilder(containerBuilder);
RoomSimulatorModule.InitializeDependencies(containerBuilder);
}
But it is called before my Module is initialised. Is there any way to add those types during module registration? Or due to the way Autofac constructs the container I can't register new types?

Have a module dependent Injection for State in PRISM WPF application

hi we have a PRISM WPF MVP application, we would like to have a state to share data between the views in the same module. Since PRISM by default doesnt have a state, was wondering if there is any way i could implement this. Presently i have injected a State with Dictionary as back-store, but the problem is its Global i.e available across the modules. i would really like to scope this injection being module specific.
I believe unity allows registering different classes to the same interface based on name, not sure if the only choice i have is to leverage that for my scenario.
Any help would be great! Thanks!
-ioWint
I would agree, scoping Unity's type registration with the ModuleName would be a place to start.
Inject a local(module level) state object into all the views that want to have share state. If the interface that defines the state object is local to your module then other modules won't be able to reference the state object because they can't reference the interface.
So: If Module A has 3 views that take an object implementing IStatefulContainer (also declared in Module A) and IStatefulContainer is registered with Unity using RegisterInstance rather than just RegisterType you'll have a singleton that is scoped to the module.
My preference would be to have a "State" service that managed state. This could allow you to add more functionality here if you needed it and is a more "Prismy" approach.
EDIT
If you're using this state object across modules then you can do the following:
1)Put the interface in an assembly that will be referenced by any module that wants to use it.
Assembly A
public interface IBlah
{
string Add(string stateKey, string stateValue);
}
Assembly B (referencing Assembly A)
public class Module:IModule
{
private IUnityContainer _container;
public Module(IUnityContainer container)
{
_container=container;
}
public void Initialize()
{
IBlah blah1=new BlahContainer();
IBlah blah2=new BlahContainer();
_container.RegisterInstance<IBlah>(blah1,"BlahContainer1");
_container.RegisterInstance<IBlah>(blah2,"BlahContainer2");
}
}
Module C(references assembly A)
_container.Resolve<IBlah>("BlahContainer1");
_container.Resolve<IBlah>("BlahContainer2");
Basically, we define the interface in an assembly we're happy to share between modules. Some projects have "Infrastructure" or Common assemblies that contain service interfaces that are used by other modules - this would fit well here.
We then have our module reference the assembly with the contract in it.
At the moment I'm relying on "magic strings" here but there are lots of ways around this.
Hope this is a little more clear.
thanks for your updated solution. I was trying to avoid a name based Unity registration, which would force my Presenter in knowing the Modules State registration Key.
I was reading stackoverflow posts on Unity and found the discussion over here Is it possible to override parameter values when using Method Injection with Unity? .
After couple of hours of trial and errors, i ended up achieving the desired functionality.
What i have done:
I have a BaseClass for my Modules -> BaseModule:IModule i have a State Property in it which conforms to my IStateService defined in the Infrastructure.Interface. I Instantiate this State property in the BaseModule() constructor.
Note: to go with this approach i have to make my Presenter's have a public IStateService State; property..
At the time of registering the Presenter in the module, i am specifying
<UnityContainer>.RegisterType<MyPresenter, new InjectionProperty("State", State).
Am overriding a public property in Presenter which has name "State" with the State instance value defined in the Module.
this way i am able to get the Modules State as the State for each of the View's presenter.
Thanks guys for directing me towards a solution.
-ioWint

PRISM: Are PRISM Modules intended to have only one view per region?

I'm really confused about what is supposed to be inside a Module.
When I call RegisterViewWithRegion for many views they are all loaded together during Module initialization... All those views are intended to be hosted inside the same region because they are diferent processes of the same module.
Let-s say that I have a Module named Inventory and it contains a view for Products, a view for Orders, etc. All of them are associated with a region named "MainRegion" and I would like to instantiate those views when user requests them, not when the module gets initialized.
In my mind, the only answer to this enigma is that Prism modules are intended to have (what I call) ONLY ONE process inside, so this way I'll end up with different modules like this:
Inventory.Products.xap
Inventory.Orders.xap
... and so on.
Is that right?
Is there any alternative that let me keep those processes together inside One module? and in this case, is this convenient?
Thanks in Advance!
Jean Paul
Prism makes a distinction between instantiating a view and displaying it. Prism 4 has a new API for displaying regions on demand, but display-on-demand can be done with older versions, as well. Unless your views are resource intensive, I'd suggest loading them at bootstrap-time, then displaying them as requested by the user.
Here are a couple of articles that should help:
Prism 4.0 Display-on-Demand
Display-on-Demand - Older Versions of Prism
Just to add to what #David said, Prism helps u logically separating different modules, and separating each view to its own module is (a) a huge overkill, and (b) a bad architecture.
good architecture is knowing how to divide & conquer the tasks of the application, which means knowing when to divide things, and sometimes even more importantly, when not to divide things.
Well, I guess I finally understand how it's supposed to work.
In order to set the grounds for this post, let's say that an application Module (not a prism module) is a collection of views (previously named Forms) and procedures related to specific activities on a business process, for example: Sales, Inventory, banking... etc.
Inside each Application module, we will find processes like Sales.Invoices, Sales.Orders, Inventory.Products, Inventory.Stocks, etc.
Now, in prism as #Elad says, create a new project for each process inside inside an Application Module may be a huge overkill, And as #David says, Prism makes a distinction between instantiating a view and displaying it.
Well, to do the right thing (which is listen to these guys), I decided to go like this:
1) Differenciate a Visual Studio project from a Prism Module:
It's not really necessary to break Application Modules into different project in your solution, all you need to do is create one project by "Application Module"
2) Create different Module Initializer Classes inside each "Application Module" project, one for each process e.g.:
For Process "A" Inside MyApplicationModule:
<ModuleExport(GetType(MyApplicationModule.ProcessAInitializer))> _
Public Class ProcessAInitializer
Implements IModule
<Import()> _
Public Property RegionManager As IRegionManager
#Region "IModule Implementation"
Public Sub Initialize()
Implements Microsoft.Practices.Prism.Modularity.IModule.Initialize
RegionManager.RegisterViewWithRegion(RegionNames.SubMenuView,
GetType(MyApplicationModule.SubMenuViewA))
RegionManager.RegisterViewWithRegion(RegionNames.ContentRegion,
GetType(MyApplicationModule.ContentViewA))
End Sub
#End Region
End Class
For Process "B" Inside MyApplicationModule:
<ModuleExport(GetType(MyApplicationModule.ProcessBInitializer))> _
Public Class ProcessBInitializer
Implements IModule
<Import()> _
Public Property RegionManager As IRegionManager
#Region "IModule Implementation"
Public Sub Initialize()
Implements Microsoft.Practices.Prism.Modularity.IModule.Initialize
RegionManager.RegisterViewWithRegion(RegionNames.SubMenuView,
GetType(MyApplicationModule.SubMenuViewB))
RegionManager.RegisterViewWithRegion(RegionNames.ContentRegion,
GetType(MyApplicationModule.ContentViewB))
End Sub
#End Region
End Class
3) Once we got this, let's change a little bit how your modulecatalog is being created on your shell project. In my case, I'm using code to add Prism Modules one by one, you could load the Modules Definition from a file but the principle is the same:
Protected Overrides Function CreateModuleCatalog() As
Microsoft.Practices.Prism.Modularity.IModuleCatalog
Dim objModuleCatalog = New ModuleCatalog
objModuleCatalog.AddModule(New ModuleInfo()
With {.InitializationMode = InitializationMode.OnDemand,
.Ref = "MyApplicationModule.xap",
.ModuleType = "MyApplicationModule.ProcessAInitializer, MyApplicationModules, Version 1.0.0.0, Culture=neutral, PublicKeyToken=null",
.ModuleName = "ProcessAInitializer"})
objModuleCatalog.AddModule(New ModuleInfo()
With {.InitializationMode = InitializationMode.OnDemand,
.Ref = "MyApplicationModule.xap",
.ModuleType = "MyApplicationModule.ProcessBInitializer, MyApplicationModule, Version 1.0.0.0, Culture=neutral, PublicKeyToken=null",
.ModuleName = "ProcessBInitializer"})
Return objModuleCatalog
End Function
Conclusion
This way, Your views will be instantiated only when user request this specific "Business Process", you don't need to split your solution into smaller parts so it take forever compiling and your solution still being "team friendly".
Thank you #David & #Elad

How to create WPF/Silverlight module utilizing prism but also that can be embedded in non-prism applicationss

I want to have create a WPF or Silverlight module which cannot only be utilised by Shell's bootstrapper, but also can be embedded in non-PRISM applications.
In short is there a way PRISM module can be intialised from module itself rather than initialsing from Shell?
Ulimate goal is to have WPF/Silverlight PRISM module, which can be initialsed by non-PRISM applications.
There is no barrier to this.
The IModule interface has a single, parameterless void method: Initialize().
A non-prism application can initialize the module by calling that method. That's it.
If the other application has a different plugin system, with a different interface, your module can implement that interface as well, and the body of whatever initialization method that interface uses can simply call Initialize(), or vice versa.
For example:
public interface IMyPluginModule
{
void StartModule();
}
public class MyModule : IModule, IMyPluginModule
{
public void Initialize()
{
// actual initialization code here
}
public void StartModule()
{
Initialize();
}
}
It's a little more complicated than it appears at first glance, but it is doable. I don't know if you are using Prism 4 yet, but if so, Microsoft actually provides guidance for this scenario:
http://msdn.microsoft.com/en-us/library/ff921109(v=PandP.40).aspx
There is a bit of project manipulation you need to do to get two projects running side-by-side. There is a sample included with Prism v4 called "MultiTargeting" if you need to see a working sample.
Your question regarding to allowing a module to be initialized by itself, rather than having the orchestrating Shell / Bootstrapper is the wrong approach, however. Essentially what you would have would be two shells... one WPF and one Silverlight. Take a look at the samples and see what you think.
Hope this helps.

How to use DataTemplates in Prism

I have been using Prism for a while now and enjoy how much easier it is to decouple my modules.
This works especially great for views and view models since you can inject the view models via interfaces and the views via the region manager.
Unfortunately this only works when my views are full blown user controls unless I'm missing something here (and I sincerely hope I am).
A lot of times though, I'll create a ViewModel and a matching DataTemplate. These can then be used by other assemblies to compose a view.
My problem is, that I see no way of referring to these datatemplates without referencing the containing assembly, so in my xaml file I write something like:
<ResourceDictionary Source="pack://application:,,/......>
Of course this is not really decoupled, although I try to make sure, that I don't refer to the assembly anywhere else in my code.
Another solution I thought of, was to put the datatemplates into the Infrastructure project, but I don't like that too much either,as I want everything that belongs to a module to be contained in it (except the interfaces of course).
So, does anyone have a good workaround, or did I miss some Prism feature?
I would suggest creating a service that encapsulates adding resource dictionaries to the Application.Resources.MergedDictionaries collection.
// Service interface (defined in the 'infrastructure' project)
public interface IResourceAggregator
{
void AddResource(Uri resourceUri);
}
// Service implementation (implemented at the application/shell level)
class ResourceAggregator : IResourceAggregator
{
public void AddResource(Uri resourceUri)
{
var resourceDictionary = new ResourceDictionary() { Source = resourceUri };
var app = Application.Current;
app.Resources.MergedDictionaries.Add(resourceDictionary);
}
}
I would expect you would "resolve" this service during module load and use it to "register" the module-local resource dictionaries.
You would need to merge the resources when the module starts. You can read more about this here: http://blogs.southworks.net/jdominguez/2008/09/presentation-model-with-datatemplates-in-compositewpf-prism-sample/
Of course you can further abstract this functionality into a reusable service.

Resources