2016-02-03 2 views
0

Я использую Prism 6, UWP с Unity.Экземпляр ViewModel всегда будет воссоздаваться при переключении между страницами

ViewModels будет автоматически вводиться в текстовый столбец страницы. Однако, когда я перемещаюсь между страницами, модели просмотра всегда будут воссозданы. Призывается ли это поведение Призма и Единство?

Представьте себе следующую ситуацию: пользователь вводит некоторые данные на страницу, поэтому будут установлены правильные свойства viewmodel. Когда пользователь переключается на другую страницу и пересматривает страницу, все введенные данные теряются, потому что создается новый экземпляр viewmodel.

В настоящее время мое обходное решение заключается в переопределении OnNavigatedTo и OnNavigatingFrom для сохранения всех свойств viewmodel с помощью руководства SessionStateService. Я не уверен, что это правильный путь?

Вы можете воспроизвести это поведение со следующим примером: https://github.com/PrismLibrary/Prism-Samples-Windows/tree/master/SplitViewSample/SplitViewSample

+0

Я не знаком с Prism 6, поэтому я не знаю, как он подключен, но я знаю, что Unity имеет способ контролировать время жизни экземпляров. Используйте его, чтобы настроить режим просмотра как одиночный, поэтому он не будет воссоздаваться каждый раз. –

+0

Пожалуйста, покажите код, как вы регистрируете свои представления с помощью единства и конструкторов ваших просмотров. – Jehof

+0

Я добавил URL-адрес официального примера призмы, который также получил то же поведение, которое я описал. – Briefkasten

ответ

0

Она должна быть решена, когда вы зарегистрировать ViewModels, как одиночки (ContainerControlledLifetimeManager) в UnityContainer. Лучшее место для этого было бы App.xaml.cs в методе OnInitializeAsync

protected override Task OnInitializeAsync(IActivatedEventArgs args) 
{ 
    Container.RegisterType<MyViewModel>(new ContainerControlledLifetimeManager()); 

    // rest of the method 
} 
+0

Ваше решение работает. Я пытался принять его следующим образом: ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver ((viewType) => { \t \t [...] если (Container.Registrations.Count (а => a.Name == type.Name) = = 0) { Container.RegisterInstance (тип.Name, новый ContainerControlledLifetimeManager()); } return type;}); Хотя viewmodels, зарегистрированные в UnityContainer, viewmodels не будут повторно использоваться. Есть идеи? – Briefkasten

+0

@Briefkasten 'Container.RegisterInstance (type.Name, new ContainerControlledLifetimeManager()). Это неправильно. Это зарегистрирует ContainerControlledLifetimeManager с заданным именем. – Jehof

1

Я не использую Prism, я использую модифицированную версию шаблона 10. Я только что быстрый взгляд на исходный код Prism. Похоже, что Шаблон 10 заимствовал много идей от Призма.

Я попытаюсь ответить на ваш вопрос, от 2-х точек зрения:

1) AFAIK, в Prism есть статический класс с помощью которого можно установить, как создать/разрешить просматривать модель, когда она ищется автоматически для соответствующего представления. Класс ViewModelLocationProvider, в файле ViewModelLocationProvider.cs вы можете использовать следующие методы для настройки «вид модели фабрики»

/// <summary> 
    /// Sets the default view model factory. 
    /// </summary> 
    /// <param name="viewModelFactory">The view model factory which provides the ViewModel type as a parameter.</param> 
    public static void SetDefaultViewModelFactory(Func<Type, object> viewModelFactory) 
    { 
     _defaultViewModelFactory = viewModelFactory; 
    } 

    /// <summary> 
    /// Sets the default view model factory. 
    /// </summary> 
    /// <param name="viewModelFactory">The view model factory that provides the View instance and ViewModel type as parameters.</param> 
    public static void SetDefaultViewModelFactory(Func<object, Type, object> viewModelFactory) 
    { 
     _defaultViewModelFactoryWithViewParameter = viewModelFactory; 
    } 

    /// <summary> 
    /// Registers the view model factory for the specified view type name. 
    /// </summary> 
    /// <param name="viewTypeName">The name of the view type.</param> 
    /// <param name="factory">The viewmodel factory.</param> 
    public static void Register(string viewTypeName, Func<object> factory) 
    { 
     _factories[viewTypeName] = factory; 
    } 

