System.Threading.Timer:它为啥讨厌我?
Posted
技术标签:
【中文标题】System.Threading.Timer:它为啥讨厌我?【英文标题】:System.Threading.Timer: Why is it hating me?System.Threading.Timer:它为什么讨厌我? 【发布时间】:2011-02-06 19:20:36 【问题描述】:我刚开始玩弄 C#/.NET/mono 之类的东西,我正在尝试制作一个简单的歌曲播放器。为此,我使用winmm.dll
(没有找到简单的跨平台解决方案)。问题是这样的:我需要在播放歌曲的同时更新轨迹栏。我有两个函数,Player.GetLength
和 Player.GetCurrentPosition
,它们以毫秒为单位返回时间。如果我称他们为“正常”,一切都很好。但我需要在计时器中调用它们,如下所示:
new System.Threading.Timer((state) =>
length = Player.GetLength();
pos = Player.GetCurrentPosition();
trackBar1.Value = (pos / length) * 100;
, null, 0, 100);
这是GetLength
,与GetCurrentPosition
类似:
public static int GetLength()
StringBuilder s = new StringBuilder(128);
mciSendString("status Song length", s, s.Capacity, IntPtr.Zero);
return int.Parse(s.ToString());
问题:当这两个函数之一被调用时,程序只是停止,没有任何警告或异常抛出。 注意:我使用的是 .NET
所以我想知道你是否可以向我解释我哪里弄错了:)
【问题讨论】:
【参考方案1】:我要注意的一件事是 System.Threading.Timer 在它自己的线程中触发它的回调。由于您正在与 UI 交互,因此您可能想要使用 System.Windows.Forms.Timer(作为表单上的组件)或调用回 UI,如下所示:
new System.Threading.Timer((state) =>
length = Player.GetLength();
pos = Player.GetCurrentPosition();
trackBar1.Invoke(new Action(()=>trackBar1.Value = (pos / length) * 100));
, null, 0, 100);
同样,我不确定 Player 类是否支持/容忍多个线程,但如果不支持,则可能需要将整个回调调用到 UI。
【讨论】:
它有效,但我也想知道为什么。你能向我解释一下到底发生了什么吗? 在 .NET(以及许多平台上的许多其他 UI 库中)中,UI 控件并非设计为可从多个线程访问。这使他们能够更快地工作,因为他们不需要担心同步数据。在您的情况下,.NET 实际上是抛出一个异常,抱怨您试图从后台线程访问 UI,但由于它位于后台线程上,因此您看不到抛出异常。 所以我想在使用线程时与它们交互的唯一方法是.Invoke
,对吧?
System.Threading.Timer 类在线程池线程上运行回调,如下所述:msdn.microsoft.com/en-us/library/system.threading.timer.aspx
那是正确的 - 您必须在与 UI 交互之前调用。以上是关于System.Threading.Timer:它为啥讨厌我?的主要内容,如果未能解决你的问题,请参考以下文章
System.Threading.Timer 杀死 PowerShell 控制台
System.Windows.Forms.TimerSystem.Timers.TimerSystem.Threading.Timer
如何在 C# 中创建计时器而不使用 System.Timers.Timer 或 System.Threading.Timer
System.Threading.Timer:它为啥讨厌我?