【发布时间】:2013-03-01 05:01:17
【问题描述】:
这是我在这里的第一篇文章,因为实际上我通常用真棒解决我所有的问题 您可以在此处找到发布数据库。但我现在实际上被困住了:
我正在开发一个遵循 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 对象线程的数据,并从该线程更新我的 ModelObjinstance 的某些属性,因此这些属性会引发属性更改我的ModelObj 和 UI 线程将更新用户界面。
如果 UI 更新花费太多时间,我可能会错过一些 Update() 出现在屏幕上,但 COM 对象会将它们记录在我的 ModelObj 实例中,因此 UI 捕获所有更新,我只是不希望 COM 对象必须等待 UI 更新才能再次调用。
我阅读了大量帖子,然后认为我的RaisePropertyChanged("property") 会失败。
实际上,即使在 COM 对象的线程中,RaisePropertyChanged 也成功执行,因此跟踪我的代码,我看到它切换到我做的 ViewModel 程序集
// Here I'm still in the thread of my COM object!
base.NotifyOfPropertyChange<string>(() => this.property)
然后是 UI 更新。
注意:我正在使用 Caliburn Micro 来绑定我在 WPF 中的视图和我的 ViewModel。
所以我无法追踪这个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 线程构建了一个不可见的控件,只是为了能够调用BeginInvoke 就可以了。
所以我宣布了它:
public static Control mInvokeControl;
delegate void MyDelegate();
private MyDelegate _NotifyDelegate;
然后在我的 Object 的静态构造函数中执行此操作:
mInvokeControl = new Control();
mInvokeControl.CreateControl();
在普通构造函数中,我以这种方式初始化委托:
_NotifyDelegate = new MyDelegate(this.NotifyByInvoke);
然后我就这样用了之后:
ModelObj.mInvokeControl.BeginInvoke(this._NotifyDelegate );
方法是:
public void NotifyByInvoke()
{
RaisePropertyChanged("Update");
}
一切正常!
【问题讨论】:
标签: c# multithreading user-interface com