Hey all I have been trying a lot of ways to correct my issue here with my WPF program. WPF is a great technology for making really nice apps but its odd-ball commands that differ from that of a WinForm gets me upset sometimes.
I have my main window load up and the event that opens the 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]
}
I currently am loading up a watchMovie.xaml by this means from my MoviePosters.xaml window:
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]
}
}
That above loads up the window just fine. However, the issue is when I close this window and return back to the original window, it still has it in memory and the timer is still active!
The code for the close of the 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]
}
}
From the start of the firstWindow.xaml the RAM starts out at ~59.0 MB. When it gets to the MoviePoster window the RAM used is ~105.4 MB. When I load up the watchingMovie window it goes up to ~145.0 MB. When I exit the watchingMovie window (with the this.Close()) it takes me back to the MoviePoster window and the RAM then is ~143.0 MB. And every time I load the watchingMovie window the more the RAM usage goes up!
So...
- Shouldn't the ram be back to around ~105 MB like it was before loading the watchingMovie window since I closed that window?
- I don't understand why the timer is still counting the minutes of the movie - you know, since it should have stopped it once the window itself had closed?
Here is a short animated GIF to show from the start of my program to the exit of the watchingMovie window.
update #1
CodePudding user response:
Calling GC in this case is completely pointless.
Since the timer continues to work for you, it means that some references to objects remain, and as long as there are these references, the GC will not collect these objects.
In the Window close event, you need to stop the timer and clear all static links.
Something like this:
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. I strongly advise you to completely abandon static members (fields and properties) that store dynamically created objects.
Static members can only be used to store references to objects that must exist for the duration of the application session.
Such objects should not be closed, destroyed until the session ends.