Announcement

Collapse
No announcement yet.

Eine Variable an den BackgroundWorker weitergeben

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Eine Variable an den BackgroundWorker weitergeben

    Hallo zusammen,

    ich habe eine Methode die bekommt beim Aufruf einen DataReader per ref übergeben. Diese Methode ruft nun den BackgroundWorker.RunWorkerAsync auf. So weit klappt alles. In der DoWork vom BackgroundWorker würde ich nun irgendwie gerne auf den DataReader zugreifen, aber wie komme ich jetzt da ran?

    [highlight=c#]
    public void PrepareReader(ref DB2DataReader dtardr)
    {
    try
    {
    dtardr = _Com.ExecuteReader();
    }
    catch (Exception Ex)
    {
    // Fehlerbehandlung mal entfernt, damit es nicht so viel Code wird.
    }
    }

    public void PrepareReaderAsync(ref DB2DataReader dtardr)
    {
    this._Bgw.DoWork += new System.ComponentModel.DoWorkEventHandler(this.bgWr k_PR);
    _Bgw.RunWorkerAsync();
    }

    private void bgWrk_PR(object sender, DoWorkEventArgs e)
    {
    try
    {
    dtardr = _Com.ExecuteReader();
    }
    catch (Exception Ex)
    {
    // Fehlerbehandlung mal entfernt, damit es nicht so viel Code wird.
    }
    }
    [/highlight]

    Sinn und zweck des Ganzen ist es eine asynchrone Version von PrepareReader zu bekommen.

    Aufgerufen wird dann die Methode: PrepareReaderAsync(ref datareader1);.

    Gruß Stephan

  • #2
    Was macht das gezeigte für einen Sinn Die Aufrufsignatur deiner PrepareReaderAsync mit dem Objekt als ref Parameter erzwingt ja quasi synchrones Verhalten. Sonst dürftest du den zurückgegeben DB2DataReader ja nicht gleich verwenden oder du müsstest in der Methode warten bis der Backgroundworker fertig ist. Dann kann man aber auch gleich auf Multithreading verzichten.

    Wenn du das asynchron kapseln willst sieh dir mal die entsprechend Muster in der MSDN an für Anregungen wie das zu implementieren wäre.

    Comment


    • #3
      Hallo Ralf,

      ich habe einen Query der zwischen 5 und 10 Minuten läuft, je nach gesetzten Bedingungen. Bevor das Ergebnis aber tatsächlich benötigt wird verbringt der User im Normalfall fast die gleiche Zeit in der nächsten Maske. Bisher muss er nach der Maske die Zeit warten bis das Ergebnis dann verfügbar ist und ich wurde eben gefragt ob man das nicht irgendwie im Hintergrund machen kann damit der Query schon mal läuft während der User noch in der nächsten Maske beschäftigt ist.

      Und wenn der User die Maske verlässt hätte ich über eine Schleife mit IsBusy Abfrage auf dem BackgroundWorker einfach die restliche Zeit gewartet bis der SQL dann wirklich durch ist und das Ergebnis verfügbar.

      Gruß Stephan

      Comment


      • #4
        Wenn Du aber eine Schleife hast die mit IsBusy wartet, dann prüft er solange ob er noch arbeitet bis der Thread beendet ist. Das blockiert die UI genauso und ist im Endeffekt langsamer als vorher.

        Asynchron heisst eigentlich immer, dass man eine Begin Methode hat. Diese startet einen Thread, am Ende bekommt man entweder ein Event was einem das Ergebnis zurückliefert (klassiches Modell). Oder man schreibt eine Continuation (Task Parallel Library).

        Comment


        • #5
          Aber das UI ist doch genauso blockiert wenn ich es ganz normal mit ExecuteReader() laufen lasse und auf das Ergebnis warten muss. Ich will ja nur erreichen das der User während das Ergebnis aufgebaut wird schon mal in der nächsten Maske weiterarbeiten kann.

          In VB6 konnte ich so einfach das Recordset aufbauen lassen während das Programm weitergelaufen ist, mehr will ich ja gar nicht

          Code:
          Set rsErg = cnConn.Execute(SQLcmd, affRow, adAsyncExecute)
          Dann habe ich dem User die nächste Maske angezeigt und darin arbeiten lassen und wenn er die verlassen hat über

          Code:
          Do While cnConn.State >= adStateExecuting
                      Call Warten(500, True)
          Loop
          gewartet bis alle Teile da sind.

          Gruß Stephan
          Zuletzt editiert von Womble; 05.11.2010, 11:27.

          Comment


          • #6
            Schau Dir mal das an:

            http://msdn.microsoft.com/de-de/library/dd537609.aspx

            Und da insbesondere den Teil mit den Aufgabenfortsetzungen. Zuerst startest Du praktisch das laden aus der Datenbank. Als Ergebnis gibst Du Dein DataSet zurück. In der Fortsetzung übergibst Du das DataSet mit this.Invoke() an die UI

            So in etwa:

            [highlight=c#]
            public void LadeDatenInUi()
            {
            // starte laden aus Db
            Task.Factory.StartNew(() => LadeDatenAusDb())
            // wenn fertig zeige in UI an
            .ContinueWith(x => ZeigeDatenInUi(x.Result));

            }

            private void ZeigeDatenInUi(DataSet dataSet)
            {
            // mit Invoke aufrufen, dass die Ausführung im Kontext des UI Thread ausgeführt wird
            Invoke(new Action(() => meineBindingSource.DataSource = dataSet));
            }

            public DataSet LadeDatenAusDb()
            {
            DataSet result = null;

            // Lade Daten aus Db

            return result;
            }
            [/highlight]
            Zuletzt editiert von fanderlf; 05.11.2010, 11:59.

            Comment


            • #7
              Hi,

              kann es sein das diese Task Geschichte erst mir Framework 4 funktioniert?
              Ich bin noch mit Framework 3 unterwegs - ja ich weiß, hätte ich vielleicht gleich schreiben sollen - und bekomme immer wenn ich, wie im Mircosoft Beispiel angegeben

              using System.Threading.Task;

              ins Programm reinschreibe die folgende Meldung "Der Typ- oder Namespacename "Task" ist im Namespace "System.Threading" nicht vorhanden. (Fehlt ein Assemblyverweis?)" aber unter Verweis hinzufügen finde ich keinen der "System.Threading" heißt.

              Gruß Stephan

              Comment


              • #8
                Aso ja... das ist neu in .NET 4.0. Sorry -.- aber ähnlich kann man das bestimmt auch mit .NET 3.5 Mitteln aufbauen. Ich versuch das gerade mal

                Edit:

                So ich hoffe das funktioniert. Wenn Du den Action Typ noch nicht hast musst Du Dir selbst ein delegate anlegen:

                [highlight=c#]
                private void ZeigeDatenInUi(DataSet dataSet)
                {
                // mit Invoke aufrufen, dass die Ausführung im Kontext des UI Thread ausgeführt wird
                Invoke(new Action(() => meineBindingSource.DataSource = dataSet));
                }

                public void LadeDatenAusDb(object o)
                {
                DataSet result = null;

                // Lade Daten aus Db

                // wenn fertig mit laden füge sie in die UI ein

                ZeigeDatenInUi(result);
                }

                public void LadeDatenInUi35()
                {
                ThreadPool.QueueUserWorkItem(LadeDatenAusDb);
                }
                [/highlight]
                Zuletzt editiert von fanderlf; 05.11.2010, 17:13.

                Comment


                • #9
                  Vielen Dank, das werde ich auf jeden Fall mal ausprobieren, kann nur etwas dauern, weil mein Chef mir schon wieder etwas anderes auf den Tisch gelegt hat.

                  Gruß Stephan

                  Comment

                  Working...
                  X