框架导航到另一个页面后,立即销毁ViewModel和Page的实例

本文关键字:ViewModel Page 实例 另一个 导航 框架 | 更新日期: 2023-09-27 18:21:06

假设我有三个页面,即Page1.xaml、Page2.xaml、Page3.xaml。

我有一个窗口,里面有一个Frame。Frame的声明看起来像:

<Frame Source="{Binding SourcePage}" NavigationUIVisibility="Hidden" />

我正在做一些工作,比如在构造函数中增加全局计数器变量,在每页的析构函数中减少全局计数器。

让我们把这个全局计数器命名为x。所以代码应该如下所示:

public int x = 0;

第1.xaml页(与Page1关联的ViewModel为ViewModel1)

public ViewModel1()
{
    x++;
}
~ViewModel1()
{
    x--;
}

类似:

Page2.xaml(与Page2关联的ViewModel是ViewModel2)

public ViewModel2()
{
    x++;
}
~ViewModel2()
{
    x--;
}

第3.xaml页(与Page3关联的ViewModel是ViewModel3)

public ViewModel3()
{
    x++;
}
~ViewModel3()
{
    x--;
}

现在,我在运行时更改帧的源。

最初,帧的源是Page1.xaml。所以,调用ViewModel1的构造函数。所以x的值变为1。

然后我在运行时通过按钮将框架的来源更改为Page2.xaml。因此,调用了ViewModel2的构造函数。所以,x的值变成2。现在,我希望立即调用ViewModel1的析构函数。所以x应该再次变为1。但ViewModel1的Destructor从未被调用。

然后,我再次在运行时通过按钮将框架的来源更改为Page3.xaml。因此,调用了ViewModel3的构造函数。所以,x的值变成3。现在,我希望立即调用ViewModel2的析构函数。所以x应该再次变为2。但ViewModel2的Destructor从未被调用。

然后,我再次在运行时通过按钮将框架的来源更改为Page1.xaml。因此,调用了ViewModel1的构造函数。所以,x的值变成4。现在,我希望立即调用ViewModel3的析构函数。所以x应该再次变为3。但ViewModel3的Destructor从未被调用。

当我关闭程序时,会调用这些ViewModel的析构函数。我不想要这种行为。我总是想在框架导航到另一个页面时立即销毁ViewModel和Page的实例。

任何帮助都将不胜感激。

更新:

让我在这里澄清一下这个问题。

这里的要点是,我想从另一个ViewModel中获取一个ViewModelProperty的当前值。

我有一个SessionViewModel如下:

public sealed class SessionViewModel : ViewModelBase, IModule
{
    private static readonly SessionViewModel instance = new SessionViewModel();
    public static SessionViewModel Instance
    {
        get
        {
            return instance;
        }
    }
    private List<IModule> modulesOpen;
    public List<IModule> ModulesOpen
    {
        get
        {
            return modulesOpen;
        }
        set
        {
            modulesOpen = value;
            NotifyPropertyChanged("ModulesOpen");
        }
    }
    public static IModule GetModuleInstance(string moduleName, string finalName)
    {
        IModule moduleToOpen = null;
        if (Instance.ModulesOpen != null)
        {
            moduleToOpen = Instance.ModulesOpen.SingleOrDefault(mod => mod.ModuleName == moduleName);
        }
        else
        {
            Instance.ModulesOpen = new List<IModule>();
        }
        if (moduleToOpen != null) return moduleToOpen;
        Type module = Type.GetType(finalName);
        moduleToOpen = (IModule)Activator.CreateInstance(module);
        Instance.ModulesOpen.Add(moduleToOpen);
        return moduleToOpen;
    }
    public string ModuleFriendlyName
    {
        get { return "SessionViewModel"; }
    }
    public string ModuleName
    {
        get { return "Session"; }
    }
}

上面代码中使用的接口I是IModule,其声明如下:

public interface IModule
{
    string ModuleFriendlyName { get; }
    string ModuleName { get; }
}

当我的程序运行时,我想收集列表中所有页面的当前实例,然后我可以从另一个ViewModel访问任何ViewModel的当前实例。从中我可以获得另一个ViewModel中属性的当前值。但是实例并不是自动添加到List中的,所以我需要将它们添加到ViewModel的构造函数中的List中,并从ViewModel的Destructor中的List中将它们移除。

让我们看看MainWindowViewModel:的代码

public class MainWindowViewModel : IModule, ViewModelBase
{
    public MainWindowViewModel() //Constructor
    {
        SessionViewModel.Instance.ModulesOpen = new List<IModule>();
        SessionViewModel.Instance.ModulesOpen.Add((IModule)this);
    }
    ~MainWindowViewModel()
    {
        SessionViewModel.Instance.ModulesOpen.Remove((IModule)this);
    }
    ..
    ..
    ..
}

在ViewModel1.cs 中

public class ViewModel1 : IModule, ViewModelBase
{
    public ViewModel1()
    {
        SessionViewModel.Instance.ModulesOpen.Add((IModule)this);
    }
    ~ViewModel1()
    {
        SessionViewModel.Instance.ModulesOpen.Remove((IModule)this);
    }
    ......
    ......
    ......
}

在ViewModel2.cs 中

public class ViewModel2 : IModule, ViewModelBase
{
    public ViewModel2()
    {
        SessionViewModel.Instance.ModulesOpen.Add((IModule)this);
    }
    ~ViewModel2()
    {
        SessionViewModel.Instance.ModulesOpen.Remove((IModule)this);
    }
    ......
    ......
    ......
}

在ViewModel3.cs 中

public class ViewModel3 : IModule, ViewModelBase
{
    public ViewModel3()
    {
        SessionViewModel.Instance.ModulesOpen.Add((IModule)this);
    }
    ~ViewModel3()
    {
        SessionViewModel.Instance.ModulesOpen.Remove((IModule)this);
    }
    ......
    ......
    ......
}

框架导航到另一个页面后,立即销毁ViewModel和Page的实例

在.Net管理的应用程序中,内存释放由垃圾回收器(GC)管理。GC根据一些复杂的规则决定何时调用终结器。所以这就是它做了你所期望的事情的原因。这些文章将有助于理解.Net 中的垃圾回收

http://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspxhttp://joeduffyblog.com/2005/12/27/never-write-a-finalizer-again-well-almost-never/

我不太确定为什么你需要在终结器中这样做,但这篇文章应该对你有帮助:

处理图案

更新:

  1. GC永远不会调用终结器,因为视图模型被添加到静态列表中,除非关闭整个应用程序
  2. 同样,在这里使用终结器来执行您想要的操作是错误的。你无法控制它何时被调用。事实上,当您实现终结器时,它实际上与垃圾收集不同。您需要自己管理静态列表