jac*_*078 1 .net c# multithreading winforms
我创建了一个托盘应用程序来控制一些硬件组件。如何在没有主窗体或控件的情况下调用 UI 线程?
托盘应用程序的启动方式为Application.Run(new MyTrayApp()):
class MyTrayApp : ApplicationContext
{
private NotifyIcon trayIcon;
public MyTrayApp()
{
trayIcon = new NotifyIcon()
{
Icon = Resources.app_icon,
ContextMenu = new ContextMenu(new MenuItem[] {
new MenuItem("Exit", Exit)
}),
Visible = true
};
// context is still null here
var context = SynchronizationContext.Current;
// but I want to invoke UI thread in hardware events
MyHardWareController controller= new MyHardWareController(context);
}
void Exit(object sender, EventArgs e)
{
// context is accessible here because this is a UI event
// too late tho
var context = SynchronizationContext.Current;
trayIcon.Visible = false;
Application.Exit();
}
}
Run Code Online (Sandbox Code Playgroud)
Control.Invoke()不可用,因为没有控件SynchronizationContext.Current应保存以供以后调用,但没有ApplicationContext.Load()事件...?MainForm是null在整个周期中。SynchronizationContext我想知道在这种情况下如何初始化?编辑:
只是为了添加一些关于我为什么要调用 UI 线程的背景信息。这是因为System.Threading.ThreadStateException当尝试访问 Windows 资源(例如Clipboard或SendKeys在另一个线程中)时会抛出:
HResult=0x80131520
Message=Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.
Source=System.Windows.Forms
StackTrace:
...
Run Code Online (Sandbox Code Playgroud)
这是另一种蠕虫病毒,但仅供参考:
[STAThreadAttribute]已设置为主功能(无效果)因此Form.Invoke()或等效于调用主线程应该是最简单的。
编辑2:
添加用于重现错误的要点: https://gist.github.com/jki21/eb950df7b88c06cc5c6d46f105335bbf
正如厌恶所提到的那样解决了它Application.Idle!谢谢大家的建议!
托盘应用程序:
class MyTrayApp: ApplicationContext {
private MyHardwareController controller = null;
public MyTrayApp() {
Application.Idle += new EventHandler(this.OnApplicationIdle);
// ...
}
private void OnApplicationIdle(object sender, EventArgs e) {
// prevent duplicate initialization on each Idle event
if (controller == null) {
var context = TaskScheduler.FromCurrentSynchronizationContext();
controller = new MyHardwareController((f) => {
Task.Factory.StartNew(
() => {
f();
},
CancellationToken.None,
TaskCreationOptions.None,
context);
});
}
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
我的硬件控制器:
class MyHardwareController {
private Action < Action > UIInvoke;
public MyHardwareController(Action < Action > UIInvokeRef) {
UIInvoke = UIInvokeRef;
}
void hardware_Event(object sender, EventArgs e) {
// Invoke UI thread
UIInvoke(() => Clipboard.SetText("I am in UI thread!"));
}
}
Run Code Online (Sandbox Code Playgroud)