首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在页面之间切换时,ViewModel实例将始终被重新创建。

在页面之间切换时,ViewModel实例将始终被重新创建。
EN

Stack Overflow用户
提问于 2016-02-03 10:33:19
回答 2查看 888关注 0票数 0

我用的是Prism 6,UWP和Unity。

ViewModels将自动注入到页面的数据文本中。但是,当我在页面之间导航时,将始终重新创建视图模型。这种行为是由棱镜和统一所要求的吗?

假设以下场景,用户在页面中输入一些数据,因此将设置视图模型的适当属性。当用户切换回另一个页面并重新访问该页时,由于创建了一个新的视图模型实例,所有输入的数据都丢失了。

目前,我的解决方法是覆盖OnNavigatedTo和OnNavigatingFrom,用SessionStateService手册保存视图模型的所有属性。我不确定这是不是正确的方法?

您可以使用以下示例再现此行为:https://github.com/PrismLibrary/Prism-Samples-Windows/tree/master/SplitViewSample/SplitViewSample

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-02-03 11:38:40

当您将ViewModels注册为UnityContainer中的单例(ContainerControlledLifetimeManager)时,应该解决这个问题。最好的方法是App.xaml.cs in method OnInitializeAsync

代码语言:javascript
复制
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
    Container.RegisterType<MyViewModel>(new ContainerControlledLifetimeManager());

    // rest of the method
}
票数 0
EN

Stack Overflow用户

发布于 2016-02-03 11:44:35

我没有使用Prism,我使用的是修改版的模板10,我只是快速地看了一下Prism源代码。看起来模板10从棱镜中借用了很多想法。

我试着从两个角度回答你的问题:

1) AFAIK,在Prism中有一个静态类,当自动查找相应的View时,您可以用它来设置如何创建/解析视图模型。类是ViewModelLocationProvider,在ViewModelLocationProvider.cs文件中,您可以使用以下方法来设置“视图模型工厂”

代码语言:javascript
复制
    /// <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;
    }

然后,所有获取视图模型实例的逻辑都在下面,注意这里的注释摘要,它描述了逻辑/策略

代码语言:javascript
复制
    /// <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行,您将获得相应视图的视图模型实例。

这意味着,如果您不调用任何这些方法来设置工厂,它将返回到默认的工厂,即

代码语言:javascript
复制
    /// <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中的工厂设置如下:

代码语言:javascript
复制
    /// <summary>
    /// Configures the <see cref="ViewModelLocator"/> used by Prism.
    /// </summary>
    protected virtual void ConfigureViewModelLocator()
    {
        ViewModelLocationProvider.SetDefaultViewModelFactory((type) => Resolve(type));
    }

这意味着工厂现在正在使用

代码语言:javascript
复制
    /// <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);
    }

您可以用自己的实现覆盖它。

PrismUnityApplicationPrismUnityApplication.cs中,它提供了一个默认的实现来解决使用Unity的实例

代码语言:javascript
复制
    /// <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中释放前一个视图/页,并且您可以使用参数和页面类型向后导航,但是它将是一个新的实例,通过还原视图模型来恢复视图的状态。

所以说真的,我认为你走在正确的轨道上。您应该尽可能保存/持久化您的用户数据,并且您的解决方案在应用程序被挂起然后恢复之后,仍然可以恢复您的视图状态。

感谢您的阅读。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35174563

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档