how to add many regions into mef container - c#

i am trying to register multiple regions to my region like in Unity:
public class ModuleA : IModule
{
private IUnityContainer _container;
private IRegionManager _regionManager;
public ModuleA(IUnityContainer container, IRegionManager regionManager)
{
_container = container;
_regionManager = regionManager;
}
public void Initialize()
{
IRegion region = _regionManager.Regions[RegionNames.ToolbarRegion];
region.Add(_container.Resolve<ToolbarView>());
region.Add(_container.Resolve<ToolbarView>());
region.Add(_container.Resolve<ToolbarView>());
region.Add(_container.Resolve<ToolbarView>());
region.Add(_container.Resolve<ToolbarView>());
}
}
}
but i can't succeed to do it with MEF
[ModuleExport(typeof(ModuleAModule))]
public class ModuleAModule : IModule
{
[Import]
private IRegionManager _regionManager;
public void Initialize()
{
_regionManager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(ContentView));
IRegion region = _regionManager.Regions[RegionNames.ToolbarRegion];
}
}
i can get the region, but i don't know how to translate the resolving into MEF.

Related

What is difference between Container.Resolve<View>() and new View()?

Now I'm practicing Prism with "Prism-Samples-Wpf" in Github.
(https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/06-ViewActivationDeactivation)
This code is part of MainWindow.xaml.cs
public partial class MainWindow : Window
{
IContainerExtension _container;
IRegionManager _regionManager;
IRegion _region;
ViewA _viewA;
ViewB _viewB;
public MainWindow(IContainerExtension container, IRegionManager regionManager)
{
InitializeComponent();
_container = container;
_regionManager = regionManager;
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_viewA = new ViewA();
_viewB = _container.Resolve<ViewB>();
_region = _regionManager.Regions["ContentRegion"];
_region.Add(_viewB);
_region.Add(_viewA);
}
}
there return same type like this.
(1) new ViewA(); // ActivationDeactivation.Views.ViewA
(2) _container.Resolve<ViewB>(); // ActivationDeactivation.Views.ViewB
What is difference between Container.Resolve() and new ViewA()?
What is difference between Container.Resolve<ViewA>() and new ViewA()?
Nothing really (besides new always returning a new instance, while ViewA might be registered as singleton).
But imagine new SomeService( aDependency, new AnotherDependency(), () => new SomeProduct( new ThirdDependency(), aDependency ) as opposed to Container.Resolve<SomeService>()...
Unity, or any DI-container, that is, just makes life easier when creating instances. Sure, you can do everything by hand, you don't have to. Be careful, though - you should not inject the container. Rather inject a factory, if you have to create instances on the fly.
Example of what MainWindow could look like:
public partial class MainWindow : Window
{
private readonly Func<ViewA> _viewAFactory;
private readonly Func<ViewB> _viewABFactory;
IRegionManager _regionManager;
IRegion _region;
ViewA _viewA;
ViewB _viewB;
public MainWindow(Func<ViewA> viewAFactory, Func<ViewB> viewBFactory, IRegionManager regionManager)
{
InitializeComponent();
_viewAFactory = viewAFactory;
_viewBFactory = viewBFactory;
_regionManager = regionManager;
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_viewA = _viewAFactory();
_viewB = _viewBFactory();
_region = _regionManager.Regions["ContentRegion"];
_region.Add(_viewB);
_region.Add(_viewA);
}
}
All of this should really happen in MainWindowViewModel, though. Have a look ViewModelLocator for a very simple way to make your views magically create their view models (properly resolved with all the dependencies).

StructureMap | How to create a singleton instance / get always the same instance

I have a class UserManagement and always want to get the same instance (like singleton pattern). So my problem is now, that I always get a new instance insted of the named "Singleton". I'm new to StructureMap. I have tried both version (http://structuremap.github.io/object-lifecycle/) (http://structuremap.github.io/glossary/) described on the website.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Container container = new Container(new UserManagement());
//UserManagement instance = container.GetInstance<UserManagement>("Singleton");
UserManagement instance = container.GetInstance<UserManagement>();
MessageBox.Show(instance.Test);
}
}
public interface IUser
{
void DoSomethingFancy();
}
public class User : IUser
{
public void DoSomethingFancy()
{
}
}
public interface IDatabase
{
void DoSomething();
}
public class Database : IDatabase
{
public void DoSomething()
{
}
}
public class UserManagement : Registry
{
public string Test;
private Container _Container;
private IUser _User;
private IDatabase _Database;
public UserManagement()
{
_Container = new Container(_ =>
{
_.For<IUser>().Use<User>();
_.For<IDatabase>().Use<Database>();
});
_User = _Container.GetInstance<IUser>();
_Database = _Container.GetInstance<IDatabase>();
Test = DateTime.Now.ToString();
//For<UserManagement>().AddInstances(x =>
//{
// x.Type<UserManagement>().Named("Singleton");
//});
For<UserManagement>().Singleton();
}
}
Update
My solution has 3 projects
BootstrapperLibrary (class library - Bootstrapper)
Gui (WpfApp - MainWindow.xaml)
Framework (class library - LoginAction - UserManagement)
BootstrapperLibrary
Bootstrapper.cs
public static class Bootstrapper
{
public static Container Container => _Container ?? (_Container = InitializeContainer());
private static Container _Container;
public static Func<Container> InitializeContainer;
}
Gui
App.xaml.cs
public partial class App : Application
{
public App()
{
Bootstrapper.InitializeContainer += InitializeContainer;
}
private Container InitializeContainer()
{
Container container = new Container(c => c.Scan(scanner =>
{
scanner.TheCallingAssembly();
scanner.WithDefaultConventions();
scanner.AssembliesFromApplicationBaseDirectory();
}));
container.Configure(c =>
{
c.ForSingletonOf<UserManagement>();
c.For<IUser>().Use<UserAdv>();
}
);
return container;
}
}
MainWindow.xaml
<Window x:Class="Gui.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:myFramework="clr-namespace:MyFramework;assembly=MyFramework"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="383,228,0,0" VerticalAlignment="Top" Width="75">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<myFramework:LoginAction/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</Window>
Framework
LoginAction.cs
public class LoginAction : TriggerAction<DependencyObject>
{
protected override void Invoke(object parameter)
{
UserManagement userManagement = Bootstrapper.Container.GetInstance<UserManagement>();
Console.WriteLine(userManagement.Test); //Just to see if it's still the same instance who holds for example the current user.
}
}
UserManagement.cs
public interface IUser
{
string Name { get; }
void DoSomethingFancy();
}
public class User : IUser
{
public string Name { get; } = "default";
public void DoSomethingFancy()
{
}
}
public class UserAdv : IUser
{
public string Name { get; } = "Advanced";
public void DoSomethingFancy()
{
}
}
public interface IDatabase
{
void DoSomething();
}
public class Database : IDatabase
{
public void DoSomething()
{
}
}
public class UserManagement
{
public string Test;
public IUser User;
private IDatabase _Database;
public UserManagement(IUser user, IDatabase database)
{
User = user;
_Database = database;
Test = DateTime.Now.ToString();
}
}
If I understood correctly, my main application now initializes and configures the Container within the application startup. The Bootstrapper class is holding a static instance there. MyFramework fetches an instance of UserManangement from the static Container instance.
Is this the correct way how to use StructureMap? Thank you for your patience!
You should declare:
ForConcreteType<UserManagement>().Singleton();
Edit:
You may implement a bootstrapper class and call the Initialize() method during program startup:
public sealed class Bootstrapper
{
private static StructureMap.Container _container;
public StructureMap.Container MyContainer
{
get { return _container; }
}
static Bootstrapper()
{
}
public static Initialize()
{
StructureMap.Configuration.DSL.Registry registry = new StructureMap.Configuration.DSL.Registry();
registry.For<IUser>().Use<User>();
registry.For<IDatabase>().Use<Database>();
registry.ForConcreteType<UserManagement>().Singleton();
_container = new Container(registry);
}
}
Remove the container initialization from the UserManagement class and let the DI framework inject the concrete types/objects.
public class UserManagement
{
public string Test;
private IUser _user;
private IDatabase _database;
public UserManagement(IUser user, IDatabase database)
{
_user = user;
_database = database;
Test = DateTime.Now.ToString();
}
}
Modify your WPF test window:
public partial class MainWindow : Window
{
static MainWindow()
{
// only for demonstration!!!
Bootstrapper.Initialize();
}
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Container container = Bootstrapper.MyContainer;
UserManagement instance = container.GetInstance<UserManagement>();
MessageBox.Show(instance.Test);
}
}

