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

时间:2009-09-02 07:45:49

标签: c# asp.net wcf

我有一个托管在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;
    }
}

5 个答案:

答案 0 :(得分:5)

首先,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建议的解决方案,即使用代表。希望这可以说是骨头上的一些肉体,可以这么说。

答案 1 :(得分:3)

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

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

您可以通过设置要更新的不动产来让您的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的具体实现。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

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

一种简单的方法如下:

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

答案 4 :(得分:0)

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

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

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