Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Threads und Controls
Xqgene
myCSharp.de - Member



Dabei seit:
Beiträge: 2.051

Themenstarter:

Threads und Controls

beantworten | zitieren | melden

Folgendes Szenario:

es gibt eine Klasse A. diese Klasse bekommt beim Erstellen als Parameter Verweis auf ein Interface I. Nun startet Klasse A ein Thread T, um sagen wir Berechnung durchzuführen. Wenn Berechnung fertig ist, ruft Klasse A aus dem Thread T eine Methode des Interfaces I.

Nun Problem ist, dass in dieser Methode werden unter anderem auch Controls aktualisiert. Und das geht nicht, da Controls „singlethreadig“ (tolles Wort habe ich ausgedacht ) sind.

Also, wie löse ich das Problem am besten?

Irgendwelche Ideen?
"A programmer is a tool which converts coffein to code."

Evely ToDo-Manager 1.2 (Build 1.2.585)
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Xqgene,

mit Control.Invoke bzw. Control.BeginInvoke. Oder willst du auf was anderes hinaus?

herbivore
private Nachricht | Beiträge des Benutzers
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

beantworten | zitieren | melden

Wenn Du Zugriff auf ein "Control" hast, dann mit Control.Invoke (.....)

Wenn Du keinen Zugriff auf ein Control hast, dann brauchst Du Zugriff auf ein im UI-Thread erstelltes ISynchronizeInvoke - Objekt um dort Invoke zu machen...

PS: UI-Controls implementieren ISynchronizeInvoke daher haben diese die Invoke-Mehthode
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers
Xqgene
myCSharp.de - Member



Dabei seit:
Beiträge: 2.051

Themenstarter:

beantworten | zitieren | melden

genau das ist es, dass ich keinen Zugriff auf Controls habe. und ich möchte nur sehr ungern das Interface so erweitern, dass so ein Zugriff ermöglicht wird.

mal sehen... wenn nix anderes übrig bleibt.
"A programmer is a tool which converts coffein to code."

Evely ToDo-Manager 1.2 (Build 1.2.585)
private Nachricht | Beiträge des Benutzers
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

beantworten | zitieren | melden

Pack ein Objekt vom Type ISynchronizeInvoke auf Dein Interface... dann kannnste ein Form übergeben (hast aber nur Zugriff auf Invoke und dessen Kollegen).... das Interface bleibt so vollkommen offen.
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers
Xqgene
myCSharp.de - Member



Dabei seit:
Beiträge: 2.051

Themenstarter:

beantworten | zitieren | melden

hast recht. ich werde mal so machen.

danke für eure mühe.
"A programmer is a tool which converts coffein to code."

Evely ToDo-Manager 1.2 (Build 1.2.585)
private Nachricht | Beiträge des Benutzers
Pulpapex
myCSharp.de - Member



Dabei seit:
Beiträge: 939
Herkunft: Rostock

beantworten | zitieren | melden

Geht es nicht noch einfacher?

Klasse A ruft aus einem "Nicht-GUI"-Thread Methoden des Interfaces auf. Das Interface soll frei von Forms und anderem Schnickschnack bleiben. Die konkrete Implementierung des Interfaces aber, die dann aufgerufen wird, aktualisiert Controls wie du gesagt hast. D.h. sie hält Referenzen auf die Controls. Dann kann doch sie Control.Invoke zum Aktualisieren benutzen. Wozu das öffentliche Interface erweitern?


Gruss
Pulpapex
private Nachricht | Beiträge des Benutzers
Xqgene
myCSharp.de - Member



Dabei seit:
Beiträge: 2.051

Themenstarter:

beantworten | zitieren | melden

über diese Möglichkeit habe ich auch schon nachgedacht, aber allein der Gedanke, dass die Klasse, die sich hinter einem Interface versteckt, verantwortlich über mögliche "thread"-Spielchen der Hostklasse sein soll, gefällt mir noch weniger als ISynchronizeInvoke-Methode.
"A programmer is a tool which converts coffein to code."