Switch View in different Modules using Prism and Unity

I want to navigate from ModuleA View to ModuleB View. How can I implement navigation between modules?
In my application which uses Prism framework, I have two module
ModuleA
ModuleB
I configure two modules in my Bootstrapper like this:
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
moduleCatalog.AddModule(typeof(ModuleA));
moduleCatalog.AddModule(typeof(ModuleB));
}
I register my both Views in my ModuleA and ModuleB like this:
public class ModuleA : IModule
{
private readonly IRegionManager regionManager;
private readonly IUnityContainer container;
public StaffModule(IUnityContainer container, IRegionManager regionManager)
{
this.container = container;
this.regionManager = regionManager;
}
public void Initialize()
{
this.regionManager.RegisterViewWithRegion("MainRegion", () => this.container.Resolve<StaffView>());
}
}
public class AccountModule : IModule
{
private readonly IRegionManager regionManager;
private readonly IUnityContainer container;
public AccountModule(IUnityContainer container, IRegionManager regionManager)
{
this.container = container;
this.regionManager = regionManager;
}
public void Initialize()
{
container.RegisterType<object, AccountView>("AccountView");
////this.regionManager.RegisterViewWithRegion("MainRegion", () => this.container.Resolve<AccountView>());
}
}
When I click Button from StaffView in ModuleA, I want to navigate to AccountView in ModuleB. Here is my code for navigation.
private void LodeViewfromModule()
{
IUnityContainer unityContainer = ServiceLocator.Current.GetInstance<IUnityContainer>();
var regionManager=unityContainer.Resolve<IRegionManager>();
var uri = new Uri("pack://application:,,,/PrismAuto.Account;component/AccountView.xaml", UriKind.RelativeOrAbsolute);
regionManager.RequestNavigate("MainRegion", uri);
}
But it shows:
System.Object exception.
Please, anyone help me to solve this problem.
You are registering your view for navigation using:
container.RegisterType<object, AccountView>("AccountView");
and navigating to it like:
var uri = new Uri("pack://application:,,,/PrismAuto.Account;component/AccountView.xaml", UriKind.RelativeOrAbsolute);
regionManager.RequestNavigate("MainRegion", uri);
This is wrong. You need to navigate to it using the key your provided when you registered it for navigation:
regionManager.RequestNavigate("MainRegion", "AccountView");
Also, if you are using Prism 6 there is an extension method in the Prism.Unity namespace for registering your views for navigation like this:
container.RegisterTypeForNavigation<AccountView>();

