Simple Prism Bootstrapper - c#

im currently porting my program to using Prism 6, it's a WPF application.
So i installed Prism.Unity (6.1.1) which came with Prism.Wpf (6.1.0), Prism.Core (6.1.0), Unity (4.0.1) and CommonServiceLocator (1.3.0).
Then i came along those PRISM samples, but for the love of god i can't get it to run.
Here's my Bootstrapper:
public class Bootstrapper : Prism.Unity.UnityBootstrapper
{
/// <exception cref="ActivationException">If there are errors resolving the shell instance.</exception>
protected override DependencyObject CreateShell()
{
return Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
this.RegisterTypeIfMissing(typeof(IWorkRepository), typeof(WorkRepository), true);
}
}
Unfortunately i can't start it. VS 2015 says it needs System.Runtime to run
return Container.Resolve<Shell>();
but once added the whole class is marked as error. If i start it directly i get the exception it couldn't load Microsoft.Practices.ServiceLocation.
I'm wondering of the dependency since several posts (including ms) suggests to remove all Practices.*.
Help would be really appreciated, since i can't get it to run. :(

What usings do you use?
The whole bootstrapper can be as simple as this (created by the Prism-template):
using Microsoft.Practices.Unity;
using Prism.Unity;
using PrismUnityApp2.Views;
using System.Windows;
namespace PrismUnityApp2
{
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
}
}
and System.Runtime isn't needed as reference. Probably you inadvertently use a namespace from that (instead of Microsoft.Practices.Unity where the Container.Resolve<> extension is).

Related

Xamarin OnLaunched event

I'm looking to create styles (and eventually some of the pages) using C# code behind. Was looking at the write up on https://learn.microsoft.com/en-us/windows/apps/design/style/xaml-resource-dictionary and when I duplicate that code it gives me an error that LaunchActivatedEventArgs is unknown.
My starting App.xaml.cs file:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace FieldDataTemplateSelectorSample
{
sealed partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// add styles here
}
}
}
It doesn't know the type or namespace for LaunchActivatedEventArgs. If I look at the list of potential fixes, it suggests that I add a using for Windows.ApplicationModel.Activation to the list of usings. If I do that, then it complains about OnLaunched not having a suitable method to override. If I take out the override, and change the signature to
using System;
using Windows.ApplicationModel.Activation;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using FieldDataTemplateSelectorSample.AppStyles;
namespace FieldDataTemplateSelectorSample
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
protected void OnLaunched(LaunchActivatedEventArgs e)
{
Resources = InitStyles.GetAppStyles();
}
}
}
The application compiles but the OnLaunched method never gets hit if I put a break point in there. What am I missing? Right now I'm using a UWP project for getting my feet wet, and eventually will add android and ios.
Thanks
OnLaunched is a Windows or UWP API, not a Xamarin API.
Put your code in OnStart instead.
For cross-platform code, find "Windows.Forms" docs, instead of "Windows App Development" docs.
OR sometimes you'll want code in your .UWP or .Windows project - but I don't think this is one of those situations.

Prism with Unity wrong instance gets passed into constructor

