gpt4 book ai didi

c# - 多线程 COMObject 和 UI 线程 (C#)

转载 作者:行者123 更新时间:2023-11-30 16:19:20 25 4
gpt4 key购买 nike

这是我在这里的第一篇文章,因为实际上我通常用真棒解决我所有的问题
您可以在此处找到发布数据库。但我现在实际上被困住了:

我正在开发一个遵循 MVVM 的项目,包括一个 COM 对象。
正如我在研究期间所读到的,我知道 COM 对象只能从创建它的线程访问。我的 COM 对象实现了以下接口(interface)

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 线程。

现在的问题是:this 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 之间进行绑定(bind)。

所以我无法追踪 base.NotifyOfPropertyChange<string>(() => this.property) .也许 Caliburn 处理线程切换,这不是我的问题。

我能说的是我的 COM 对象线程等待 UI 更新以在我的 RaisePropertyChanged("property") 之后进入下一条指令。 ,所以它与 UI 线程完成整个工作完全一样。

我希望我的 COM 对象线程更新我的 ModelObj它将向 UI 发送一条消息以进行更新(因为 ModelObj 的某些字段已更改)并继续 立即 ,不知道 UI 是否实际更新。

有人知道这种行为吗?

非常感谢你。

####更新####

谢谢大家这么快的回答。

我实际上按照 Zdeslav Vojkovic 的建议做了:

您应该始终从 GUI 线程更新 GUI

为了完整起见,这是我的做法:

因为我的 View 是完整的 WPF,后面没有代码我没有任何控件或表单可以从中调用 BeginInvoke,所以在我的 ModelObj 的静态构造函数中,我从 UI 线程构建了一个不可见的控件,以便能够在其上调用 BeginInvoke .

所以我宣布它:
public static Control mInvokeControl;
delegate void MyDelegate();
private MyDelegate _NotifyDelegate;

然后在我的对象的静态构造函数中执行此操作:
mInvokeControl = new Control();
mInvokeControl.CreateControl();

在普通构造函数中,我以这种方式初始化委托(delegate):
_NotifyDelegate = new MyDelegate(this.NotifyByInvoke);

然后在我以这种方式使用它之后:
ModelObj.mInvokeControl.BeginInvoke(this._NotifyDelegate );

方法是:
public void NotifyByInvoke()
{
RaisePropertyChanged("Update");
}

一切正常!

最佳答案

the COMObj is only accessible from the thread which created it



这不是真的。它取决于对象单元模型,但通常您可以从任何线程访问它,并且它将在同一线程上调用或编码到适当的线程。

我相信您的问题是您从后台线程更新 GUI,这是一个主要的禁忌。您应该始终从 GUI 线程更新 GUI。当您更新模型对象时,它仍然发生在后台线程和 INotifyPropertyChanged 事件上接口(interface)在该线程上触发。

您需要使用类似这样的方法将模型更新同步到 GUI 线程(WinForms,而不是 WPF - 在 WPF 中您应该使用 frm.Dispatcher.BeginInvoke,但问题是一样的):

私有(private)委托(delegate)无效 ExecuteActionHandler( Action Action );
public static void ExecuteOnUiThread(this Form form, Action action)
{
if (form.InvokeRequired) { // we are not on UI thread
// Invoke or BeginInvoke, depending on what you need
// but you said ' and continue immediatly' so BeginInvoke it is
form.BeginInvoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
}
else { // we are on UI thread so just execute the action
action();
}
}

another question with similar problem我在那里提供了更多详细信息。

关于c# - 多线程 COMObject 和 UI 线程 (C#),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15382288/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com