Showing Prism modules inside Prism Module

I am implementing application in PRISM, which need to import modules dynamically from dll files.
I managed to do that - they are importing, but I can't display it.
I decided to create a special module to encapsulate it - let us call it ModuleDock.
So we have something like that:
Bootstrapper.cs:
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)Shell;
Application.Current.MainWindow.Show();
}
protected override IModuleCatalog CreateModuleCatalog()
{
var modules = new DirectoryModuleCatalog
{
LoadSubdirectories = true,
ModulePath = #"C:\Modules"
};
modules.AddModule(typeof(ModuleDockModule));
return modules;
}
}
Shell.xaml:
<ContentControl regions:RegionManager.RegionName="ModuleDockModule" />
ModuleDockModule.cs (in ModuleDock project):
public class ModuleDockModule : IModule
{
private readonly IRegionManager _regionManager;
private readonly IUnityContainer _unityContainer;
public void Initialize()
{
RegisterIoc();
if (_regionManager.Regions.ContainsRegionWithName("ModuleDockModule"))
{
_regionManager.RegisterViewWithRegion("ModuleDockModule", typeof(ModuleDockView));
}
}
public ModuleDockModule(IRegionManager regionManager, IUnityContainer unityContainer, IRegionViewRegistry regionViewRegistry)
{
_regionManager = regionManager;
_unityContainer = unityContainer;
}
private void RegisterIoc()
{
_unityContainer.RegisterType<IModuleDockView, ModuleDockView>();
_unityContainer.RegisterType<IModuleDockViewModel, ModuleDockViewModel>();
}
}
and finally in one of loaded modules:
[Module(ModuleName = "TestModule", OnDemand = false)]
public class TestModuleModule : IModule
{
private readonly IRegionManager _regionManager;
private readonly IUnityContainer _unityContainer;
public void Initialize()
{
RegisterIoc();
if (_regionManager.Regions.ContainsRegionWithName("TestModule"))
{
_regionManager.RegisterViewWithRegion("TestModule", typeof(TestView));
}
}
public TestModuleModule(IRegionManager regionManager, IUnityContainer unityContainer)
{
_regionManager = regionManager;
_unityContainer = unityContainer;
}
private void RegisterIoc()
{
_unityContainer.RegisterType<ITestView, TestView>();
_unityContainer.RegisterType<ITestViewModel, TestViewModel>();
}
}
For test purposes I've created that line of XAML:
<ContentControl regions:RegionManager.RegionName="TestModule" />
Could you tell me, why that line displays TestModule in Shell.xaml, but don't display it in ModuleDockView.xaml?
Please, mind that in final stage I have to use various number of unknown modules provided by other users of my platform, so I can't make anything static (like module names or initializations).
Thank you in advance!
Based on the code you described, the TestModule module has a module dependency with ModuleDockModule as this is defining the region that the TestModule's Views would then be registered into.
Therefore, you would need to make sure that ModuleDockModule is initialized before TestModule and any other module that would depend on it. In order to do this, you would need to declare a dependency attribute on TestModuleModule class, right above the class definition as follows:
[Module(ModuleName = "TestModule", OnDemand = false)]
[ModuleDependency("ModuleDockModule")]
public class TestModuleModule : IModule
{ ...
For more information about Moduled you may refer to the following MSDN Prism Guide chapter:
Modular Application Development
I hope this helped you, Regards.

PRISM View Injection/Navigation in Same Module

This is ModuleInit.cs in Products module
public class ModuleInit : IModule
{
private readonly IUnityContainer _container;
private readonly IRegionManager _regionManager;
public ModuleInit(IUnityContainer container, IRegionManager regionManager)
{
_container = container;
_regionManager = regionManager;
}
#region IModule Members
public void Initialize()
{
App app = (App)Application.Current;
_regionManager.RegisterViewWithRegion(RegionNames.ModuleRegionProducts, () => _container.Resolve<Views.ProductsCycle>());
}
#endregion
}
Below is button event handler in ProductsCycle.cs to go to another view still within same module:
private void btnForward_Click(object sender, RoutedEventArgs e)
{
IRegion productsRegion = _regionManager.Regions["ModuleRegionProducts"];
var productsListView = _container.Resolve<Views.ProductsList>();
productsRegion.Add(productsListView, "ProductsList");
productsRegion.Activate(productsListView);
}
State: ProductsCycle page is successfully loaded on first load.
Problem: View doesn't changed from ProductCycle page to ProductsList page when btnForward is clicked.
I'm using Silverlight 4 and PRISM2.
Please your advice, thank you.
change productsRegion.Activate(productsListView);
to productsRegion.Remove(this);
because my productListView is not inherited directly from UserControl.

Categories

Resources