2009-09-02 12 views
5

Mam usługę WCF, która jest obsługiwana w formularzu systemu Windows.WCF, Dostęp do systemu Windows tworzy formanty z usługi

Jak uzyskać dostęp do elementów sterujących formularza z metod dostępnych w mojej usłudze?

na przykład mam

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

Odpowiedz

1

Użyj delegata. Utwórz delegata w kodzie strony swojego formularza, który odwołuje się do metody, która zapisuje do pola tekstowego i przekazuje ją do usługi, usługa może następnie wywołać delegata, gdy chce wydrukować wiadomość.

Będziesz miał problemy z aktualizacją pola tekstowego, ponieważ delegat zostanie wywołany w innym wątku niż ten, w którym został utworzony. W świecie WPF należy użyć Dispatcher.BeginInvoke, aby obejść ten problem, nie mając pewności, czym jest ekwiwalent WinForm.

+0

Dobra uwaga na temat przewlekania. To może być bolesne :-) –

0

Usługa będzie wymagać odniesienia do instancji formularza, a nie tylko do typu formularza.

Ponadto będziesz potrzebował sposobu na przesłanie wartości do formantów formularza z twojej klasy usług. Można to zrobić, czyniąc same elementy sterujące publicznymi lub chronionymi, lub można tworzyć właściwości w klasie formularza, które ustawią właściwości w kontrolkach.

Prostym rozwiązaniem byłoby następujące:

  1. Dodaj do konstruktora klasy usług, które ma odniesienie do instancji formularza. Jeśli hostujesz swoją usługę w formularzu, powinno to być łatwe.
  2. Dodaj właściwości publiczne dla właściwości sterowania, które chcesz ustawić z usługi. Właściwości powinny być publiczne lub wewnętrzne i ustawią wartości właściwości kontrolnych.
  3. W swojej usłudze ustalasz wartości nowo dodanych właściwości.
3

Najlepszym sposobem radzenia sobie z takim scenariuszem jest wprowadzenie formularza do usługi jako zależności. ja bym zdefiniował jakiś interfejs, który oddziela kod formularza z kodem WCF:

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

możesz mieć swój Formularz implementować interfejs IFormService ustawiając nieruchomość, którą chcesz zaktualizować.

Usługa musiałby wystąpienie IFormService zrobić swoją pracę:

public class Service : IService 
{ 
    private readonly IFormService form; 

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

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

Ponieważ klasa Serwis teraz nie ma domyślnego konstruktora, będzie trzeba także wdrożenie niestandardowych ServiceHostFactory który może tworzyć instancje Serwisie klasy i wstrzyknąć konkretną implementację IFormService.

5

Przede wszystkim atrybut ServiceContract powinien znajdować się w interfejsie, a nie w metodzie PrintMessage().

Korzystając ze skorygowanej wersji swojego przykładu, możesz to zrobić w ten sposób.

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

Jest to zasadniczo rozwiązanie sugerowane przez @Simon Fox, tj. Użyj delegata. Miejmy nadzieję, że po prostu kładzie trochę ciała na kościach, że tak powiem.

+0

To wygląda dobrze Matt z wyjątkiem linii "service.TextUpdater = ShowMessageBox;" Kiedy tworzę usługę, wykonuję: ServiceHost myService = new ServiceHost (typeof (IService), uri); Jak ustawić właściwość TextUpdater, jeśli jest to ServiceHost, a nie Service? –

+0

Dobrze. Ustaw właściwość TextUpdater jako statyczną właściwość klasy Service. Twoja usługa będzie wtedy miała dostęp do delegata po jego utworzeniu. –

+0

Zaktualizowałem przykład kodu, aby było bardziej zrozumiałe. –

0

Dla kompletności istnieje prostsze podejście przy użyciu tego samego rozwiązania.

Możesz bezpośrednio wywołać delegata w tym samym wątku, używając metody invoke.

Invoke(new MethodInvoker(delegate{FormTextBox.Text = message;}); 
Powiązane problemy