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
Backgroundworker und Mehrsprachigkeit
thomas.at
myCSharp.de - Member



Dabei seit:
Beiträge: 109
Herkunft: Österreich / Wien

Themenstarter:

Backgroundworker und Mehrsprachigkeit

beantworten | zitieren | melden

Hallo Leute

Ich habe eine Server/Client-Anwendung mit einem Pluginsystem auf der Clientseite. Diese werden über eine seperate Domain im Clienthauptprogramm geladen. In einem Modul ist eine längerdauernde Funktion, die Daten aus eine Datenbank in Excel umkopiert. Um die GUI nicht zu blockieren, wurde diese Funktion in einen Backgroundworker ausgelagert. Im Plugin wird ein Fortschrittssfenster geöffnet und der Backgroundworker gestartet. Dieser aktualisiert dann einen Fortschrittsbalken auf dem Formular. Dies funktioniert alles bestens. Nun ist mein Programm aber mehrsprachig aufgebaut (über die mechanismen von .NET, also Resourcen ...). Hier mal die Code-Relevanten Teile:

Plugin:



    private void RunBackground()
    {
      frmFortschritt = new Fortschritt(this.Bounds);
      frmFortschritt.Max = (akt + ms + 1) * frmWahl.Gewaehlt.Count;
      frmFortschritt.Closed += new EventHandler(frmFortschritt_Closed);
      frmFortschritt.Cancel = Export;
      frmFortschritt.Show();

      bgwExcel.DoWork += new DoWorkEventHandler(bgwExcel_DoWork);
      bgwExcel.ProgressChanged += new ProgressChangedEventHandler(bgwExcel_ProgressExport);
      bgwExcel.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwExcel_ExportCompleted);
      bgwExcel.WorkerReportsProgress = true;
      bgwExcel.WorkerSupportsCancellation = true;
      bgwExcel.RunWorkerAsync(Export);
    }
 
    private void bgwExcel_ProgressExport(object sender, ProgressChangedEventArgs e)
    {
      Show_Fortschritt();
    }

    private void bgwExcel_ExportCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      if ((bool)e.Result)
      {
        frmFortschritt.Set_Text(Properties.Resources.DatenWurdenExportiert);
        //Show_Text(Properties.Resources.DatenWurdenExportiert);
      }
    }
		
    delegate void SetTextCallback(string text);

    private void Show_Text(string Text)
    {
      if (frmFortschritt != null)
      {
        if (frmFortschritt.InvokeRequired)
        {
          SetTextCallback d = new SetTextCallback(Show_Text);
          frmFortschritt.Invoke(d, new object[] { Text });
        }
        else
          frmFortschritt.Set_Text(Text);
      }
    }

    private void Show_Fortschritt()
    {
      if (frmFortschritt != null)
      {
        // if (frmFortschritt.InvokeRequired)
        // {
        //   frmFortschritt.Invoke(new MethodInvoker(Show_Fortschritt));
        //   return;
        // }
        frmFortschritt.Aktuell = frmFortschritt.Aktuell + 1;
        frmFortschritt.Set_Text();
      }
    }

Fortschrittssdialog:


    public int Aktuell 
    { 
      get { return (pgbFortschritt.Value); } 
      set { pgbFortschritt.Value = value; }       // <-- Hier Fehler
    }

    public void Set_Text(string Text)
    {
      label1.Text = Text;                                 //<-- Hier Fehler
      btnCancel.Text = "OK";
    }


Wenn ich das Programm jetzt starte, dann bekomme ich beim Aktualisieren des Fortschrittbalkens (im ProgressChanged) und beim Completed die Fehlermeldung : "Ungültiger threadübergreifender Vorgang". Wenn ich dann den auskommentierten Teil einbaue, dann funktioniert das Programm wieder, allerdings sind dann die Texte in Deutsch (also Defaultsprache). Kann mir jemand helfen, wie ich das Problem löse, so dass die Texte in der gewünschten Sprache ohne CrossThreadError angezeigt werden?