Evely ToDo-Manager 1.2 (Build 1.2.585)
private Nachricht | Beiträge des Benutzers
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

beantworten | zitieren | melden

Uebrigens so kann man eine Methode in einer Klasse welche ISynchronizeInvoke (z.B: Control / Form usw.) bauen, dass es egal ist woher der Aufruf erfolgt.

Multithreads, DataGrid
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers
Pulpapex
myCSharp.de - Member



Dabei seit:
Beiträge: 939
Herkunft: Rostock

beantworten | zitieren | melden

Man kann es auch von der anderen Seite betrachten.

Control.Invoke ist ein Workaround für eine aus der Win-Api geerbte Unzulänglichkeit von Windows-Forms, nicht mit mehreren Threads umgehen zu können. Warum diese technische Eigenart veröffentlichen und dadurch das Interface versauen?

Es wird quasi unbenutzbar. Und es wird fehleranfälliger, da Members öffentlich gemacht werden, die nicht verwendet werden dürfen - jedenfalls nicht direkt.

Hier ein Beispiel wie ich das meine:

public interface IFileProcessorView {
   public string CurrentAction( get; set; );   // Nur über UIThread aufrufen.
   public string CurrentFile( get; set; );     // Nur über UIThread aufrufen.
   public double OverallProgress( get; set; ); // Nur über UIThread aufrufen.
   public double FileProgress( get; set; );    // Nur über UIThread aufrufen.
   public ISynchronizeInvoke UIThread { get; }
}

// Im Thread ausgeführte Methode.
private void ThreadMethod() {

   IFileProcessorView view = this.fileProcessorView;

   // Verboten!
   view.CurrentAction = "Deleting File ...";


   // Stattdessen folgender Code ...

   // Parameter für BeginInvoke vorbereiten.
   SetCurrentActionDelegate setCurrentAction = 
      new SetCurrentActionDelegate(SetCurrentAction);
   string[] action = new string[] {"Deleting File ..."};

   // BeginInvoke: im UIThread ausführen.
   view.UIThread.BeginInvoke(setCurrentAction, action);
}

// Für den Delegaten notwendige Hilfsmethode.
private void SetCurrentAction(string action) {
   IFileProcessorView view = this.fileProcessorView;
   view.CurrentAction = action;
}

// Delegate für Invoke.
private delegate void SetCurrentActionDelegate(string action);
Das wiederholt sich an allen Stellen wo auf das Interface zugegriffen wird.

Versteckt man den Code in der Implementierung, braucht man sich nicht mehr darum zu kümmern und kann die Interface-Members wieder direkt verwenden. Nur die Implementierung soll ja wissen, dass im Hintergrund Windows-Controls aktualisiert werden.
private Nachricht | Beiträge des Benutzers
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

beantworten | zitieren | melden

@Pulpalex

Noch schöner ist es wenn die Methode auf sich selber wrappt... siehe meinen Link...

Die Kapselung ist dadurch noch viel besser.... das Objekt wird somit ThreadSicher... bedingt allerdings dass das Objekt ISynchronizeInvoke implementiert.
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers
Xqgene
myCSharp.de - Member



Dabei seit:
Beiträge: 2.051

Themenstarter:

beantworten | zitieren | melden

das bsp von Pulpalex hat mich jetzt doch überzeugt.
und das wrappen von Programmierhans finde ich auch sehr interessant.

ich bedanke mich bei allen.


P.S. sollte jemand 'ne möglichkeit ohne Control.Invoke kennen/ausdenken, werde ich im tausend danke-schön-mails senden.
"A programmer is a tool which converts coffein to code."

Evely ToDo-Manager 1.2 (Build 1.2.585)
private Nachricht | Beiträge des Benutzers
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

beantworten | zitieren | melden

Zitat
Original von Xqgene

P.S. sollte jemand 'ne möglichkeit ohne Control.Invoke kennen/ausdenken, werde ich im tausend danke-schön-mails senden. :D

Control.BeginInvoke
Control.EndInvoke



aber bitte nicht vollspamen
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers