i have some usercontrols in my solution, in main window i just change content of ContentControl.
in one usercontrol there is a timer
BringTrinket trincket = new BringTrinket();
trincket.TrincketBringed += new TrincketBringedEventHandler(trincket_TrincketBringed);
this.contentSwitcher.Content = new BringTrinket();
}
void trincket_TrincketBringed(object sender, TrincketEventArgs e)
{
MessageBox.Show(e.TrincketNumber);
this.contentSwitcher.Content = new Loading();
}`
after some event Main Window should change content to (new Loading()), it's OK!
public partial class BringTrinket : UserControl, ISwitchable
{
public event TrincketBringedEventHandler TrincketBringed;
private DispatcherTimer timer;
public BringTrinket()
{
InitializeComponent();
/////////////////////////////////////////////////////////////////////////////
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 1800);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
/////////////////////////////////////////////////////////////////////////////
}
/////////////////////////////////////////////////////////////////////////////
void timer_Tick(object sender, EventArgs e)
{
if (TrincketBringed != null)
{
TrincketBringed(this, new TrincketEventArgs("Hello"));
//TrincketBringed = null;
}
}
But after i've navigataged Timer in BringTrinket still working, how have i dispose that usercontrol? (I know i can set TrincketBringed to null, but timer will still be working)
I think not only timer, but also usercontrol remains in memory
So, your question is how to stop the timer? Use timer.Stop().
BTW, your code would read better if you rename TricketBringed to TrincketBrought.
It looks like your timer is inside of your first usercontrol. You would either need to stop the timer before losing the reference to that object, or better yet, move the timer out of your control.
Related
I don't understand why my test WPF application here doesn't free up the memory it uses after I have closed the MainWindow and set it to null, and even run the garbage collector?
In the beginning, even before the MainWindow is created, the Application takes almost no memory, about 5 MB, but when I create the first window it takes 43 MB and it stays there for the rest of the application's life. Isn't it possible to get it back down to 5 MB again without restarting the application?
Diagnostic Tools
public App()
{
ShutdownMode = ShutdownMode.OnExplicitShutdown;
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 2);
Thread.Sleep(2000);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (MainWindow == null)
{
MainWindow = new MainWindow();
MainWindow.Show();
}
else
{
MainWindow.Close();
MainWindow = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
You have a memory leak, so the GC will not be able to collect your MainWindow. You must unsubscribe from your event handler. So keep the timer in a backing field:
MainWindow = null;
// Add this:
this.dispatcherTimer.Tick -= new EventHandler(dispatcherTimer_Tick);
this.dispatcherTimer.Stop();
I am new to C# and also to WPF, I am trying to understand how DispatcherTimer works with GUI (WPF). I want to make my application run a function every 2 seconds but still using the app itself, when I try the following code, the timer starts but I can't use the following Buttons (logout and exit), it's like the app freezes.
public MainLoggedWindow()
{
Globals.mainLoggedWindow = this;
InitializeComponent();
DispatcherTimer dt = new DispatcherTimer();
dt.Tick += new EventHandler(dtTiker);
dt.Interval = new TimeSpan(0, 0, 1);
dt.Start();
}
private void exit_button_Click(object sender, RoutedEventArgs e)
{
logout_button_Click(sender, e);
Environment.Exit(-1);
}
private void logout_button_Click(object sender, RoutedEventArgs e)
{
Globals.LOGGED_IN_USER.logout();
this.Hide();
Globals.mainWindow.Show();
}
private int increment = 0;
private void dtTiker(object sender,EventArgs e)
{
increment++;
Time.Content = increment.ToString();
}
DispatcherTimer runs on the UI thread. It means that when the DispatcherTimer invokes its Tick method the UI thread becomes busy handling that, and it doesn't have time to handle other UI input like button clicks, so the window freezes.
What you could do is increase the interval time for your DispatcherTimer - your question desription says that it's once every two seconds, but your initialisation logic has it every one second: dt.Interval = new TimeSpan(0, 0, 1);
I've been writing a program in c# using windows form(WPF), and I've been stuck on this problem. I'm trying to create a function that will displays an image for a few seconds. This function has to be able to be called from an outside function.
The method should be fairly trivial. When called it would show your image (it's visibility could be false by default). The method could then start a timer, with an interval of the required number of seconds. In the timers elapsed callback you could simply set the images visibility to false.
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 3); //fire after 3 seconds
...
private void ShowMyImage()
{
// logic to show your image
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
// logic to hide your image
dispatcherTimer.Stop();
}
For example. I have some Timer and i'm initializing it in my Window constructor.
public MainWindow()
{
InitializeComponent();
CheckTImer = new Timer(3000);
CheckTimer.Elapsed += CheckTimer_Elapsed;
CheckTimer.Start();
}
And this is my CheckTimer_Elapsed method:
void CheckTimer_Elapsed(object sender, ElapsedEventArgs e)
{
MessageBox.Show("FirstText");
Image IMG = new Image();
MessageBox.Show("SecondText");
}
Why it is loading only a first MessageBox window? But, if it would be function that is called not by a Timer all is OK.
public MainWindow()
{
InitializeComponent();
SomeFunc();
}
void SomeFunc()
{
MessageBox.Show("FirstText");
Image IMG = new Image();
MessageBox.Show("SecondText");
}
I believe this is a threading problem.
If I recall the event that is getting called from the timer is on a new thread. You are trying to do UI work which is not on the UI thread (which is not allowed). Couple of solutions to this, the simplest of which is to use a DispatcherTimer instead of a Timer. You can find it in System.Windows.Threading;
The Event that gets called from the DispatcherTimer is on the UI thread
Hope this helps
In my WPF application i have to show a progressbar progress with in a timer tick event, which i am writing as below,
System.Windows.Forms.Timer timer;
public MainWindow()
{
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
this.timer.Tick += new System.EventHandler(this.timer_Tick);
}
load event as below
private void Window_Loaded(object sender, RoutedEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Value = DateTime.Now.Second;
progressBar1.Maximum = 700;
timer.Start();
}
And at last in tick event,
private void timer_Tick(object sender, EventArgs e)
{
Duration duration = new Duration(TimeSpan.FromSeconds(20));
//progress bar animation
System.Windows.Media.Animation.DoubleAnimation doubleanimation = new System.Windows.Media.Animation.DoubleAnimation(200.0, duration);
progressBar1.BeginAnimation(ProgressBar.ValueProperty, doubleanimation);
}
When the program's progressbar shows the progress for two-three bars and then it stops increment. Later there is no effect in the progress at all.
Why?
Since your ProgressBar doesn't relate to any particular behavior, it looks like a job for an indeterminate bar.
This other SO question provides some insight about it. In short, it's a XAML one-liner:
<!-- MinVal, MaxVal, Height needed for this to work -->
<ProgressBar x:Name="progressBar1" Margin="5" IsIndeterminate="True"
MinimumValue="0" MaximumValue="700" value="0" Height="20"/>
Then in code, you go like this:
progressBar1.IsIndeterminate = true; // start animation
progressBar1.IsIndeterminate = false; // stop animation
In my WPF application I have ... System.Windows.Forms.Timer timer;
That is the wrong type of timer. Use a DispatcherTimer instead.
When i execute my program progressbar shows the progress for two-three bars and then it stops
This surprises me, I wouldn't have expected it to work at all. This means you may have other problems too, like blocking the main (dispatcher) thread.
You are only setting the Value once, in the Loaded event:
progressBar1.Value = DateTime.Now.Second;
There is no change to progressBar1.Value in the Tick event. So it figures that it stops moving.
Use DispatcherTimer instead of Timer (Forms object), and use Value property of ProgressBar.
Try this:
MainWindows.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="55" Width="261">
<Grid>
<ProgressBar Name="pb" Maximum="60" />
</Grid>
</Window>
MainWindows.xaml.cs:
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private DispatcherTimer timer;
public MainWindow()
{
InitializeComponent();
this.timer = new DispatcherTimer();
this.timer.Tick += timer_Tick;
this.timer.Interval = new System.TimeSpan(0, 0, 1);
this.timer.Start();
}
private void timer_Tick(object sender, System.EventArgs e)
{
this.pb.Value = System.DateTime.Now.Second % 100;
}
}
}
You can change the behaviour of the progress bar by changing the Value property (don't forget defining the Maximum property in the xaml).
I found this (WPF Multithreading: Using the BackgroundWorker and Reporting the Progress to the UI. link) to contain a great solution for my needs, albeit with a dialog box.
The one thing I found very useful was that the worker thread couldn't access the MainWindow's controls (in its own method). However, when using a delegate inside the main windows event handler, it was possible.
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
pd.Close();
// Get a result from the asynchronous worker
T t = (t)args.Result
this.ExampleControl.Text = t.BlaBla;
};