2012-06-29 53 views
2

簡化了我想要實現的版本:自託管(WinForm)WCF服務如何與主窗體進行交互?

  • 我有在後臺運行,隱藏(visible = FALSE)WinForms應用程序。
  • 它只有一個窗體,並保留默認名稱 - Form1
  • 此WinForms應用程序託管一個WCF服務。現在我們將其稱爲監聽器服務。
  • 該偵聽器服務有一個稱爲函數「DisplayAlert()」這是作爲服務公開功能
  • 應用程式坐在另一臺機器上通過一個標準的WCF服務呼叫

我將消息發送到所述偵聽器服務上面所有的工作都很好。在調用DisplayAlert()函數時,我可以遍歷代碼並觀察消息流。

我想不通,我不能相信這是很難找到如何做這個簡單:

- 我想在託管服務交互的DisplayAlert()函數直接使用WinForm來託管它以使窗體可見。

我想要做的就是將Visibility設置爲true,並在WinForm上調用另一個函數。

在我看來,它應該像添加對錶單的引用,或者在表單上創建公共函數並從服務類調用它一樣簡單,但我甚至無法弄清楚如何引用Form1從服務類內。

我錯過了一些明顯的東西嗎?我怎樣才能參考託管服務的Form1的實例?

我已南下的路徑....

  • 創建於ListenerService(AlertReceived,虛擬無效OnAlertReceived)事件,以爲Form上,我可以添加一個事件處理程序。
    • 沒有骰子。我沒有直接實例化ListenerService類,它在ServiceHost中運行。
  • 試圖從類內部引用應用程序對象,認爲我可以將它引用爲Application.Form1,但不是。我甚至無法從服務類中看到Application對象。
    • 我可能在這裏丟失了一些明顯的東西,但我不確定。

其他建議?

如果有幫助,我可以添加代碼。

+0

如果有沒有一個辦法直接做到這一點,我把它看作一個答案,並重新思考設計。 – David

回答

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); 
    } 
} 

的Program.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(); 
    } 
} 
1

在我看來,答案是「simpol」,正如一位朋友所說。首先,我甚至懶得去遵循你描述的路徑,畢竟網絡服務提供了所有必要的手段來與它溝通。在您的Form1(託管您的服務)和您的託管服務之間添加一個客戶端(其中客戶端代碼由相同的Form1託管),並允許您的客戶端使用雙工通道與您的服務進行通信。通過這種方式,您的客戶端可以通過發起長時間運行的請求並通過回調得到通知來知道消息是否已發送到您的服務。這裏是一個鏈接與一個奇特的文章有關雙工渠道:http://blogs.msdn.com/b/carlosfigueira/archive/2012/01/11/wcf-extensibility-transport-channels-duplex-channels.aspx

P.S:這是一個粗略的建議,讓你開始,肯定可以改善。

+0

謝謝!我們想要避開很多開放渠道,併爲此投票。我們的零售地點的帶寬與十億個其他功能捆綁在一起,所以在商店層面,我們確實需要一些東西,直到有理由發送警報爲止。在另一種情況下,我會使用你的建議,所以+1。 – David

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));