vielen Dank im Vorraus

Thomas
private Nachricht | Beiträge des Benutzers
norman_timo
myCSharp.de - Member

Avatar #avatar-1775.jpeg


Dabei seit:
Beiträge: 4.506
Herkunft: Wald-Michelbach (Odw)

beantworten | zitieren | melden

Hallo thomas.at,

ich glaube Du hast das Baum-Wald Phänomen:

private void Show_Fortschritt()
    {
      if (frmFortschritt != null)
      {
        // if (frmFortschritt.InvokeRequired)
        // {
        //   frmFortschritt.Invoke(new MethodInvoker(Show_Fortschritt));
        //   return;
        // }
        else
        {
          frmFortschritt.Aktuell = frmFortschritt.Aktuell + 1;
          frmFortschritt.Set_Text();
        }
      }
    }

Einfach Else dazupacken, falls ich nicht noch etwas übersehen haben sollte.

Grüße
Norman-Timo
A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”
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 thomas.at,

und im Allgemeinen: [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke)

herbivore
private Nachricht | Beiträge des Benutzers
norman_timo
myCSharp.de - Member

Avatar #avatar-1775.jpeg


Dabei seit:
Beiträge: 4.506
Herkunft: Wald-Michelbach (Odw)

beantworten | zitieren | melden

Hallo nochmal,

das war Blödsinn von mir, Du hast ja ein Return drin, was das Else auch nicht viel besser macht ;-)

Eventuell liegt das Problem bei

frmFortschritt.Set_Text();

Ich finde nur komisch, dass Du nicht die Eigenschaften und Methoden innerhalb Deiner Form Threadsicher gestaltest, so dass der Workerthread nicht darauf achten muss, ob ein "Invoke required" ist.

Also ich würde an Deiner Stelle alle Eigenschaften und Methoden, die von Threads aufgerufen werden können (im Detail z.B. "frmFortschritt.Aktuell", "frmFortschritt.Set_Text();" ...) so erweitern, dass sie dann selbst nachfragen, ob ein "Invoke required" ist.

Dann wäre die Threadsicherheit gekapselt und betrifft ALLE Threads, die sich Deiner Form begnügen.

Grüße
Norman-Timo
A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”
private Nachricht | Beiträge des Benutzers
thomas.at
myCSharp.de - Member



Dabei seit:
Beiträge: 109
Herkunft: Österreich / Wien

Themenstarter:

beantworten | zitieren | melden

Hallo

das Problem wurde von mir vielleicht nicht ganz klar dargestellt. Bis zur Umstellung auf Mehrsprachigkeit (Localizable = false) hat ja alles mittels Backgroundworker funktioniert (der kümmert sich ja um das Invoke selbst). Nachdem ich aber Localizable auf true gesetzt habe musste ich das Invoke selbst noch abfragen (daher auch dies im Workerthread). Wenn ich das mache funktioniert ja alles wieder (keine Fehlermeldung) nur die Texte sind dann eben nicht in der gewünschten Sprache sondern in der Default. Für mich sieht es so aus, alsob der Workerthread eben in einem Defaultthread läuft und die Sprache noch in einem zusätzlichen Thread gestartet wird, aus dem dann der Backgroundworker arbeitet.

Thomas
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 thomas.at,

Thread.CurrentCulture
Thread.CurrentUICulture

herbivore
private Nachricht | Beiträge des Benutzers
thomas.at
myCSharp.de - Member



Dabei seit:
Beiträge: 109
Herkunft: Österreich / Wien

Themenstarter:

beantworten | zitieren | melden

Hallo herbivore

Danke für den Tip. Ich musste nur im Backgroundworker in der Dowork-Methode über Thread.CurrentUICulture die aktuelle Sprache setzen und schon geht alles wieder (auch ohne InvokeRequired)

Wieder einmal hat das Forum super geholfen!
private Nachricht | Beiträge des Benutzers
snoop83
myCSharp.de - Member



