Как улучшить передачу объекта при переходе к новому представлению в PRISM 4 - PullRequest
3 голосов
/ 17 февраля 2012

Я использую Prism с IoC. Проблема в том, чтобы передать объект (например, коллекции) через навигацию. Я смотрел этот пост: Как передать объект при переходе к новому виду в 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);
    }
}

Вот и все.

Я не уверен, что это решение лучше всего подходит для передачи объектов. Я думаю, что это может быть услуга. Это хороший способ сделать это или есть лучший способ сделать это?

Ответы [ 2 ]

6 голосов
/ 14 декабря 2012

я выложил более простой способ. Упоминание здесь для справки -

Я бы использовал методы OnNavigatedTo и OnNavigatedFrom для передачи объектов с помощью NavigationContext.

Сначала выведите модель представления из интерфейса INavigationAware -

 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;
              ...
        }
    }
}
1 голос
/ 24 ноября 2013

Я только начал использовать 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...