在我使用.NET 4.0为现有第三方应用程序创建C#的插件中,我创建了一个线程,让服务侦听命名管道。
在我设置为OperationContract
的函数中,我需要调用处理UI的函数,这些函数有时会在调用后创建新的UI控件。即我收到以下错误:
"在一个线程上创建的控件不能作为另一个线程上的控件的父级"
我发现我应该使用BeginInvoke
函数中的OperationContract
来访问用户界面,但我的问题是我不知道从哪里获取要调用的对象。我尝试了很多(this.BeginInvoke
,Application.Current.BeginInkove
),但一直无法解决,所以我甚至无法编译它。
以下代码是从与主UI线程不同的线程创建的服务架构。我需要知道如何调用BeginInvoke从名为OperationContractForService(字符串值)的函数中的主UI线程运行一些代码:
using System;
using System.Windows;
using System.Windows.Forms;
using System.ServiceModel;
using System.Threading;
.
.
.
[ServiceContract]
public interface IInterfaceForService
{
[OperationContract]
string OperationContractForService(string value);
}
public class InterfaceForService : IInterfaceForService
{
public string OperationContractForService(string value)
{
// .
// Some code that may create controls in the UI in the main thread
// How do I call BeginInvoke from here?
// .
}
}
如何做到这一点?
答案 0 :(得分:1)
如果从UI线程调用库的方法,则可以捕获当前上下文:
var UiContext = TaskScheduler.FromCurrentSynchronizationContext();
然后你可以启动你的线程,当你想在UI线程上运行代码时,创建一个任务并安排它在捕获的上下文上运行:
Task t = new Task(() =>
//update UI
);
t.Start(uiContext);
或者更好的是,创建一个具有上述计划的TaskFactory,并在需要更新UI时使用它来创建新任务:
TaskFactory tf = new TaskFactory(uiContext);
tf.StartNew(() => { ... });
答案 1 :(得分:0)
你提到你已经尝试了Application.Current.BeginInvoke
,但是你错过了一点:它是Application.Current.Dispatcher.BeginInvoke
。这有用吗?
说实话,不过,我会对你的WCF层中的UI线程有所了解。如果由OperationContract调用的东西创建了一个UI元素,那么让它调用UI线程本身。
如果这是不可行的,我会让你的InterfaceForService
能够告诉哪个TaskScheduler要调度,但是让其他一些层负责确定哪个TaskScheduler对应于UI线程。