I am trying to understand/learn Prism with Unity
I created following classes:
==========================================
Seperate Assembly containing a "Module":
using GlobalContracts;
using Prism.Ioc;
using Prism.Modularity;
namespace ModuleA
{
[Module(ModuleName = MyModuleA.NAME, OnDemand = true)]
public class MyModuleA : IModule
{
public const string NAME = "MyModuleA";
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<MyControlA>();
containerRegistry.Register<IView, MyControlA>(NAME);
containerRegistry.Register<PluginViewModelBase, MyControlViewModel>(NAME);
}
public void OnInitialized(IContainerProvider containerProvider)
{
}
}
}
==========================================
A ViewModel
using GlobalContracts;
namespace ModuleA
{
public class MyControlViewModel : PluginViewModelBase
{
public MyControlViewModel(IView view) : base(view)
{
}
}
}
==========================================
The Host Application (other assembly):
public partial class App : PrismApplication
{
private Shell mShell;
private ShellViewModel mShellViewModel;
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog(){ModulePath = #"..\..\..\..\ModulesOutput"};
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<IView, Shell>();
containerRegistry.Register<IViewModel, ShellViewModel>();
}
protected override Window CreateShell()
{
mShellViewModel = Container.Resolve<ShellViewModel>();
mShell = (Shell)mShellViewModel.View;
return mShell;
}
(...)
Now my question is:
How do I tell Prism to resolve the IView-Parameter passed to the
constructor of the ViewModel properly?
It resolves it as "Shell" and not as "MyControlA".
Further tips regarding my code are welcome
I found some sources in the web but they used "RegisterType" method of a container. And for now I do not have dependencies to Unity in my ModuleA and I would not know how to get the container to call the "RegisterType". All sources are outdated in the web..
By default, it resolves the default registration, which in your case is Shell.
Registering a type with a name does not mean that that name is automatically used to resolve dependencies. You have to do that manually, with parameter override, injection factory or the like. But I'd try to avoid that as it makes things a bit fragile and tedious.

Prism - Unity - Can't resolve IRegionBehaviorFactory in ConfigureRegionAdapterMappings

i'm new to Prism, i have an application and i need to have a custom region mapping.
when i try to resolve IRegionBehaviorFactory with ServiceLocator, i receive the error :
Activation error occurred while trying to get instance of type IRegionBehaviorFactory, key ""
I understand that is because the class RegionBehaviorFactory receive Microsoft.Practices.Unity.IServiceLocator, but with Unity 7.0 i use as ServiceLocator Unity.ServiceLocation.UnityServiceLocator
How can i do?
This is my bootstrapper.cs
class Bootstrapper : UnityBootstrapper
{
private UnityContainer uc = new UnityContainer();
protected override void ConfigureServiceLocator()
{
base.ConfigureServiceLocator();
UnityServiceLocator locator = new UnityServiceLocator(uc);
ServiceLocator.SetLocatorProvider(() => locator);
}
protected override DependencyObject CreateShell()
{
return ServiceLocator.Current.GetInstance<wMain>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow = (wMain)this.Shell;
Application.Current.MainWindow.Show();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
protected override void InitializeModules()
{
base.InitializeModules();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
uc.RegisterType<IServiceLocator, UnityServiceLocator>();
uc.RegisterType<IRegionBehaviorFactory, RegionBehaviorFactory>();
Application.Current.Resources.Add("IoC", uc);
}
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
var mappings = base.ConfigureRegionAdapterMappings();
var aa = ServiceLocator.Current.GetInstance<IRegionBehaviorFactory>();
mappings.RegisterMapping(typeof(RadPaneGroup), new RadPaneGroupRegionAdapter(uc.Resolve<RegionBehaviorFactory>()));
return mappings;
}
}
Thanks
Why are you creating anew container and service locator? That class is all wrong. You don't need to create those as the container with all services has already been created for you. That's why you're using the UnityBootstrapper. The ServiceLocator is also already setup for you.
You should go through these samples to better understand hwo to use Prism: https://github.com/PrismLibrary/Prism-Samples-Wpf
Another bit of advice, don't use the ServiceLocator like you are. That's bad practice. Stick with common DI patterns and resolve objects usin ctor injectin or by resolving objects from your container.

How to register types by convention using Unity with Prism?

I have a WPF app that uses the Prism.Wpf and Prism.Unity NuGet packages (both 6.3.0). I'm currently registering types in the Unity container manually in a bootstrapper class (see below) and everything is working great.
internal class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
// Register types
Container.RegisterType<IDialogService, DialogService>(new ContainerControlledLifetimeManager());
}
}
However, when I try to register types by convention, I get a Microsoft.Practices.Unity.DuplicateTypeMappingException when registering the types in the Unity container.
The register by convention code:
protected override void ConfigureContainer()
{
base.ConfigureContainer();
// Register types by convention
Container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled);
}
Exception message:
An attempt to override an existing mapping was detected for type Prism.Regions.IRegionNavigationContentLoader with name "", currently mapped to type Prism.Unity.Regions.UnityRegionNavigationContentLoader, to type Prism.Regions.RegionNavigationContentLoader.
How do I register types by convention when using Prism & Unity?
Just swap Container.RegisterTypes(...); and base.ConfigureContainer();
The UnityBootstrapper will only register types that weren't registered before, so you should be fine.

Caliburn.Micro can't match View and ViewModel from different assemblies

I just started with Caliburn.Micro.
I'm trying to bootstrap my simple sample solution placing the ShellView (usercontrol) in an Test.App assembly, and the ShellViewModel in the Test.ViewModel assembly.
What i get is a window with the following text: "Cannot find view for Caliburn.Test.ViewModel.ShellViewModel".
But if I move the ViewModel to the .App assembly, it works perfectly.
this is the Bootstraper in the Caliburn.Micro.Test assembly (executable):
namespace Caliburn.Micro.Test
{
public class AppBootstrapper : BootstrapperBase
{
SimpleContainer container;
public AppBootstrapper()
{
this.Start();
}
protected override void Configure()
{
container = new SimpleContainer();
this.container.Singleton<IWindowManager, WindowManager>();
this.container.Singleton<IEventAggregator, EventAggregator>();
this.container.PerRequest<IShell, ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
var instance = this.container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return this.container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
this.container.BuildUp(instance);
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
this.DisplayRootViewFor<IShell>();
}
protected override IEnumerable<System.Reflection.Assembly> SelectAssemblies()
{
var assemblies = new List<Assembly>()
{
Assembly.GetExecutingAssembly(),
Assembly.Load("Caliburn.Micro.Test.ViewModel"),
};
return assemblies;
}
}
}
this is my ViewModel in the Caliburn.Micro.Test.ViewModel assembly (class library):
namespace Caliburn.Micro.Test.ViewModel
{
public interface IShell
{
}
public class ShellViewModel : IShell
{
}
}
Can you help me solve my problem, please?
Thank you! :D
Check that you have selected your assembly for CM by overriding SelectAssemblies in your bootstrapper.
The documentation here has an example:
http://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[] {
Assembly.GetExecutingAssembly()
};
}
Edit:
Ok not only do you need to select assemblies to tell CM where to look - it sounds like in your case your VMs and your Views may be in different namespaces since you have them in separate libraries. You can use the same root namespace in both libraries and the standard view resolution should work fine - however, you need to make sure you have selected the assembly in the bootstrapper in order to tell CM what assemblies to try to resolve views in.
If you want to put your views/VMs in different namespaces for some reason or another, you need to customise the logic that CM uses to resolve a view. It uses naming conventions to locate a View based on the fully qualified type name of the viewmodel (or vice-versa if you are using a view-first approach)
I suggest reading up on the introductory documentation:
http://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation
Then follow it through. If you want to skip directly to naming conventions, check out this particular page:
http://caliburnmicro.codeplex.com/wikipage?title=View%2fViewModel%20Naming%20Conventions&referringTitle=Documentation
and
http://caliburnmicro.codeplex.com/wikipage?title=Handling%20Custom%20Conventions&referringTitle=Documentation
Solved thanks to this article
http://www.jerriepelser.com/blog/split-views-and-viewmodels-in-caliburn-micro/
EDIT: since you integrated your reply with mine I change the accepted answer to be yours.

Categories