【问题标题】:How to improve the Pass an object when navigating to a new view in PRISM 4在 PRISM 4 中导航到新视图时如何改进传递对象
【发布时间】:2012-03-09 05:04:05
【问题描述】:

我将 Prism 与 IoC 一起使用。问题是通过导航传递一个对象(如集合)。我在看这个帖子:How to Pass an object when navigating to a new view in PRISM 4

这就是解决方案

我提取对象的哈希码并保存在Dictionary中,哈希码作为键,对象作为对的值。

然后,我将哈希码附加到UriQuery

之后,我只需要在目标视图上获取来自 Uri 的哈希码,并使用它从 Dictionary 请求原始对象。

一些示例代码:

参数库类:

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

调用者代码:

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);

目标视图代码:

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);
    }
}

就是这样。

我不确定这个解决方案是否是传递对象的最佳选择。我想这可能是一项服务。是一个好方法还是有更好的方法?

【问题讨论】:

    标签: c# wpf module navigation prism


    【解决方案1】:

    我发布了一个更简单的方法。在此提及以供参考 -

    我会使用 OnNavigatedTo 和 OnNavigatedFrom 方法通过 NavigationContext 传递对象。

    首先从 INavigationAware 接口派生 viewmodel -

     public class MyViewModel : INavigationAware
     { ...
    

    然后您可以实现 OnNavigatedFrom 并将您想要作为导航上下文传递的对象设置如下 -

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

    当你想接收数据时,在第二个视图模型中添加以下代码-

    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;
                  ...
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我刚开始使用 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;
          }
      }
      

      现在在 prism 引导程序中,您需要在 ConfigureServiceLocator 方法中将 BaseRegionNavigationContentLoader 注册为 IRegionNavigationContentLoader。 确保将其标记为 TransientLifetimeManager,以便每次都会更新。 IRegionNavigationContentLoader 的默认注册是由容器控制的,这使得它就像一个单例,但我们每次都需要一个新的注册,因为我们需要将 uri 从一个方法传递到属性中的下一个方法。

      现在我可以编写如下代码,并且仍然使用构造函数注入。

      var uri = new NavigationUri("MessageBoxView");
      uri.Add(messageBoxEventArgs);
      regionManager.RequestNavigate(RegionNames.MainRegion, uri);
      

      【讨论】:

      • 这是一个超级解决方案,也许 prism 4.2 以同样的方式解决了这个问题,现在终于支持传递对象了。但我认为你只解决了 90% 的问题 (-: 是一种避免每次要检索参数时将 NavigationContext.Uri 转换为 NavigationUri 的方法。var values = ((NavigationUri)navigationContext.Uri).Values ;
      • 猜我不完全理解你的问题。在我们的应用程序中,视图创建了视图模型。因此,如果我有一个 MsgBoxView 并在它的构造函数中创建 MsgBoxVM 并且 MsgBoxVM 构造函数接受另一个类,让我们调用该类 MsgBoxOptions。我会创建一个 var uri = new NavigationUri("MsgBoxView");如果我已经创建了 MsgBoxOptions 并将其放在一个名为 msgBoxOptions 的变量中,那么我将执行 uri.Add(msgBoxOptions)。在 viewmodel 的构造函数中,MsgBoxOptions 参数将使用相同的 obj 填充。
      • 我们所做的一项改进是,当我们将 Uri 保存在 BaseRegionNavigationContentLoader 中并自动将其添加到 NavigationUri 时,还可以保存 UriQuery。因此,如果我想要 UriQuery,我可以通过将它作为参数添加到视图模型中来在构造函数中访问它。我更喜欢这种方式,而不是在定义的导航事件中捕获它。那是你要找的吗?如果是这样,我可以将代码更新为我们现在拥有的更多内容。
      猜你喜欢
      • 2011-08-03
      • 2012-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-27
      • 2011-09-21
      • 1970-01-01
      相关资源
      最近更新 更多