4

I have a main WPF window and one of its controls is a user control that I have created. This user control is an analog clock and contains a thread that update hour, minute and second hands. Initially it wasn't a thread, it was a timer event that updated the hour, minutes and seconds but I have changed it to a thread because the application does some hard work when the user press a start button and then the clock wouldn't update so I changed it to a thread.

Code snippet of WPF window:

 <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:GParts" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes assembly=PresentationFramework.Aero" xmlns:UC="clr-namespace:GParts.UserControls" x:Class="GParts.WinMain" Title="GParts" WindowState="Maximized" Closing="Window_Closing" Icon="/Resources/Calendar-clock.png" x:Name="WMain" > <...> <!-- this is my user control --> <UC:AnalogClock Grid.Row="1" x:Name="AnalogClock" Background="Transparent" Margin="0" Height="Auto" Width="Auto"/> <...> </Window> 

My problem is that when the user exits the application then the thread seems to continue executing. I would like the thread to finish automatically when the main windows closes.

Code snippet of user control constructor:

namespace GParts.UserControls { /// <summary> /// Lógica de interacción para AnalogClock.xaml /// </summary> public partial class AnalogClock : UserControl { System.Timers.Timer timer = new System.Timers.Timer(1000); public AnalogClock() { InitializeComponent(); MDCalendar mdCalendar = new MDCalendar(); DateTime date = DateTime.Now; TimeZone time = TimeZone.CurrentTimeZone; TimeSpan difference = time.GetUtcOffset(date); uint currentTime = mdCalendar.Time() + (uint)difference.TotalSeconds; christianityCalendar.Content = mdCalendar.Date("d/e/Z", currentTime, false); // this was before implementing thread //timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); //timer.Enabled = true; // The Work to perform ThreadStart start = delegate() { // With this condition the thread exits when main window closes but // despite of this it seems like the thread continues executing after // exiting application because in task manager cpu is very busy // while ((this.IsInitialized) && (this.Dispatcher.HasShutdownFinished== false)) { this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { DateTime hora = DateTime.Now; secondHand.Angle = hora.Second * 6; minuteHand.Angle = hora.Minute * 6; hourHand.Angle = (hora.Hour * 30) + (hora.Minute * 0.5); DigitalClock.CurrentTime = hora; })); } Console.Write("Quit ok"); }; // Create the thread and kick it started! new Thread(start).Start(); } // this was before implementing thread void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { DateTime hora = DateTime.Now; secondHand.Angle = hora.Second * 6; minuteHand.Angle = hora.Minute * 6; hourHand.Angle = (hora.Hour * 30) + (hora.Minute * 0.5); DigitalClock.CurrentTime = hora; })); } } // end class } // end namespace 

How can I automatically exit from the thread when the main window closes and then the application exits?

5 Answers 5

11

Just set the IsBackground property of the Thread to true so it doesn't prevent the process from terminating.

Thread t = new Thread(...) { IsBackground = true }; 
Sign up to request clarification or add additional context in comments.

3 Comments

Ok thanks, I'll try it. If I set IsBackground property to true and I do and infinite loop, for example while (true) { // do stuff }, when exit application the thread will terminate executing?
Yes. .NET will kill the process when all non-background threads have exited. Background threads will get silently terminated. However, for my money, although setting the worker thread to background is the Right Thing, I still think it's only a partial solution: as RandomEngy points out, your worker thread is basically sitting on 100% CPU queuing up work for the UI thread, and if you address that design issue then your termination issue should go away into the bargain. (But setting IsBackground = true will still be worth doing.)
OK,I'll try it.One question I would like that you suggest me the best and efficient way to do the task for updating clock.What I want is a efficient way to update clock and when main window (application exit) closes it stops.As you say a good way is doing thread background but is it correct to put all update operations inside a infinite while loop placed inside a thread?or is there a better way to do it?Is this thread correct: while (true) { this.Dispatcher.invoke(...); Thread.Sleep(1000);}
1

Well, one major problem you have is you seem to be running an infinite loop that queues a lot of dispatcher jobs to update your clock, continuously and quickly. An easy fix might be to put a Thread.Sleep(1000); statement in the loop, then making your thread a background thread as Taylor suggests.

Anyway, I'm a little surprised that background work would cause a Timer to fail to update. Getting that approach working would be the ideal solution. Maybe try out DispatcherTimer and see if that can do updates while background work is going on.

4 Comments

The dispatcher only runs when an event handler finishes. If he has a long computation in an event handler, the dispatcher won't be running to dispatch the timer events.
Ok, thanks, but how to exit while loop when main application (window) is closed or when user exit application? my while loop is correct? i have test that when exiting application the thread finishes and reaches at line: console.write("Quit OK") But for some reason after exiting application I note that CPU usage is very high in task manager and it seems thread really hasn't finished executing. What is the correct condition in while loop in order to exit from it and from the thread when the user exit application (close main windows that contains the user control analogclock)? thanks.
I think what's happening is all the dispatcher jobs you've been pouring on the the work queue are grinding out before it lets your app close. Putting a sleep statement for 1 second in your loop, then changing the thread to a background thread should work.
gabe: The dispatcher jobs he's using are not long-running. The background thread will spew them out full speed and the UI thread will work on them almost full-time.
0

May be use DependecyProperty in Your clock-model http://www.wpftutorial.net/HowToCreateADepProp.html DependecyProperty is faster than INotifyPropertyChanget interface, so maybe it's will good for you http://blog.lexique-du-net.com/index.php?post/2010/02/24/DependencyProperties-or-INotifyPropertyChanged

Comments

0

Finally I mixed two solutions, RandomEngy and Taylor but it wasn't working quit well (application wasn't exit successfully) so I decided to combine them with another one solution in the thread:

wpf cancel backgroundworker on application exits

I main window application, from XAML I set the ShutdownMode property of my application to OnMainWindowClose as Thomas said in his comment.

Thanks!

Comments

0

I know you solved your problem, but as I was having a similar issue regarding a running thread and exiting the application correctly, I thought I'd share how I solved my problem.

I ended up skirting the dispatcher/thread model you used and instead opted to use the BackgroundWorker class (System.ComponentModel.BackgroundWorker). It was a simple 4 step process:

  1. create a private member to hold the BackgroundWorker
  2. assign the BackgroundWorker.DoWork event handler in the ctor
  3. define the DoWork event handler method
  4. call _myBackgroundWorker.RunWorkAsync() when I wanted to fire off the actual work.

There are details on using BackgroundWorker embedded in this article about using the Dispatcher in WPF.

Hope it helps someone...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.