這是我這裏其實我平時解決與真棒 後的數據庫,你可以在這裏找到我的所有問題的第一篇文章。但實際上,我堅持現在:多線程COMObject和UI線程(C#)
我工作的一個項目MVVM包括COM對象以下。 正如我在研究中讀到的,我明白COM對象只能從創建它的線程訪問。我的COM對象實現以下接口
interface IComUpdate
{
void Update();
}
所以,當我創建我的COM對象,每次有更新(我不知道什麼時候,它的隨機)的COM服務器將調用COM對象類我的Update()
執行。
我的目標是創建一個不同的線程,命名一個COM對象線程,其中COM對象獨立於我的UI線程存在,所以每次有更新時,我都會在與UI線程不同的線程中處理它。
其實這是工作:
在我的ViewModel的開始,我創建一個特定的對象的集合。
這個對象,可以把它叫做ModelObj
,是模型的一部分,定義了一個靜態構造函數中的應用,除了初始化一些變量,COM對象創建並啓動一個新的線程:
Thread t = new System.Threading.Thread(() =>
{
System.Threading.Thread.CurrentThread.Name = "Thread of COM Object";
IComUpdate myComObj;
myComObj = (IComUpdate)Activator.CreateInstance(blabla);
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
它實際上工作得很好,在我的COM對象的Update()
實現中,我確實看到線程是剛剛創建的線程,而不是UI線程。
現在的問題是:這個ModelObj
我創建實現了INotifyPropertyChanged
接口。
我的想法如下:每次COM對象接收到更新時,我都會處理來自COM對象線程的數據,並從此線程更新我的ModelObj
實例的某些屬性,以便這些屬性將引發屬性更改我的ModelObj
和UI線程將更新用戶界面。
如果UI更新需要太多時間,我可能會錯過一些Update()
出現在屏幕上,但COM對象將它們記錄在我的ModelObj
實例中,因此UI捕獲所有更新並不重要,I只是不希望COM對象不得不等待UI被更新以再次調用。
我讀噸的帖子,然後以爲我RaisePropertyChanged("property")
會失敗。
其實即使是在COM對象的線程中,RaisePropertyChanged
成功執行,那麼跟蹤我的代碼,我把它切換到我的視圖模型組件,在那裏我做
// Here I'm still in the thread of my COM object!
base.NotifyOfPropertyChange<string>(() => this.property)
,然後UI更新。
注:我使用微卡利我在WPF查看和我的視圖模型之間的結合。
所以我可以在此base.NotifyOfPropertyChange<string>(() => this.property)
後無法跟蹤。也許Caliburn處理線程切換,這不是我的問題。
我能說的是,我的COM對象線程等待UI更新以在我的RaisePropertyChanged("property")
之後到達下一條指令,所以它和UI線程完成整個工作完全一樣。
我希望我的COM對象的線程來更新我的ModelObj
將發送發送UI消息更新(因爲這ModelObj
的某些領域已經改變),並繼續立刻,不知道如果UI實際上更新或不。
有人對此行爲有了解嗎?
非常感謝。
#### UPDATE ####
謝謝大家對這樣的快速解答。
我確實是因爲Zdeslav Vojkovic建議:
你應該總是從GUI線程
爲了完整更新GUI這裏是我是如何做到:
因爲我的看法是完全WPF背後沒有代碼我沒有任何控件或窗體可以調用BeginInvoke,所以在我的ModelObj的靜態構造函數中,我從UI Thread構建了一個不可見的控件,只是爲了能夠調用BeginInvoke。
因此,我宣佈它:
public static Control mInvokeControl;
delegate void MyDelegate();
private MyDelegate _NotifyDelegate;
,然後做這在我的對象的靜態構造函數:
mInvokeControl = new Control();
mInvokeControl.CreateControl();
在正常的構造我初始化委託這種方式:
_NotifyDelegate = new MyDelegate(this.NotifyByInvoke);
然後我就這樣用它:
ModelObj.mInvokeControl.BeginInvoke(this._NotifyDelegate);
所述方法的:
public void NotifyByInvoke()
{
RaisePropertyChanged("Update");
}
一切正常!
「COMObj只能從創建它的線程訪問」,你其實是對的。我只是爲其他人添加評論: 如果我讓我的新線程MTA,COMObj駐留在主線程(因爲它是第一個調用CoInitialize類似的東西,我明白)。但ThreadingModel(請參閱註冊表編輯器)是Apartment,這就是爲什麼在我的具體情況中這是真的。 – user2164703 2013-03-13 10:35:28
我只是有一個剩餘的問題,假設我調用BeginInvoke過程,但正如我所說,它需要更多的時間來更新UI比處理數據,我會做其他BeginInvoke調用之前的行動終止在UI線程上。我的通話是否丟失或排隊?我寧願讓它迷路。 – user2164703 2013-03-13 12:51:00
不確定WPF,因爲我沒有使用它,但是對於WinForms來說,這些調用被確定,因爲它們實際上是用PostMessage處理的。如果WPF表單不會使用某種類似的技術,我會感到驚訝 - 確保這些調用不會丟失,但我不確定執行順序是否有保證。在這裏看到更多:http://stackoverflow.com/a/2411183/1663919 – 2013-03-13 12:55:10