2009-09-02 3 views
5

Windows Form 내에서 호스팅되는 WCF 서비스가 있습니다.WCF, 서비스에서 Windows Forms 컨트롤에 액세스

내 서비스의 메소드에서 양식의 컨트롤에 액세스하려면 어떻게해야합니까? 예를 들어

나는

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

답변

1

가 대리자를 사용합니다. 텍스트 상자에 쓰고이를 서비스에 전달하는 메서드를 참조하는 폼의 코드 숨김에 대리자를 만들면 서비스는 메시지를 인쇄 할 때 대리자를 호출 할 수 있습니다.

텍스트 상자를 만든 스레드와 다른 스레드에서 대리자가 호출되기 때문에 텍스트 상자를 업데이트하는 동안 문제가 발생합니다. WPF 세계에서 Dispatcher.BeginInvoke를 사용하면이 문제를 해결할 수 있습니다. WinForms가 무엇인지 모릅니다.

+0

스레딩에 대한 좋은 지적. 이것은 고통이 될 수 있습니다 :-) –

0

서비스는 양식의 유형뿐만 아니라 양식의 인스턴스에 대한 참조가 필요합니다.

또한 서비스 클래스의 양식 컨트롤에 값을 보내는 방법이 필요합니다. 컨트롤 자체를 public 또는 protected로 만들거나 컨트롤의 속성을 설정할 폼 클래스에서 속성을 만들 수 있습니다.

  1. 이 양식 인스턴스에 대한 참조를 취 서비스 클래스에 생성자를 추가

    간단한 방법은 다음과 같이 될 것이다. 양식 내에서 서비스를 호스팅하는 경우 쉽습니다.

  2. 서비스에서 설정할 컨트롤 속성의 public 속성을 추가하십시오. 속성은 public 또는 internal이어야하며 컨트롤 속성의 값을 설정합니다.
  3. 서비스에서 새로 추가 된 속성의 값을 설정합니다.
3

이러한 시나리오를 처리하는 가장 좋은 방법은 Form을 서비스에 종속성으로 주입하는 것입니다.

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

당신은 당신의 양식을 업데이트하고자하는 부동산을 설정하여 IFormService 인터페이스를 구현 할 수 있습니다 : 나는 WCF 코드에서 양식 코드를 분리시킨다 인터페이스의 어떤 종류를 정의하는 것입니다.

의 작업을 수행 할 IFormService의 인스턴스를 필요가 귀하의 서비스 : 당신은 또한 서비스의 인스턴스를 만들 수있는 사용자 정의 ServiceHostFactory을 구현해야합니다 서비스 클래스는 이제 더 기본 생성자가 없기 때문에

public class Service : IService 
{ 
    private readonly IFormService form; 

    public Service(IFormService form) 
    { 
     this.form = form 
    } 

    public string PrintMessage(string message) 
    { 
     this.form.Text = message; 
    } 
} 

을 IFormService의 구체적인 구현을 삽입하십시오.

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가 제안한 해결책입니다. 이것은 바라건대 그냥 뼈에 살점을 붙이는 것입니다.

+0

"service.TextUpdater = ShowMessageBox;"줄을 제외하고는 매트가 좋아 보입니다. 서비스를 만들 때 : ServiceHost myService = new ServiceHost (typeof (IService), uri); 그렇다면 ServiceUst 유형이고 Service 유형이 아닌 TextUpdater 속성을 설정하려면 어떻게해야합니까? –

+0

오른쪽. TextUpdater 속성을 Service 클래스의 정적 속성으로 만듭니다. 그러면 서비스가 인스턴스화 될 때 위임에 액세스 할 수 있습니다. –

+0

코드 예제를보다 명확하게 업데이트했습니다. –

0

완벽을 기하기 위해 동일한 솔루션을 사용하는 간단한 방법이 있습니다.

invoke 메서드를 사용하여 동일한 스레드에서 대리인을 직접 호출 할 수 있습니다.

Invoke(new MethodInvoker(delegate{FormTextBox.Text = message;}); 
관련 문제