【问题标题】:Exit thread automatically when WPF application closesWPF 应用程序关闭时自动退出线程
【发布时间】:2010-03-19 22:05:18
【问题描述】:

我有一个 WPF 主窗口,其中一个控件是我创建的用户控件。此用户控件是一个模拟时钟,并包含一个更新时针、分针和秒针的线程。最初它不是一个线程,它是一个更新小时、分钟和秒的计时器事件,但我已将其更改为线程,因为当用户按下开始按钮时应用程序会做一些艰苦的工作,然后时钟不会更新,所以我把它改成了一个线程。

WPF窗口的代码sn-p:

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

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

用户控件构造函数的代码sn-p:

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

如何在主窗口关闭后应用程序退出时自动退出线程?

【问题讨论】:

    标签: wpf multithreading window


    【解决方案1】:

    只需将 Thread 的 IsBackground 属性设置为 true,这样就不会阻止进程终止。

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

    【讨论】:

    • 好的,谢谢,我试试。如果我将 IsBackground 属性设置为 true 并且执行无限循环,例如 while (true) { // do stuff },当退出应用程序时线程将终止执行?
    • 是的。当所有非后台线程都退出时,.NET 将终止该进程。后台线程将被静默终止。然而,为了我的钱,虽然将工作线程设置为后台是正确的,但我仍然认为这只是部分解决方案:正如 RandomEngy 指出的那样,你的工作线程基本上是 100% 坐在 CPU 上为 UI 线程排队工作,如果您解决了该设计问题,那么您的终止问题应该解决。 (但设置 IsBackground = true 仍然值得。)
    • 好的,我会试试的。一个问题我希望你建议我最好和最有效的方式来完成更新时钟的任务。我想要的是一种有效的方式来更新时钟和何时主窗口(应用程序退出)关闭它会停止。正如你所说的一个好方法是做线程背景但是将所有更新操作放在一个无限循环中是否正确?或者有更好的方法吗?此线程正确:while (true) { this.Dispatcher.invoke(...);线程.Sleep(1000);}
    【解决方案2】:

    嗯,您遇到的一个主要问题是您似乎正在运行一个无限循环,该循环将许多调度程序作业排队以连续且快速地更新您的时钟。一个简单的解决方法可能是将 Thread.Sleep(1000); 语句放入循环中,然后按照 Taylor 的建议将您的线程设为后台线程。

    无论如何,我有点惊讶后台工作会导致计时器无法更新。让这种方法发挥作用将是理想的解决方案。也许试试DispatcherTimer,看看它是否可以在后台工作进行时进行更新。

    【讨论】:

    • 调度程序仅在事件处理程序完成时运行。如果他在事件处理程序中有很长的计算,则调度程序将不会运行以调度计时器事件。
    • 好的,谢谢,但是当主应用程序(窗口)关闭或用户退出应用程序时如何退出while循环?我的while循环正确吗?我已经测试退出应用程序时线程完成并到达行:console.write("Quit OK") 但出于某种原因,在退出应用程序后我注意到任务管理器中的 CPU 使用率非常高,似乎线程确实没有执行完毕。当用户退出应用程序(关闭包含用户控件模拟时钟的主窗口)时,while 循环中的正确条件是什么,以便从它和线程中退出?谢谢。
    • 我认为正在发生的事情是,您一直在工作队列中的所有调度员工作都在让您的应用关闭之前完成。在循环中放置一个 sleep 语句 1 秒,然后将线程更改为后台线程应该可以工作。
    • gabe:他使用的调度员作业不是长时间运行的。后台线程将全速输出它们,而 UI 线程将几乎全​​时处理它们。
    【解决方案3】:

    可以在您的时钟模型http://www.wpftutorial.net/HowToCreateADepProp.html 中使用 DependecyProperty DependecyProperty 比 INotifyPropertyChanget 接口快,所以也许对你有好处http://blog.lexique-du-net.com/index.php?post/2010/02/24/DependencyProperties-or-INotifyPropertyChanged

    【讨论】:

      【解决方案4】:

      最后我混合了 RandomEngy 和 Taylor 这两种解决方案,但效果不佳退出(应用程序未成功退出),因此我决定将它们与线程中的另一种解决方案结合起来:

      wpf cancel backgroundworker on application exits

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

      谢谢!

      【讨论】:

        【解决方案5】:

        我知道你解决了你的问题,但是由于我在运行线程和正确退出应用程序方面遇到了类似的问题,所以我想我会分享我是如何解决我的问题的。

        我最终避开了您使用的调度程序/线程模型,而是选择使用 BackgroundWorker 类 (System.ComponentModel.BackgroundWorker)。这是一个简单的 4 步过程:

        1. 创建一个私有成员来保存 BackgroundWorker
        2. 在 ctor 中分​​配 BackgroundWorker.DoWork 事件处理程序
        3. 定义 DoWork 事件处理方法
        4. 当我想启动实际工作时调用 _myBackgroundWorker.RunWorkAsync()。

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

        希望对某人有所帮助...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-17
          相关资源
          最近更新 更多