从另一个线程访问UI控件

时间:2013-12-08 01:33:28

标签: c# multithreading wcf

在我使用.NET 4.0为现有第三方应用程序创建C#的插件中,我创建了一个线程,让服务侦听命名管道。

在我设置为OperationContract的函数中,我需要调用处理UI的函数,这些函数有时会在调用后创建新的UI控件。即我收到以下错误:

"在一个线程上创建的控件不能作为另一个线程上的控件的父级"

我发现我应该使用BeginInvoke函数中的OperationContract来访问用户界面,但我的问题是我不知道从哪里获取要调用的对象。我尝试了很多(this.BeginInvokeApplication.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?
        // .
   }

}

如何做到这一点?

2 个答案:

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