【问题标题】:Navigation & reinstanciate pages/viewmodel constructor导航和重新实例化页面/视图模型构造函数
【发布时间】:2014-01-02 05:49:38
【问题描述】:

我正在使用 Galasoft Mvvm Light 工具包,以 MVVM 模式为 windows phone 构建我的应用程序。我必须每个页面都有自己的视图模型。

当用户启动应用程序时,他可以选择新游戏并打开问题页面。这些页面都有一个视图模型,并且一切都使用视图模型定位器。当用户随后导航返回以再次在新游戏和问题之间进行选择时。视图模型/页面不会被删除。这意味着当用户第二次进入问题或新游戏时,视图模型的构造函数不会被调用,因此构造函数中的初始化不会运行,并且视图设置不正确。

我尝试过的解决方案

我尝试删除导航中的后台堆栈,例如新导航到新游戏或问题,应该启动一个新页面,从而调用构造函数。不工作。

在视图中使用加载的事件,并调用构造函数。不工作。

试图关注 How to reset all instances in IOC Container 但无法让它工作,可能只是我。

有没有人解决过这个问题,如果有,应该如何解决?

代码 在这里你可以找到一个例子。按问题,然后按一次那里的按钮,使用后键。并再次按问题。您会看到数字现在是 1,这很容易更改。但是当您再次按下按钮时会出现错误。突然出现两个弹出窗口。

那么设置视图模型的正确方法是什么。因为 newgame 的视图将在重新加载旧游戏时使用,仅使用其他值,以及当人们想要开始新游戏时。希望你明白:)

这个例子只是为了展示我每次返回视图模型页面时弹出窗口计数增加的问题。 https://www.dropbox.com/s/gjbz0l8rmsxqzrd/PhoneApp8.rar

ViewModel 定位器 我在我当前的项目中使用以下代码中的三个视图模型:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;

namespace MVVMTestApp.ViewModel
{
public class ViewModelLocator
{
    public ViewModelLocator()
    {
        //Holder styr på ViewModels
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        //Tilføj linje her for hver ViewModel
        SimpleIoc.Default.Register<MainViewModel>();
        SimpleIoc.Default.Register<MainViewModelTest>();
        SimpleIoc.Default.Register<MenuViewModel>();
    }

    //Tilføj metode som denne for hver ViewModel
    public MainViewModel Map
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }

    public MainViewModelTest Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModelTest>();
        }
    }

    public MenuViewModel Menu
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MenuViewModel>();
        }
    }

    public static void Cleanup()
    {
            // TODO Clear the ViewModels
    }
}

我查看了上面引用的链接,重置了 IOC 容器中的所有实例。但是不确定键是如何工作的,以及如何确保在离开视图时调用清理函数。因为我不想同时清理所有视图模型。

导航和视图模型绑定

我将我的视图模型绑定到视图

DataContext="{Binding Source={StaticResource Locator},Path=Map}"

我使用 NavigationService 和后退按钮来回导航。从菜单到游戏:

NavigationService.Navigate(new Uri("/View/MainPage.xaml", UriKind.Relative));

在页面中

protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        //e.Content = NavigationMode.New;
        //e.NavigationMode = NavigationMode(
        ViewModel.MainViewModel test = new ViewModel.MainViewModel();
        GC.Collect();
        base.OnNavigatedTo(e);
    }

从游戏到菜单:

protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        //e.NavigationMode = NavigationMode.
        this.DataContext = null;
        GC.Collect();
        base.OnNavigatedFrom(e);
        //test = null;
    }

在菜单中我调用了垃圾收集器。可以看出,我打破了 MVVM 结构以适应问题。

【问题讨论】:

  • 我认为如果您可以发布一个特定示例来演示该问题,您将获得更具体的答案。但总的来说,我认为视图模型的重点是跨页面加载持久化数据,因此您不应该对第二个页面视图保留第一个视图的数据感到惊讶。您可以通过将一些页面 init 从构造函数移出到从构造函数调用的函数以及从页面加载事件调用的函数中来处理此问题。
  • 这正是我所做的。但是存在内存问题,因为在导航时没有清除视图模型。而且由于数据上下文设置为视图,因此我无法访问后面的视图模型。到目前为止,我必须做的是设置 datacontext = null,并调用 GC.collect()。但这不是一个很好的方法。我想知道正确的方法是什么。
  • 请发布一个示例,展示您当前正在做什么(使用 cmets 展示您希望发生的事情)。当第二次加载 P1 时,给定页面 P1 的视图模型 V1 仍然在内存中,这是应该发生的。您是否在 P1.DataContext 中看到了其他视图模型?
  • @BobHy 我创建了一个小样本,我制作了一个 rar 文件并包含在文本中。

标签: c# mvvm windows-phone-8 ioc-container


【解决方案1】:

ViewModelLocator 的属性返回单例。要让属性每次都返回一个新实例,您可以简单地编写:

private int questCount;

public Question Quest
{
    get
    {
        return ServiceLocator.Current.GetInstance<Question>((++questCount).ToString());
    }
}

但是,它会导致问题 ViewModel 缓存。您需要通过密切关注您链接的答案来释放未使用的 ViewModel。这导致我认为对于简单结果的代码过多。您可以使用其他 IOC 容器来代替 Windows Phone 上的 SimpleIoc(例如 ninjectunity),它们可能更适合您的需求。

在一个简单的项目(几个页面的应用程序)中,尤其是在没有太多 IOC 容器经验的情况下,我建议您放弃所有 SimpleIoc 接线,只调用构造函数:

public Question Quest
{
    get { return new Question(); }
}

【讨论】:

  • 感谢您的回复,我的项目比较大,我使用了三个视图模型。我已经尝试实现清理功能但没有让它工作,因为我不确定如何调用清理,以及如何确保对所有变量进行清理,即使它们是静态的。我可以执行我链接到的代码并让它工作,但我不明白密钥是如何工作的。所以我不太喜欢使用代码,我不知道如何维护。所以我想使用 SimpleIoc,因为我使用的是 MVVM light,但不确定如何去做。我将使用 Viewmodellocator 更新我的问题。
  • @JTIM 三个 ViewModel 具有非常简单的构造函数(根据您的 SimpleIoc 设置判断),绝对我会使用 IOC 容器.显式的构造函数调用将产生更少的代码,你肯定能理解。
  • @JTIM 至于 SimpleIoc - GetInstance 返回相同的实例,具有给定键的 GetInstance 为给定键产生相同的实例。取消注册允许删除分配给密钥的实例。这只是 SimpleIoc 规范。这使得它在某些情况下有用,在某些情况下很难应用。 SimpleIoc 只是 MVVMLight 中的助手之一——您不必在每个项目中都使用它们。 ViewModelLocator 可以在没有它的情况下轻松编写。
  • 好吧,我不知道。但是我仍然很难理解,因为这是我学到的 :) 但是如果不使用 ViewmodelLocater,我必须自己在视图中连接数据上下文。我能说服你做一个样品吗?我不知道该怎么做,我做了一些解决方法,但它们并不漂亮,因此我喜欢另一种方法。
  • @JTIM 我确实使用 ViewModelLocator(用于在 .xaml 中绑定 DataContext),但我使用 SimpleIoc。 ViewModelLocator 属性类似于答案 (get { return new QuestionViewModel(); })。每次打开新页面时,都会创建新的 ViewModel,然后我让 GarbageCollector 完成其余的工作(当页面关闭时,ViewModel 会被移除)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-18
  • 2020-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多