【发布时间】:2012-03-02 08:35:57
【问题描述】:
我有一个对象,它使用计时器偶尔轮询资源,然后在轮询发现值得注意的东西时引发事件。我查看了其他几个示例,但似乎无法找到一种方法将事件编组回 UI 线程,而无需在 UI 线程上的事件处理程序上添加额外代码。所以我的问题是:
有什么方法可以对我的对象的用户隐藏这种额外的努力吗?
为了便于讨论,我将举一个简单的例子:
假设我有一个带有 1 个富文本框的表单:
private void Form1_Load(object sender, EventArgs e)
{
var listener = new PollingListener();
listener.Polled += new EventHandler<EventArgs>(listener_Polled);
}
void listener_Polled(object sender, EventArgs e)
{
richTextBox1.Text += "Polled " + DateTime.Now.Second.ToString();
}
我也有这个对象:
public class PollingListener
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
public event EventHandler<EventArgs> Polled;
public PollingListener()
{
timer.Elapsed +=new System.Timers.ElapsedEventHandler(PollNow);
timer.Start();
}
void PollNow(object sender, EventArgs e)
{
var temp = Polled;
if (temp != null) Polled(this, new EventArgs());
}
}
如果我运行它,正如预期的那样,它会产生异常
"跨线程操作无效:已访问控件'richTextBox1' 来自创建它的线程以外的线程”
这对我来说很有意义,我可以像这样以不同的方式包装事件处理程序方法:
void listener_Polled(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() => { UpdateText() }));
}
void UpdateText()
{
richTextBox1.Text += "Polled " + DateTime.Now.Second.ToString();
}
但是现在我的对象的用户必须为我控制的计时器事件引发的任何事件执行此操作。那么,有什么我可以添加到我的 PollingListener 类中的东西,它不会改变它的方法的签名以传递额外的引用,从而允许我的对象的用户忘记后台到 UI 线程的封送事件?
感谢您的任何意见。
【问题讨论】:
-
只需使用 WinForms 或 WPF 计时器。删掉大部分代码。
-
如果从那些定时器调用他的轮询操作可能会阻塞任何显着的时间,那么这些定时器可能会阻塞 UI 线程。
-
我个人认为隐藏你在后台线程上的事实并不是一个好主意。这是您的用户应该注意的事情(我假设您所说的用户是指其他程序员)。用户可能希望事件在默认 UI 线程之外的线程中触发,或者根本不关心它触发的线程 - 这是他们的调用,而不是您的调用(作为实用程序类的作者)。
-
虽然这里有几个优点,并且诚然,这里大量使用计时器导致与我更(不太明显)的基本问题产生分歧,但我一直在寻找构建对象的方法记住哪个线程创建了它,如果它是某种 UI 线程,它会适当地编组。考虑到该设计的脆弱性,尽管我想不出任何好主意。我假设有几个现有的对象在内部使用线程,引发事件,并为我将它们冒泡到 UI 线程 wo/Form refs,但显然不是。
标签: c# multithreading