Я только начал использовать Prism, и это одно из первых ограничений, с которыми я столкнулся. Я решил это по-другому. Сначала я создал класс, который наследуется от Uri и реализует IDictionary (а также несколько универсальных методов для более легкого доступа)
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();
}
}
Затем я создал класс, который наследуется от RegionNavigationContentLoader. На GetContractFromNavigationContext я сохраняю переданный в Uri, чтобы я мог получить к нему доступ в методе CreateNewRegionItem. В этом методе я проверяю, является ли Uri NavigationUri, и если да, я делаю цикл, добавляя все переопределения внедрения зависимостей. Я использую Unity, но я предполагаю, что код может быть легко преобразован в другой контейнер IOC.
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
{
// Create injection overrides for all the types in the uri
var depoverride = new DependencyOverrides();
foreach (var supplant in uri)
{
depoverride.Add(supplant.Key, supplant.Value);
}
instance = _unityContainer.Resolve<object>(candidateTargetContract, depoverride);
}
}
catch (ActivationException exception)
{
throw new InvalidOperationException(string.Format(System.Globalization.CultureInfo.CurrentCulture, "CannotCreateNavigationTarget", new object[] { candidateTargetContract }), exception);
}
return instance;
}
}
Теперь в загрузочном призме призмы необходимо зарегистрировать BaseRegionNavigationContentLoader как IRegionNavigationContentLoader в методе ConfigureServiceLocator. Убедитесь, что вы отметили его как TransientLifetimeManager, чтобы он обновлялся каждый раз . Регистрация по умолчанию для IRegionNavigationContentLoader контролируется контейнером, что делает его действующим как одноэлементный, но нам каждый раз нужен новый, так как нам нужно передавать uri от одного метода к другому в свойстве.
Теперь я могу написать код, подобный следующему, и все еще использовать инжектор конструктора.
var uri = new NavigationUri("MessageBoxView");
uri.Add(messageBoxEventArgs);
regionManager.RequestNavigate(RegionNames.MainRegion, uri);