WPF window 不停止 timer/closing 并降低 RAM 使用率

WPF window not stopping timer/closing and lowering RAM usage

嘿,我已经尝试了很多方法来纠正我的 WPF 程序问题。 WPF 是一项伟大的技术,可用于制作非常好的应用程序,但它与 WinForm 不同的古怪命令有时让我感到不安。

我已加载主要 window 以及打开 MoviePosters 的事件 window:

namespace WpfApplication49
{
    public partial class firstWindow : Window
    {
        public static bool exitLoading = false;
        public static bool loadedMovies  = false;
        public static MoviePosters MP;

....[more code within this area]

    private void myControl1_Click(object sender, myClickEventArgs e)
    {
        if (e.my.Tag.ToString().Contains("movieIcon"))
        {
            if (!loadedMovies)
            {
                MP = new MoviePosters();
                MP.Show();
            }
            else
            {
                MP.Show();
            }
        }

....[more code within this area]

        this.Topmost = false;
    }

....[more code within this area]

}

我目前正在通过这种方式从我的 MoviePosters.xaml [=87= 加载一个 watchMovie.xaml ]:

namespace WpfApplication49
{
    public partial class MoviePosters : Window
    {
        static watchingMovie MW;

    ....[more code within this area]

        private void myControl1_Click(object sender, myClickEventArgs e)
        {
            MW = new watchingMovie((string)e.my.Tag.ToString())
            MW.Show();
        }

    ....[more code within this area]
    }
}

上面的加载 window 就好了。然而,问题是当我关闭这个 window 和 return 回到原来的 window 时,它仍然在内存中并且计时器仍然有效!

watchingMovie.xaml的关闭代码:

namespace WpfApplication49
{
    public partial class watchingMovie : Window
    {
        public readonly DispatcherTimer timer = new DispatcherTimer();

        public watchingMovie(String movie)
        {
            InitializeComponent();
            passedMovie = movie;
            timer.Interval = TimeSpan.FromMilliseconds(200);
            timer.Tick += new EventHandler(timer_Tick);
            this.Topmost = true;
        }

    ....[more code within this area]

        public void Exit_Click(object sender, RoutedEventArgs e)
        {
            ME.Stop();
            ME.Close();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            timer.Stop();
            this.Close();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            TimeSpan _duration = ME.NaturalDuration.TimeSpan;
            TimeSpan remaining = _duration.Subtract(ME.Position);

            if (!isDragging)
            {
                seekBar.Value = ME.Position.TotalSeconds;
                currentposition = seekBar.Value;
                lblMovieTime.Content = remaining.ToString(@"hh\:mm\:ss");
            }

            var totalTime = string.Format("{0:00}:{1:00}", (_duration.Hours * 60) + _duration.Minutes, _duration.Seconds);

        
            var currentTime = string.Format("{0:00}:{1:00}", (remaining.Hours * 60) + remaining.Minutes, remaining.Seconds);

            TimeSpan diff = remaining - _duration;
        }

 ....[more code within this area]

    }
}

firstWindow.xaml 开始,RAM 开始时为 ~59.0 MB。当它到达 MoviePoster window 时,使用的 RAM 是 ~105.4 MB。当我加载 watchingMovie window 时,它会上升到 ~145.0 MB。当我退出 watchingMovie window(使用 this.Close())时,它会带我回到 MoviePoster window 然后 RAM 是 ~143.0 MB。每次我加载 watchingMovie window 时,RAM 使用率就会上升!

所以...

这是一个简短的动画 GIF,展示了从我的程序开始到 watchingMovie window.

退出的过程

更新 #1

在这种情况下调用 GC 是完全没有意义的。
由于计时器继续为你工作,这意味着一些对对象的引用仍然存在,只要这些引用存在,GC 就不会收集这些对象。

在Window关闭事件中,需要停止定时器并清除所有静态链接。
像这样:

    public watchingMovie(String movie)
    {
        InitializeComponent();
        Closed += OnWindowClosed;

        passedMovie = movie;
        timer.Interval = TimeSpan.FromMilliseconds(200);
        timer.Tick += timer_Tick;
        this.Topmost = true;
    }

    void timer_Tick(object sender, EventArgs e)
    { 
        // Some Code
    }

    private void OnWindowClosed(object sender, EventArgs e)
    {
        timer.Stop();
        timer.Tick -= timer_Tick;
        ME.Stop();
        ME.Close();
        ME = null;
    }
        private void myControl1_Click(object sender, myClickEventArgs e)
        {
            MW = new watchingMovie((string)e.my.Tag.ToString());
            MW.Closed += (_, __) => MW = null;
            MW.Show();
        }
    public firstWindow()
    {
        InitializeComponent();
        Closed += (_, __) => MP?.Close();
    }

    private void myControl1_Click(object sender, myClickEventArgs e)
    {
        if (e.my.Tag.ToString().Contains("movieIcon"))
        {
            if (!loadedMovies)
            {
                MP = new MoviePosters();
                MP.Closed += (_, __) => MP = null;
                MP.Show();
            }
            else
            {
                MP.Show();
            }
        }
    }

P.S.我强烈建议你完全放弃存储动态创建对象的静态成员(字段和属性)。
静态成员只能用于存储对应用程序会话期间必须存在的对象的引用。
在会话结束之前,不应关闭、销毁此类对象。