这是我这里其实我平时解决与真棒 后的数据库,你可以在这里找到我的所有问题的第一篇文章。但实际上,我坚持现在:多线程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