为什么WPF窗口在主窗口关闭后没有自动释放和回收?

5

我一直在思考这个问题,并正在寻找最佳解决方案。要重现此问题,只需:

  1. Add a new Window in a new WPF application.
  2. Add the following code:

    public MainWindow()
    {
        InitializeComponent();
        //add code
        Window1 w1 = new Window1();
        //following is in my actual project
        DataContext = new AllUserQueryiesViewModel(new CommonQueryTestSubWindow());
    }
    
  3. Run and close MainWindow.

到目前为止,我原本以为应用程序已经关闭了,但我的VS2010似乎仍然在运行。那么问题出在哪里?如何解决呢?
---------更新-----------------
我想最好还是分享一下我实际项目中的场景,这样你就能更好地理解我为什么要这样做。想象一下一个查询列表和打开查询功能,就像针对TFS工作项查询一样。我正在创建一些用户控件来完成这个任务,供我们团队中的其他人在同一应用程序中使用。查询列表和打开的查询位于不同的用户控件中,因此用户(其他程序员)可以将打开的查询放在任何位置(ContentControl)中。这些是ViewModels:
public class AllVM

    {
        public AllVM(IOneVMContainer container)
        {
            OneVMs = new ObservableCollection<OneVM>()
           {
               new OneVM(container),
               new OneVM(container)
           };
        }

        public ObservableCollection<OneVM> OneVMs { get; set; }
        public OneVM SelectedOneVM { get; set; }

        public void OpenOne()
        {
            SelectedOneVM.Open();
        }
    }

public class OneVM
{
    IOneVMContainer container;
    public OneVM(IOneVMContainer container)
    {
        this.container = container.NewInstance();
    }
    //I want to open and close the view from viewmodel
    public void Open()
    {
        container.GetContentCtl().Content = this;
        container.Show();
    }
    public void Close()
    {
        container.Close();
    }
}

为了在ViewModel中打开和关闭视图,我创建了这样的接口

//Is it good to use interface?
//Maybe a better interface?
public interface IOneVMContainer
{
    IOneVMContainer NewInstance();
    void Show();
    void Close();
    ContentControl GetContentCtl();
}

使用上述视图模型:

请注意以下几点使用要点:

//my usercontrol to hold AllVM
public AllUC()
{
    InitializeComponent();
    DataContext = new AllVM(new  OneContainerWindow());
}

//implement by other team members
public partial class OneContainerWindow : Window,IOneVMContainer
{
    public OneContainerWindow()
    {
        InitializeComponent();
    }
    public IOneVMContainer NewInstance()
    {
       return new OneContainerWindow();
    }
    public ContentControl GetContentCtl()
    {
        return contentCtl1;
    }
}

我想知道是否必须将窗口存储在ViewModel中,这是主要问题。我知道你一定有更好的解决方案,请帮忙。


1
这不是MVVM。DataContext 应该保存 ViewModel,而不是 View(Window)。 - Clemens
你似乎连 WPF 最基本和最基础的步骤——设置“DataContext”都搞混了。我建议你在尝试编写任何代码之前,花些时间阅读 MSDN 上的 入门指南 (WPF) 页面,特别是在你再次提问之前。 - Sheridan
@Clemens 上面的代码不是MVVM(仅用于重现,我的实际DataContext继承自ViewModelBase),但我在我的项目中使用了MVVM。现在我已经在我的问题中删除了MVVM这个词,这个问题仍然是一个问题。它可以是一个使用或不使用MVVM的问题。 - Lei Yang
1
问题与是否为“DataContext”属性无关。添加一个成员,如private Window window = new Window();也会显示相同的行为。我想说的是,窗口只需要以某种方式关闭即可。 - Clemens
@Clemens 好的,我已经按照你的建议更新了我的代码。 - Lei Yang
2个回答

4

首先,不要在构造函数中实例化一个新窗口。

现在回答你的问题,你需要设置窗口的Owner

public MainWindow()
{
    InitializeComponent();
    Loaded += MainWindow_Loaded;
}

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    Window w = new Window() { Owner = this };
}

通过这种方式,子窗口应该被正确地清除。


@LeiYang:你需要想办法将子窗口的所有者设置为主窗口。根据你的结构,这是你的任务。但基本上,你可以使用以下“肮脏技巧”:someWindow.Owner = Application.Current.MainWindow; - Liero

3
WPF调度程序循环会一直运行,只要您的应用程序仍有一个活动的窗口实例。你的Window1对象也不例外。即使它不可见因为你从未调用过Show()方法,你也永远无法关闭该窗口,因为你已经丢失了对该窗口的引用,但这并不改变上述结果。
虽然不太清楚为什么要考虑这样做,但其中一种解决方法是在主窗口关闭时强制退出调度程序循环。
    protected override void OnClosed(EventArgs e) {
        base.OnClosed(e);
        Application.Current.Dispatcher.InvokeShutdown();
    }

还有其他很多选择,比如将"w1"作为类的一个字段,以便可以调用其Close()方法。或者将其设置为拥有窗口,以便在主窗口关闭时也一并关闭。或者展示它,使用户对您的应用程序中的窗口保持控制。任选其一。


调度程序循环是否会一直运行,即使从未调用Window.Show()?为什么会这样呢?这对我来说没有太多意义。 - Liero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接