Dabei seit:
Beiträge: 46

beantworten | zitieren | melden

@ thomas.at:

Wie reichst du die Sprachänderung von der GUI an deinen Backgroundworker weiter?

Ich habe gerade ein ähnliches Problem mit mehreren Threads (und div. Timer, die Aktionen auslösen). Wenn ich in der GUI die Sprache ändere, so betrifft das nur den einen Thread. Mir fehlt eine Möglichkeit, für alle laufenden Threads die Sprache zu ändern.
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10.006

beantworten | zitieren | melden

Es geht aber nicht anders.

Du musst in jedem Thread die Culture setzen.
private Nachricht | Beiträge des Benutzers
snoop83
myCSharp.de - Member



Dabei seit:
Beiträge: 46

beantworten | zitieren | melden

Ja, das ist mir mittlerweile klar, aber wie realisiere ich es, dass ich alle Threads benachrichtige? Ich habe es bisher nur geschafft, mit Thread.CurrentThread... die Culture zu setzen, weiß aber nicht, wie ich die anderen Threads "benachrichtige".
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10.006

beantworten | zitieren | melden

Garnicht.

Du musst dies beim Erstellen eines Thread machen.
Wenn du z.b. den SmartThreadPool von Codeproject nimmst, hättest du das schon eingebaut.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von FZelle am .
private Nachricht | Beiträge des Benutzers
kleines_eichhoernchen
myCSharp.de - Member

Avatar #avatar-2079.jpg


Dabei seit:
Beiträge: 3.971
Herkunft: Ursprünglich Vogtland, jetzt Much

beantworten | zitieren | melden

Zitat
Ja, das ist mir mittlerweile klar, aber wie realisiere ich es, dass ich alle Threads benachrichtige?
Threads benachrichtigen geht nicht, dass ist der falsche Weg. Deine Threads können maximal prüfen, ob sich der Status geändert hat und darauf entsprechende Anweisungen ausführen.

Es ist aber unsinnig, während der Ausführung einer bestimmten Aufgabe, diverse relevante Daten zu ändern. Das ändern der Kultur für alle Threads könnte ungeahnte Konsequenzen hervorrufen. Es ist sinniger, dass nur neugestartete Threads bzw. welche aus dem Threadpool (direkt als erste Anweisung) die entsprechende neue Kultur sich holen. Laufende Threads müssten weiterlaufen so wie sie sind oder abgebrochen und neugestartet werden.

Eine andere Überlegung wäre, dass die Threads kultur-neutral arbeiten und erst innerhab des Gui-Threads (Control.Invoke) die entsprechende Ressource mit der aktuellen Kultur geladen wird.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
private Nachricht | Beiträge des Benutzers
snoop83
myCSharp.de - Member



Dabei seit:
Beiträge: 46

beantworten | zitieren | melden

Da hast du natürlich auch wieder Recht!

Mein Fehler ist vermutlich, dass ich meine Ressourcen zu früh hole, und zwar in den Hintergrundthreads. Vermutlich sollte ich darauf achten, sämtliche Ressourcen erst im Hauptthread (nach Invoke) abzurufen und von dort zu setzen.

Ich werde mal prüfen, ob das den gewünschten Effekt hervorruft.

Thx so far :)
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10.006

beantworten | zitieren | melden

Warum?

Viel einfacher ist doch, beim threadstart die Culture richtig zu setzen.
private Nachricht | Beiträge des Benutzers
snoop83
myCSharp.de - Member



Dabei seit:
Beiträge: 46

beantworten | zitieren | melden

Da es sich teilweise um Events von Timern oder Hardware-Ereignisse handelt, ist dies nicht möglich. Die Sprache meiner Oberfläche kann sich zudem jederzeit ändern.
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10.006

beantworten | zitieren | melden

Ja und?

Wo ist da jetzt das Problem?
private Nachricht | Beiträge des Benutzers