簡體   English   中英

WCF,從服務訪問Windows窗體控件

[英]WCF, Accessing a windows forms controls from a service

我有一個在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; }
}

您可以通過設置要更新的不動產來讓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;});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM