2010-03-19 177 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的詳細信息。

希望它可以幫助別人......

相關問題