我有一个主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
当主窗口关闭然后应用程序退出时,如何自动退出线程?
答案 0 :(得分:11)
只需将Thread的IsBackground属性设置为true,这样就不会阻止进程终止。
Thread t = new Thread(...) { IsBackground = true };
答案 1 :(得分:1)
嗯,你遇到的一个主要问题是你似乎正在运行一个无限循环,它会让很多调度员工作排队,以便连续快速地更新你的时钟。一个简单的解决方法可能是在循环中放置Thread.Sleep(1000);
语句,然后像Taylor建议的那样使你的线程成为后台线程。
无论如何,我有点惊讶,后台工作会导致Timer无法更新。使该方法有效将是理想的解决方案。也许试试DispatcherTimer,看看在后台工作进行时是否可以进行更新。
答案 2 :(得分:0)
可以在你的时钟模型http://www.wpftutorial.net/HowToCreateADepProp.html中使用DependecyProperty DependecyProperty比INotifyPropertyChanget界面更快,所以也许它对您有好处http://blog.lexique-du-net.com/index.php?post/2010/02/24/DependencyProperties-or-INotifyPropertyChanged
答案 3 :(得分:0)
最后我混合了两个解决方案,RandomEngy和Taylor,但它没有正常工作(应用程序没有成功退出)所以我决定将它们与线程中的另一个解决方案结合起来:
wpf cancel backgroundworker on application exits
我是主窗口应用程序,从XAML我将我的应用程序的ShutdownMode属性设置为OnMainWindowClose,正如托马斯在评论中所说。
谢谢!
答案 4 :(得分:0)
我知道你解决了你的问题,但由于我遇到了关于正在运行的线程和正确退出应用程序的类似问题,我想我会分享我是如何解决我的问题的。
我最终绕开了您使用的调度程序/线程模型,而是选择使用BackgroundWorker类(System.ComponentModel.BackgroundWorker)。这是一个简单的4步过程:
有关使用this article about using the Dispatcher in WPF中嵌入的BackgroundWorker的详细信息。
希望它有所帮助...