这是我在这里的第一篇文章,因为实际上我通常用你可以在这里找到的很棒的帖子数据库来解决我的所有问题。但我现在实际上被困住了:
我正在开发一个遵循 MVVM 的项目,包括一个 COM 对象。正如我在研究期间所读到的,我知道 COM 对象只能从创建它的线程访问。我的 COM 对象实现了以下接口
interface IComUpdate
{
void Update();
}
因此,当我创建我的 COM 对象时,每次有更新(我不知道什么时候,它是随机的)时,COM 服务器都会调用Update()
我实现的 COM 对象类。
我的目标是创建一个不同的线程,命名一个 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();
它实际上工作得很好,在Update()
我的 COM 对象的实现中,我实际上看到线程是刚刚创建的线程,而不是 UI 线程。
现在的问题是:ModelObj
我创建的这个实现了INotifyPropertyChanged
接口。
我的想法是:每次 COM 对象收到更新时,我从 COM 对象线程处理数据,并ModelObj
从该线程更新我的实例的某些属性,因此这些属性将引发我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 中的 View 和 ViewModel 之间进行绑定。
所以我无法在此之后追踪base.NotifyOfPropertyChange<string>(() => this.property)
。也许 Caliburn 处理线程切换,这不是我的问题。
我可以说的是,我的 COM 对象线程等待 UI 更新以到达 my 之后的下一条指令RaisePropertyChanged("property")
,所以它与 UI 线程完成整个工作完全一样。
我希望我的 COM 对象线程更新我的ModelObj
,它将向 UI 发送一条要更新的消息(因为其中的某些字段ModelObj
已更改)并立即继续,而不知道 UI 是否实际更新。
有人知道这种行为吗?
非常感谢你。
####更新####
谢谢大家这么快的回答。
我实际上按照 Zdeslav Vojkovic 的建议做了:
您应该始终从 GUI 线程更新 GUI
为了完整起见,这是我的做法:
因为我的视图是完整的 WPF,后面没有代码我没有任何控件或表单可以从中调用 BeginInvoke,所以在我的 ModelObj 的静态构造函数中,我从 UI 线程构建了一个不可见的控件,以便能够在其上调用 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");
}
一切正常!