тогда вся логика для получения экземпляра вида модели заключается в следующем, обратите внимание на резюме комментария здесь, он описывает логику/стратегию

/// <summary> 
    /// Automatically looks up the viewmodel that corresponds to the current view, using two strategies: 
    /// It first looks to see if there is a mapping registered for that view, if not it will fallback to the convention based approach. 
    /// </summary> 
    /// <param name="view">The dependency object, typically a view.</param> 
    /// <param name="setDataContextCallback">The call back to use to create the binding between the View and ViewModel</param> 
    public static void AutoWireViewModelChanged(object view, Action<object, object> setDataContextCallback) 
    { 
     // Try mappings first 
     object viewModel = GetViewModelForView(view); 

     // Fallback to convention based 
     if (viewModel == null) 
     { 
      var viewModelType = _defaultViewTypeToViewModelTypeResolver(view.GetType()); 
      if (viewModelType == null) 
       return; 

      viewModel = _defaultViewModelFactoryWithViewParameter != null ? _defaultViewModelFactoryWithViewParameter(view, viewModelType) : _defaultViewModelFactory(viewModelType); 
     } 

     setDataContextCallback(view, viewModel); 
    } 

В строке 87 и 96 вы можете просмотреть экземпляр модели для соответствующего вида.

Так что означает, что если вы не вызываете любой из этих методов для установки на заводах, он будет падать обратно на завод по умолчанию, который

/// <summary> 
    /// The default view model factory whic provides the ViewModel type as a parameter. 
    /// </summary> 
    static Func<Type, object> _defaultViewModelFactory = type => Activator.CreateInstance(type); 

, который довольно ясно, что вы всегда получите новый пример.

Что касается единства, я не вижу ничего особенного, единственный ключ в том, что в PrismApplication классе в PrismApplication.cs, он устанавливает завод, как следующее:

/// <summary> 
    /// Configures the <see cref="ViewModelLocator"/> used by Prism. 
    /// </summary> 
    protected virtual void ConfigureViewModelLocator() 
    { 
     ViewModelLocationProvider.SetDefaultViewModelFactory((type) => Resolve(type)); 
    } 

, что означает, что завод в настоящее время использует

/// <summary> 
    /// Resolves the specified type. 
    /// </summary> 
    /// <param name="type">The type.</param> 
    /// <returns>A concrete instance of the specified type.</returns> 
    protected virtual object Resolve(Type type) 
    { 
     return Activator.CreateInstance(type); 
    } 

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

В PrismUnityApplication классе, PrismUnityApplication.cs, он предлагает реализацию по умолчанию для разрешения экземпляра с Unity

/// <summary> 
    /// Implements the Resolves method to be handled by the Unity Container. 
    /// Use the container to resolve types (e.g. ViewModels and Flyouts) 
    /// so their dependencies get injected 
    /// </summary> 
    /// <param name="type">The type.</param> 
    /// <returns>A concrete instance of the specified type.</returns> 
    protected override object Resolve(Type type) 
    { 
     return Container.Resolve(type); 
    } 

и да, как упоминалось другие ребята, вы можете контролировать время жизни ваших моделей просмотреть себя с помощью Unity.

2) извините за длинный ответ , но я чувствую, что лучше показать вам какой-то код, который прояснит ситуацию. Я буду держать второй короткий.

На мой взгляд, вам не нужна модель просмотра, когда ваше представление исчезло. Я не уверен, как стек кадров реализован в UWP и как они управляют экземплярами view/page. Я бы предположил, что когда вы переходите на другую страницу, предыдущий просмотр/страница должен быть выпущен или может быть выпущен в GC, и у вас есть параметр и тип страницы, чтобы иметь возможность перемещаться назад, но это будет новый экземпляр, и вы восстановите состояние своего вида, восстановив модель просмотра.

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

Спасибо за чтение.

Смежные вопросы