我用的是Prism 6,UWP和Unity。
ViewModels将自动注入到页面的数据文本中。但是,当我在页面之间导航时,将始终重新创建视图模型。这种行为是由棱镜和统一所要求的吗?
假设以下场景,用户在页面中输入一些数据,因此将设置视图模型的适当属性。当用户切换回另一个页面并重新访问该页时,由于创建了一个新的视图模型实例,所有输入的数据都丢失了。
目前,我的解决方法是覆盖OnNavigatedTo和OnNavigatingFrom,用SessionStateService手册保存视图模型的所有属性。我不确定这是不是正确的方法?
您可以使用以下示例再现此行为:https://github.com/PrismLibrary/Prism-Samples-Windows/tree/master/SplitViewSample/SplitViewSample
发布于 2016-02-03 11:38:40
当您将ViewModels注册为UnityContainer中的单例(ContainerControlledLifetimeManager)时,应该解决这个问题。最好的方法是App.xaml.cs in method OnInitializeAsync。
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
Container.RegisterType<MyViewModel>(new ContainerControlledLifetimeManager());
// rest of the method
}发布于 2016-02-03 11:44:35
我没有使用Prism,我使用的是修改版的模板10,我只是快速地看了一下Prism源代码。看起来模板10从棱镜中借用了很多想法。
我试着从两个角度回答你的问题:
1) AFAIK,在Prism中有一个静态类,当自动查找相应的View时,您可以用它来设置如何创建/解析视图模型。类是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);
}是的,就像其他人提到的,你可以通过团结来控制你的观点模型的生命周期。
2)很抱歉回答得太长了,但我觉得最好给你看一些代码,这样才能把事情弄清楚。我会留第二个短的。
在我看来,当您的视图消失时,您不需要一个视图模型。我不确定框架堆栈是如何在UWP中实现的,以及它们如何管理视图/页面实例。我假设,一旦导航到不同的页面,就应该释放或可以在GC中释放前一个视图/页,并且您可以使用参数和页面类型向后导航,但是它将是一个新的实例,通过还原视图模型来恢复视图的状态。
所以说真的,我认为你走在正确的轨道上。您应该尽可能保存/持久化您的用户数据,并且您的解决方案在应用程序被挂起然后恢复之后,仍然可以恢复您的视图状态。
感谢您的阅读。
https://stackoverflow.com/questions/35174563
复制相似问题