I just started using Prism, and this is one of the first limitations that I encountered. I decided it differently. First I created a class that inherits from Uri and implements IDictionary (plus some common methods for easier access)
public class NavigationUri : Uri, IDictionary<Type, object> { private IDictionary<Type, object> _internalDictionary = new Dictionary<Type, object>(); public NavigationUri(string uriString) : base(uriString, UriKind.Relative) { } public NavigationUri(string uriString, UriKind uriKind) : base(uriString, uriKind) { } public void Add<T>(T value) { Add(typeof(T), value); } public void Add(Type key, object value) { _internalDictionary.Add(key, value); } public bool ContainsKey<T>() { return ContainsKey(typeof (T)); } public bool ContainsKey(Type key) { return _internalDictionary.ContainsKey(key); } public ICollection<Type> Keys { get { return _internalDictionary.Keys; } } public bool Remove<T>() { return Remove(typeof (T)); } public bool Remove(Type key) { return _internalDictionary.Remove(key); } public bool TryGetValue<T>(out object value) { return TryGetValue(typeof (T), out value); } public bool TryGetValue(Type key, out object value) { return _internalDictionary.TryGetValue(key, out value); } public ICollection<object> Values { get { return _internalDictionary.Values; } } public object this[Type key] { get { return _internalDictionary[key]; } set { _internalDictionary[key] = value; } } public void Add(KeyValuePair<Type, object> item) { _internalDictionary.Add(item); } public void Clear() { _internalDictionary.Clear(); } public bool Contains(KeyValuePair<Type, object> item) { return _internalDictionary.Contains(item); } public void CopyTo(KeyValuePair<Type, object>[] array, int arrayIndex) { _internalDictionary.CopyTo(array, arrayIndex); } public int Count { get { return _internalDictionary.Count; } } public bool IsReadOnly { get { return _internalDictionary.IsReadOnly; } } public bool Remove(KeyValuePair<Type, object> item) { return _internalDictionary.Remove(item); } public IEnumerator<KeyValuePair<Type, object>> GetEnumerator() { return _internalDictionary.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _internalDictionary.GetEnumerator(); } }
Then I created a class that inherits from RegionNavigationContentLoader. In GetContractFromNavigationContext, I store the passed in Uri, so I can access it in the CreateNewRegionItem method. In this method, I check if Uri is NavigationUri, and if so, then I loop, adding all injection dependency overrides. I am using Unity, but I assume that the code can be easily converted to another IOC container.
public class BaseRegionNavigationContentLoader : RegionNavigationContentLoader { private Uri _uri; private IServiceLocator _serviceLocator; private IUnityContainer _unityContainer; public BaseRegionNavigationContentLoader(IServiceLocator serviceLocator, IUnityContainer unityContainer) : base(serviceLocator) { _serviceLocator = serviceLocator; _unityContainer = unityContainer; } protected override string GetContractFromNavigationContext(NavigationContext navigationContext) { _uri = navigationContext.Uri; return base.GetContractFromNavigationContext(navigationContext); } protected override object CreateNewRegionItem(string candidateTargetContract) { object instance; try { var uri = _uri as NavigationUri; if (uri == null) { instance = _serviceLocator.GetInstance<object>(candidateTargetContract); } else {
Now in Bootstrapper, you need to register BaseRegionNavigationContentLoader as IRegionNavigationContentLoader in the ConfigureServiceLocator method. Make sure you mark it as TransientLifetimeManager so that it is updated every time . The default registration for IRegionNavigationContentLoader is controlled by the container, which makes it act as a singleton, but each time we need a new one, since we need to pass the uri from one method to the next in the property.
Now I can write code similar to the following and still use constructor injection.
var uri = new NavigationUri("MessageBoxView"); uri.Add(messageBoxEventArgs); regionManager.RequestNavigate(RegionNames.MainRegion, uri);