我正在尝试根据在后台线程上完成的轮询来禁用.NET应用程序中的部分UI。后台线程检查应用程序使用的全局数据库连接是否仍处于打开状态且可以运行。
我需要做的是,如果不在UI线程上进行轮询,我更愿意这样做,就是添加一个事件处理程序,如果连接状态发生变化,后台线程可以引发该事件处理程序。这样,任何表单都可以有一个处理程序,用于禁用需要连接才能运行的UI部分。
尝试在保存线程sub的类中使用直接事件声明,并在后台线程中引发事件,从而导致从其他线程访问UI控件的跨线程执行错误。
显然,有一种正确的方法可以做到这一点,但我们对事件(主要是单线程应用程序)的经验有限,而且几乎没有代表。我已经阅读了代表的文档和示例,它似乎更接近我们需要的东西,但我不确定如何使它在这种情况下工作。
该应用程序主要使用VB.NET编写,但C#中的示例或帮助也很好。
答案 0 :(得分:2)
您可以将事件的提升重新组合回UI线程。由于这很可能(如果你设计得很好)是从一个单独的类完成的,我的建议是将当前SynchronizationContext的副本传递给处理后台进程的类。
以下是C#中的一些示例代码:
public class BackgroundWork
{
public SynchronizationContext Context { get; private set; }
public BackgroundWork(SynchronizationContext context)
{
this.Context = context;
}
// Thread handler, etc...
// Method to raise event
void RaiseEvent()
{
Context.Post( (state) =>
{
// Raise the event
this.ConnectionStatusChanged(this, EventArgs.Empty);
}, null);
}
}
然后,当你构造类(在你的UI线程中)时,将它传递给当前上下文:
BackgroundWork worker = new BackgroundWork(SynchronizationContext.Current); // This passes the UI thread context...
worker.Start();
(顺便说一句,这是BackgroundWorker类使用的相同技术,这就是为什么它对Windows窗体和WPF都有相同的工作原理......)
答案 1 :(得分:0)
使用Control.Dispatcher.Invoke
:
public void EnventHandlerMethod(object sender, EventArgs e)
{
myLabel.Dispatch.Invoke(new Action(() => { myLabel.Content = "Updated"; }));
}
事件处理程序的签名可能因您正在处理的事件而异。当然,如果您只是在另一个线程中更改控件,则只需要上述方法的主体。
此(我认为)假定.NET 3.5
答案 2 :(得分:0)
尝试使用您想要更改的控件的Invoke方法,或任何控件,并提供一个小功能来完成您想要的工作。或者请参阅BeginInvoke
异步执行此操作。
请注意线程问题,修改“主”线程正在改变的变量等等。