How to improve object transfer when navigating to a new view in PRISM 4

I am using Prism with IoC. The problem is to pass an object (e.g. collections) through navigation. I watched this post: How to pass an object when navigating to a new view in PRISM 4

And this decision

I extract the hash code of the object and save it in the Dictionary , and the hash code as the key, and the object as the value of the pair.

Then I attach the hash code to UriQuery .

After that, I need to get the hash code that comes from Uri in the target view, and use it to query the source object from Dictionary .

Code example:

Parameter Repository Class:

 public class Parameters { private static Dictionary<int, object> paramList = new Dictionary<int, object>(); public static void save(int hash, object value) { if (!paramList.ContainsKey(hash)) paramList.Add(hash, value); } public static object request(int hash) { return ((KeyValuePair<int, object>)paramList. Where(x => x.Key == hash).FirstOrDefault()).Value; } } 

Caller Code:

 UriQuery q = null; Customer customer = new Customer(); q = new UriQuery(); Parameters.save(customer.GetHashCode(), customer); q.Add("hash", customer.GetHashCode().ToString()); Uri viewUri = new Uri("MyView" + q.ToString(), UriKind.Relative); regionManager.RequestNavigate(region, viewUri); 

Target View Code:

 public partial class MyView : UserControl, INavigationAware { // some hidden code public void OnNavigatedTo(NavigationContext navigationContext) { int hash = int.Parse(navigationContext.Parameters["hash"]); Customer cust = (Customer)Parameters.request(hash); } } 

What is it.

I am not sure that this decision is best conveyed. I think it could be a service. Is this a good way to do this, or is there a better way to do this?

+3
source share
2 answers

I posted an easier way. Mentioning him here for reference -

I would use the OnNavigatedTo and OnNavigatedFrom methods to transfer objects using the NavigationContext.

First output the model with the INavigationAware interface -

  public class MyViewModel : INavigationAware { ... 

Then you can implement OnNavigatedFrom and set the object you want to pass as a navigation context, as follows -

 void INavigationAware.OnNavigatedFrom(NavigationContext navigationContext) { SharedData data = new SharedData(); ... navigationContext.NavigationService.Region.Context = data; } 

and when you want to get the data, add the following code snippet to the second view model -

 void INavigationAware.OnNavigatedTo(NavigationContext navigationContext) { if (navigationContext.NavigationService.Region.Context != null) { if (navigationContext.NavigationService.Region.Context is SharedData) { SharedData data = (SharedData)navigationContext.NavigationService.Region.Context; ... } } } 
+6
source

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 { // 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; } } 

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); 
+1
source

Source: https://habr.com/ru/post/1396947/


All Articles