Laden...

[erledigt] asychrones Anzeigen eines WPF-Fensters aus einer DLL dauert (relativ) lange

Erstellt von Hurby vor 9 Jahren Letzter Beitrag vor 9 Jahren 2.381 Views
H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren
[erledigt] asychrones Anzeigen eines WPF-Fensters aus einer DLL dauert (relativ) lange

Hallo,

ich habe eine DLL, welche Daten durch einen WCF-Dienst validieren lässt. Während des Verbindungsaufbaus und der Validierung möchte ich ein kleines "Bitte warten"-Fenster anzeigen.

Im Konstruktor der entsprechenden Klasse wird als erstes das Anzeigen des Fensters initiiert, die Methode dazu sieht wie folgt aus:


private void ShowBusyWindow(string text)
{
    Thread thread = new Thread(() =>
    {
        BusyWindow busyWindow = new BusyWindow(text);
        busyWindow.ShowDialog();
    });

    thread.SetApartmentState(ApartmentState.STA);
    thread.IsBackground = true;
    thread.Start();
}

Nach der Instanziierung wird durch den Aufrufer die eigentliche Validierung angestoßen, welche synchron erfolgt. Obwohl das Fenster, bis auf das Setzen einer DP im Konstruktor, keinerlei Logik enthält, dauert das Anzeigen dessen relativ lange, sodass es erst kurz vor Abschluss der Validierung kurz angezeigt wird.

Meine Frage ist nun, warum das Anzeigen des Fensters so (relativ) lange dauert, sowie ob und wie sich dies beschleunigen lässt?

Vielen Dank im Voraus für eure Anregungen...

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

5.299 Beiträge seit 2008
vor 9 Jahren

weißnicht, warums so lahm ist, aber warum zeigst du es nebenläufig an?
Warum nicht ganz normal?

AFAIK sollte es nur einen Gui-Thread geben, und die Validierung wäre der Task, der nebenläufig erfolgen sollte.

Der frühe Apfel fängt den Wurm.

T
314 Beiträge seit 2013
vor 9 Jahren

Du musst den Spieß umdrehen. Die Validierung im Hintergrund ausführen und solange diese dauert deinen WaitDialog anzeigen. Dann erledigt sich der Rest von alleine.

F
10.010 Beiträge seit 2004
vor 9 Jahren
H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren

Hallo,

das Fenster wird asynchron angezeigt, weil die Bibliothek letzten Endes von nativen COM-Komponenten genutzt wird. Da ich keinen Einfluss darauf habe, in welchen Apartments diese laufen, erstelle ich einen neuen Thread und setzte ihn explizit auf STA. Die nebenläufige Validierung der Daten bringt eine Zeitersparnis von 0,4 Sekunden. Ich gehe mittlerweile davon aus, dass wenn man alleine den Umfang der von der WPF zur leistenden Arbeit berücksichtigt, eine Reaktionszeit von ~ 0,7 Sekunden durchaus akzeptabel ist.

Trotzdem vielen Dank für eure Mühen.

PS: @FZelle: Die Richtlinien in den verlinkten Informationen sind mir geläufig und werden natürlich in dem fertigen Produkt zum Tragen kommen. Das Snippet ist daher lediglich als (quick and dirty) Test anzusehen...

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Die Richtlinien in den verlinkten Informationen sind mir geläufig und werden natürlich in dem fertigen Produkt zum Tragen kommen.

Äh, scheinbar nicht, denn da steht ganz eindeutig drin das UI Elemente niemals in einem anderen Thread ( einem nicht dem UI Thread entsprechenden ) erzeugt werden dürfen.
Und was machst du in den ersten Zeilen deines Postings?

Das Snippet ist daher lediglich als (quick and dirty) Test anzusehen...

Das habe ich in den letzten 30 Jahren oft gehört, und dann doch 1:1 im Produktionscode gefunden.
Deshalb, gleich richtig machen, zeigt auch den anderen das man es verstanden hat und führt nicht zu den dann unerwünschten Antworten.

H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren

Hallo,

der Punkt ist der, dass ich bisher nur "reine" WPF-Anwendungen erstellt habe, in denen man ja auf eine bestehende Nachrichtenschleife und UI-Thread aufsetzt. Nun habe ich aber eine reine DLL, welche mittels Verweise auf die entsprechenden WPF-Komponenten die Funktionalität quasi untergejubelt bekommt. Da muss ich zugeben, taten sich dann doch ein paar Wissenslücken auf.

Mein Ablauf sieht nun wie folgt aus:

  1. Erzeugen eines neuen UI-Threads und Dispatchers im Konstruktor mittels:

