WCF,从服务访问Windows窗体控件

我有一个托管在Windows窗体中的WCF服务。

如何从我的服务中的方法访问表单的控件?

比如我有

public interface IService { [ServiceContract] string PrintMessage(string message); } public class Service: IService { public string PrintMessage(string message) { //How do I access the forms controls from here? FormTextBox.Text = message; } } 

首先,ServiceContract属性应该在接口上,而不是PrintMessage()方法。

使用示例的更正版本,您可以这样做。

 [ServiceContract] public interface IService { [OperationContract] string PrintMessage(string message); } public class Service : IService { public string PrintMessage(string message) { // Invoke the delegate here. try { UpdateTextDelegate handler = TextUpdater; if (handler != null) { handler(this, new UpdateTextEventArgs(message)); } } catch { } } public static UpdateTextDelegate TextUpdater { get; set; } } public delegate void UpdateTextDelegate(object sender, UpdateTextEventArgs e); public class UpdateTextEventArgs { public string Text { get; set; } public UpdateTextEventArgs(string text) { Text = text; } } public class MainForm : Form { public MainForm() { InitializeComponent(); // Update the delegate of your service here. Service.TextUpdater = ShowMessageBox; // Create your WCF service here ServiceHost myService = new ServiceHost(typeof(IService), uri); } // The ShowMessageBox() method has to match the signature of // the UpdateTextDelegate delegate. public void ShowMessageBox(object sender, UpdateTextEventArgs e) { // Use Invoke() to make sure the UI interaction happens // on the UI thread...just in case this delegate is // invoked on another thread. Invoke((MethodInvoker) delegate { MessageBox.Show(e.Text); } ); } } 

这基本上是@Simon Fox建议的解决方案,即使用委托。 可以这么说,这可能只会给骨头带来一些肉体。

处理这种情况的最佳方法是将Form作为依赖项注入服务。 我将定义某种类型的接口,将表单代码与WCF代码分离:

 public interface IFormService { string Text { get; set; } } 

您可以通过设置要更新的real属性,让Form实现IFormService接口。

您的服务需要一个IFormService实例来完成其工作:

 public class Service : IService { private readonly IFormService form; public Service(IFormService form) { this.form = form } public string PrintMessage(string message) { this.form.Text = message; } } 

由于Service类现在没有默认构造函数,因此您还需要实现一个自定义ServiceHostFactory,它可以创建Service类的实例并注入IFormService的具体实现。

使用代表。 在表单的代码隐藏中创建一个委托,该委托引用写入文本框并将其传递给服务的方法,然后服务可以在想要打印消息时调用委托。

尝试更新文本框时会遇到问题,因为委托将在与创建文本框的线程不同的线程上调用。 在WPF世界中,您将使用Dispatcher.BeginInvoke来解决这个问题,而不确定WinForms等价物是什么。

该服务需要对表单实例的引用,而不仅仅是表单的类型。

此外,您还需要一种从服务类向表单控件发送值的方法。 这可以通过使控件本身公开或受保护来完成,也可以在窗体类上创建将在控件上设置属性的属性。

一个简单的方法如下:

  1. 向您的服务类添加一个构造函数,该构造函数接受对表单实例的引用。 如果您在表单中托管服务,这应该很容易。
  2. 添加要从服务设置的控件属性的公共属性。 属性应该是public或internal,并将设置controls属性的值。
  3. 在您的服务中,您可以设置新添加的属性的值。

为了完整起见,使用相同的解决方案有一种更简单的方法。

您可以使用invoke方法直接在同一线程上调用委托。

 Invoke(new MethodInvoker(delegate{FormTextBox.Text = message;});