2010-03-19 128 views
4

我有一个主要的WPF窗口,其中一个控件是我创建的用户控件。这个用户控制是一个模拟时钟,并包含一个更新小时,分钟和秒针的线程。最初它不是一个线程,它是一个计时器事件,更新了小时,分钟和秒钟,但我已将它更改为一个线程,因为当用户按下开始按钮然后时钟不会更新,所以我改变它为一个线程。 WPF窗口当WPF应用程序关闭时自动退出线程

代码片段:

 <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> 

我的问题是,当用户退出应用程序,然后线程似乎继续执行。我希望线程在主窗口关闭时自动完成。用户控制构造的

代码片段:

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 

怎么能当主窗口关闭,然后应用程序退出我自动从线程退出?

回答

1

那么,你有一个主要问题是你似乎运行一个无限循环,排队很多调度员工作,以持续和快速地更新你的时钟。一个简单的解决方法可能是在循环中放入一个Thread.Sleep(1000);语句,然后按照泰勒的说法将线程设置为后台线程。

无论如何,我有点惊讶,后台工作会导致计时器无法更新。获得该方法的工作将是理想的解决方案。也许试试DispatcherTimer,看看是否可以做更新,而后台工作正在进行。

+0

调度程序只在事件处理程序完成时运行。如果他在事件处理程序中有很长的计算时间,调度程序将不会运行以分派计时器事件。 – Gabe

+0

好的,谢谢,但是当主应用程序(窗口)关闭或用户退出应用程序时,如何退出while循环?我的while循环是正确的?我已经测试,当退出应用程序的线程完成并达到线:console.write(“退出确定”)但由于某种原因退出应用程序后,我注意到CPU使用率是非常高的任务管理器,它似乎线程真的没有完成执行。当用户退出应用程序(关闭包含用户控制模拟时钟的主窗口)时,while循环中的正确条件以便退出并从线程中退出? 谢谢。 – toni

+0

我认为发生了什么事情是所有调度员的工作都在你的应用程序关闭之前就已经被磨掉了。在你的循环中放置睡眠语句1秒,然后将线程更改为后台线程应该工作。 – RandomEngy

11

线程的IsBackground属性正好被设置为true,所以它不会阻止从终止的过程。

Thread t = new Thread(...) { IsBackground = true }; 
+0

好的,谢谢,我会尝试。如果我将IsBackground属性设置为true,并且我做了无限循环,例如while(true){// do stuff},退出应用程序时线程将终止执行? – toni

+1

是的。当所有非后台线程退出时,.NET将终止进程。后台线程将被默默终止。然而,对于我的钱来说,尽管将工作线程设置为后台是正确的,但我仍然认为这只是一个部分解决方案:正如RandomEngy指出的那样,您的工作线程基本上是100%CPU排队等待UI线程工作,如果你解决了这个设计问题,那么你的终止问题应该放弃讨价还价。 (但是设置IsBackground = true仍然值得去做。) – itowlson

+0

好的,我会尝试一下。有一个问题,我希望你建议我以最好和有效的方式来完成更新clock.What我想要的是一个高效更新时钟的方式以及主窗口(应用程序出口)关闭时的方法stops.As你说一个好的方法是做线程背景,但是把所有更新操作放在一个无限的while循环放在一个线程内是正确的吗?还是有更好的方法方法来做到这一点吗?这个线程是否正确: while(true){this.Dispatcher.invoke(...); Thread.sleep代码(1000);} – toni

0

最后我是混合两种解决方案,RandomEngy和泰勒,但它不工作以及退出(应用程序没有成功退出),所以我决定将它们与线程另一个解决方案相结合:

wpf cancel backgroundworker on application exits

我从XAML获得主窗口应用程序如Thomas在他的评论中所述,我将应用程序的ShutdownMode属性设置为OnMainWindowClose。

谢谢!

0

我知道你解决了你的问题,但由于我在正在运行的线程和退出应用程序时遇到了类似的问题,我以为我会分享我是如何解决我的问题的。我结束了使用调度程序/线程模型,而是选择使用BackgroundWorker类(System.ComponentModel.BackgroundWorker)。这是一个简单的4个步骤:

  1. 创建一个私有的部件保持的BackgroundWorker
  2. 分配BackgroundWorker的。DoWork事件处理程序在ctor
  3. 中定义了DoWork事件处理程序方法
  4. 当我想要关闭实际工作时调用_myBackgroundWorker.RunWorkAsync()。

有关于使用嵌入在this article about using the Dispatcher in WPF中的BackgroundWorker的详细信息。

希望它可以帮助别人......

相关问题