Thread uiThread = new Thread(() =>
{
    this.dispatcher = Dispatcher.CurrentDispatcher;
    Dispatcher.Run();
});

uiThread.SetApartmentState(ApartmentState.STA);
uiThread.Start();

  1. Dispatchen der GUI-Operationen an
this.dispatcher
  1. Nach getaner Arbeit mittels
this.dispatcher.InvokeShutdown();

aufräumen

Ist diese Vorgehensweise (Hauptaugenmerk sind Schritt 1 und 3) so korrekt?

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Nein.
Wozu meinst du das machen zu müssen?

Wenn du in deiner DLL irgendeine Langlaufende Aktion hast, ist der Aufrufer
für das behandeln/erzeugen von UI Elementen zuständig.

H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren

Du meinst also, dass die DLL lediglich die Validierungsfunktionalität bereitstellt und die UI in die aufrufende Anwendung verlegt werden soll?

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Nein.

Aber die UI Aktionen haben vom UI Thread zu erfolgen.
Ob diese Aktion nun in der DLL ist oder nicht ist nebensächlich.

H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren

Okay. Da allerdings der Consumer der DLL ein Cobol-Programm hust ist, wird die UI in der DLL landen. Das Problem ist dass ich den initialen Appartement-State nicht kenne. Deswegen muss ich doch zwangsläufig einen neuen Thread nutzen um den State festzulegen, oder?

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Vor allem musst du mal genauer sagen was du da wirklich machst, denn das du jedesmal mit irgendeiner anderen "Kleinigkeit" kommst ist nicht hilfreich eine Lösung zu finden.

Also mal grundsätzlich was soll das werden?
Ein Cobol Programm ruft deine Funktion per COM auf?

Dann ist erstmal Primär das Cobol Programm dafür zuständig die UI zu bedienen.
Rückmeldungen macht man i.A. durch Callbacks.

Sollte sowas nicht möglich sein, was wir auch gelegentlich haben,
mache ich das meist indem ich per IPC mit einem Program im Tray kommuniziere das dann wiederum die Ausgabe übernimmt.

Hat den Vorteil, das man das auch z.B. durch Austausch des IPC Endpunkt ( z.b. WCF ) auch auf andere Maschinen routen kann und/oder in einer DB mitloggt.

Aber in einem absoluten Ausnahmefall kann oder muss man selber eine Nachrichtenschleife machen.

H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren

So ist es, allerdings ruft die Cobol-Runtime die DLL nicht direkt auf, sondern bedient sich dazu einer C++/CLI-DLL, welche die C#-DLL wrappt. Aus (vorrangig) ästhetischen Gründen soll die Oberfläche auf WPF basieren.

Die C#-DLL ist allerdings keine Benutzersteuerelementbibliothek, sondern eine einfache DLL, welche WPF- XAML-Funktionalität besitzt. Demnach sind doch beim Einstieg noch keinerlei WPF-spezifischen Dinge (Nachrichtenschleife und UI-Thread) geladen, oder?

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Der Unterschied zwischen einer Klassenbibliothek und einer Benutzersteuerelementbibliothek sind nur das ein paar Verweise im Projekt sind, mehr nicht.

H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren

Wenn nun die Verlagerung der UI in die DLL unumgänglich ist, sind dann die 3 von mir genannten Schritte so korrekt? Falls nein, wie müsste der Ablauf in etwa aussehen?

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Keine Ahnung, ich würde es niemals so machen sondern wie angedeutet.
Deshalb kann ich dir auch nicht sagen ob es so gehen würde.

H
Hurby Themenstarter:in
222 Beiträge seit 2010
vor 9 Jahren

Verstehe.

Dann bedanke ich mich trotzdem nochmal bei dir und den anderen beiden und schließe damit den Thread...

Die Welt hat genug für jedermanns Bedürfnisse, aber nicht für jedermanns Gier.

J
641 Beiträge seit 2007
vor 9 Jahren
Kein Fehler

Ich würde nicht sagen das es falsch ist sich einen neuen WPF Gui Thread zu erstellen, wird ja auch in der MSDN so beschrieben: Threading-Modell

cSharp Projekte : https://github.com/jogibear9988

16.842 Beiträge seit 2008
vor 9 Jahren

Die MSDN ist eine gute Referenz; aber nicht der heilige Gral.
Das Problem von Microsoft bei vielen Beispiele ist: sie sind ganz weit weg von der Realität.

Sieht man vor allem im Web- und Datenbankbereich.