2013-11-20 60 views
1

我正在玩托盤應用程序。應用程序僅在系統托盤中運行,並且沒有與之關聯的Windows窗體。應用程序使用ManagementEventWatcher並在特定情況下顯示警報窗口。托盤應用程序:從後臺線程事件處理程序在主線程上創建UI

[STAThread] 
static void Main() 
{ 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 

    Application.Run(new AppContext()); 
} 

...

public class AppContext : ApplicationContext 
{ 
    private System.ComponentModel.IContainer _components; 
    private NotifyIcon _notifyIcon; 
    private ContextMenuStrip _contextMenu; 
    private ManagementEventWatcher _regWatcher; 


    public AppContext() 
    { 
     //Initialize context menu & tray icon 

     _regWatcher = new ManagementEventWatcher(query); 
     _regWatcher.EventArrived += new EventArrivedEventHandler(_regWatcher_EventArrived); 
     _regWatcher.Start(); 
    } 

    void _regWatcher_EventArrived(object sender, EventArrivedEventArgs e) 
    { 
     Alert.Show("Alert!", "My Message", someParam); 
    } 
} 

...

public class Alert 
{ 
    public static void Show(string title, string message, string extraInfo) 
    { 
     new Alert(title, message, extraInfo).ShowDialog(); 
    } 

    private Alert(string title, string message, string extraInfo) 
    { 
     InitializeComponent(); 

     this.Icon = Properties.Resources._default; 
     this.Text = title; 
     this.label1.Text = message; 
     this.linkLabel1.Text = extraInfo; 
    } 
} 

有趣的是,它不抱怨線程安全的方式不訪問UI。我想因爲它只存在於這個後臺線程上。但稍後當表單嘗試訪問剪貼板時,它不起作用,因爲它正在MTA線程上運行。到目前爲止,我發現的所有類似問題都有調用Invoke的窗體,或者可以選擇使用BackgroundWorker。在這種情況下,在主線程上創建和顯示Alert Form的最佳方法是什麼?

+1

見安迪·懷特菲爾德的博客[這裏](http://nosuchblogger.com/post/60/applicationcontext-and-the-ui-thread),他採用的是**的SynchronizationContext()**解決類似的問題。 –

+0

@Idle_Mind這是對的錢!我將探討這一點。 – xr280xr

+0

我不完全確定你的意思,@HansPassant。我可能在那裏做了一個假設,但是我知道的是當_regWatcher_EventArrived事件處理程序執行時,System.Threading.Thread.CurrentThread.ThreadState是Background和System.Threading.Thread.CurrentThread.ApartmentState是MTA。 – xr280xr

回答

0

感謝Idle_Mind鏈接到Andy Whitfield's blog post我已經到了解決方案。我向AppContext類添加了一個私有全局SynchronizationContext。在構造函數中,我將它初始化爲一個WindowsFormsSynchronizationContext的實例。然後,當註冊表觀察者的事件發生時,我可以將任務發回主線程。

public class AppContext : ApplicationContext 
{ 
    private SynchronizationContext _uiThreadContext; 
    ... 
    public AppContext() 
    { 
     //Initialize context menu & tray icon 

     _uiThreadContext = new WindowsFormsSynchronizationContext(); 

     _regWatcher = new ManagementEventWatcher(query); 
     _regWatcher.EventArrived += new EventArrivedEventHandler(_regWatcher_EventArrived); 
     _regWatcher.Start(); 

     ... 
    } 

    private void _regWatcher_EventArrived(object sender, EventArrivedEventArgs e) 
    { 
     ... 
     _uiThreadContext.Post(new SendOrPostCallback(MyEventHandler), parameters) 
    } 
+1

'SynchronizationContext.Current'返回UI線程上下文,如果你在UI線程上調用它(啓動Application類後)。非常好的速記。 – Gusdor

相關問題