2

我想要实现的简化版本:

  • 我有一个在后台运行隐藏(可见 = false)的 WinForms 应用程序。
  • 它只有一个表格,我保留了默认名称 - Form1
  • 此 WinForms 应用托管 WCF 服务。现在我们将其称为监听器服务。
  • 此侦听器服务有一个名为“DisplayAlert()”的函数,它作为服务函数公开
  • 位于另一台计算机上的应用通过标准 WCF 服务调用向侦听器服务发送消息

我已经完成了上述所有工作。在调用 DisplayAlert() 函数时,我可以单步执行代码并观察消息流。

我想不通,我不敢相信很难找到如何做这么简单的事情:

- 我希望托管服务中的 DisplayAlert() 函数直接与托管它的 WinForm 交互以使表单可见。

我要做的就是将 Visibility 设置为 true,然后在 WinForm 上调用另一个函数。

在我看来,这应该像添加对表单的引用一样简单,或者在表单上创建一个公共函数并从服务类调用它,但我什至不知道如何从服务中引用 Form1班级。

我错过了一些明显的东西吗?我什至如何引用托管服务的 Form1 的实例?

我已经走上了……的路。

  • 在ListenerService(AlertReceived,virtual void OnAlertReceived)中创建一个事件,认为在Form上,我可以添加一个事件处理程序。
    • 没有骰子。我没有直接实例化 ListenerService 类,它在 ServiceHost 中运行。
  • 试图从类中引用 Application 对象,认为我可以将其引用为 Application.Form1,但不是。我什至无法从服务类中看到 Application 对象。
    • 我可能在这里遗漏了一些明显的东西,但我不确定。

还有其他建议吗?

如果有帮助,我可以添加代码。

4

3 回答 3

11

使用这种方法,您就拥有了一个完全线程安全的应用程序,并且没有任何限制。

服务合同定义

[ServiceContract]
public interface IService
{
    [OperationContract]
    void DisplayAlert();
}

服务实施

public class Service:IService
{
    public void DisplayAlert()
    {
        var form = Form1.CurrentInstance;
        form.MySynchronizationContext.Send(_ => form.Show(), null);
    }
}

程序.cs

[STAThread]
static void Main()
{        
    var host = new ServiceHost(typeof (Service));
    host.Open();

    Application.SetCompatibleTextRenderingDefault(false);
    Application.EnableVisualStyles();
    Application.Run(new Form1());
 }

表单实现

public partial class Form1 : Form
{
    public static Form1 CurrentInstance;
    public SynchronizationContext MySynchronizationContext;
    private bool showForm = false;

    public Form1()
    {
        InitializeComponent();
        MySynchronizationContext = SynchronizationContext.Current;
        CurrentInstance = this;
    }

    // use this method for hiding and showing if you want this form invisible on start-up
    protected override void SetVisibleCore(bool value)
    {
        base.SetVisibleCore(showForm ? value : showForm);
    }

    public void Show()
    {
        showForm = true;
        Visible = true;   
    }

    public void Hide()
    {
        showForm = true;
        Visible = true;
    }
}

客户

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press Enter to show form");
        Console.ReadLine();

        var client = new ServiceClient();
        client.DisplayAlert();
    }
}
于 2012-06-29T19:40:32.083 回答
1

在我看来,正如一位朋友所说,答案是“simpol”。首先,我什至不会费心遵循您描述的路径,毕竟 Web 服务提供了与之通信的所有必要手段。在您的 Form1(托管您的服务)和您的托管服务之间添加一个客户端(其中客户端代码由相同的 Form1 托管)并允许您的客户端使用双工通道与您的服务进行通信。通过这种方式,您的客户端将通过发起一个长时间运行的请求并通过回调得到通知来了解是否有消息发送到您的服务。这是与双工通道相关的精美文章的链接:http: //blogs.msdn.com/b/carlosfigueira/archive/2012/01/11/wcf-extensibility-transport-channels-duplex-channels.aspx

PS:这是一个粗略的建议,可以帮助您入门,肯定可以改进。

于 2012-06-29T19:00:43.300 回答
0

您可以为您的服务使用单例吗?如果是这样,您可以像这样实现它:

[ServiceContract]
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyClass : IMyClass
{
    Form1 _f;
    public MyClass(Form1 f)
    {
        _f = f;
    }

    [OperationContract]
    public void Alert(string mess)
    {
        _f.Text = mess;
    }
}

然后,当您设置服务主机时,将其实例化并将其传递给表单:

MyClass c = new MyClass(this);
string baseAddress = "http://localhost:12345/Serv";
var host = new ServiceHost(c, new Uri(baseAddress));
于 2012-06-29T19:04:45.057 回答