none
Backgroundworker benötigt RRS feed

  • Frage

  • Hallo,

    Ich habe folgendes Problem, vorweg ich nutze Visual Basic WPF 2010 mit Framework 4.

    Ich möchte in meinem Projekt durch eine Methode (Public Sub Refresh()) eine Datenbank füllen. Das füllen der Datenbank beansprucht einige Zeit und deshalb benötige ich am besten einen Backgroundworker. Den Backgroundworker erstelle ich mit folgendem Code:

     

    WithEvents worker As New ComponentModel.BackgroundWorker
     Private Sub worker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
     ' Hier wird die Methode (Sub Refresh()) ausgeführt
     End Sub
    
     Private Sub worker_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
     ' Hier lass ich zum Test eine MsgBox ausgeben
     End Sub
    

     

    Den Backgroundworker starte ich mit dem Befehl "worker.RunWorkerAsync()".
    Aber jetzt zu meinem eigentlichen Problem. In der Methode (Public Sub Refresh()) muss ich auf Form Komponenten (z.B. label) zugreifen. An der Stelle bekomme ich den Fehler:

    Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da sich das Objekt im Besitz eines anderen Threads befindet.

    In WinForms konnte ich das Umgehen in dem ich in den DoWork Prozess "CheckForIllegalCrossThreadCalls = False" am Anfang eingefügt habe.

     



    Ich danke im Vorraus für jedliche Hilfe,


    MfG ASkuN


    Mittwoch, 30. März 2011 08:28

Alle Antworten

  • Am besten kapselst du den zugriff auf das Label mit einer Eigenschaft.
    Den Zugriff musst du dann über einen Dispatcher machen.

    Schau dir mal folgenden Link an:

    http://msdn.microsoft.com/de-de/magazine/cc163328.aspx

     

    Mittwoch, 30. März 2011 09:52
    Beantworter
  • Hallo ClassMP2002,

    erstmal danke für deine Antwort. Im Grundprinzip habe ich es verstanden.

    Ich habe es jetzt angewand aber leider hängt das Formular immernoch während die Sub ausgeführt wird (also das füllen der Datenbank).


    MfG ASkuN
    Mittwoch, 30. März 2011 10:20
  • Kannst du mal mehr Code posten?

     

    Mittwoch, 30. März 2011 10:51
    Beantworter
  • Ja,

    Hier ist die zu ausführende Methode:

    Sub dgchange()
        frmMainTotal.Activate()
        Dim i As Integer = -1
        cCust.getCustomers()
        frmMainTotal.dg_Kunden.ItemsSource = cCust.dsCustomers.Tables("BIN_Main").DefaultView 'dt.DefaultView
        If Not cPers.GUID = "" Then
          For i = cCust.dsCustomers.Tables("BIN_Main").Rows.Count - 1 To 0 Step -1
            If cCust.dsCustomers.Tables("BIN_Main").Rows(i).Item("StammGUID") = cPers.GUID Then
              Exit For
            End If
          Next
          If i >= 0 Then
            frmMainTotal.dg_Kunden.SelectedIndex = i
            frmMainTotal.dg_Kunden.SelectedItem = frmMainTotal.dg_Kunden.SelectedIndex
            frmMainTotal.dg_Kunden.ScrollIntoView(frmMainTotal.dg_Kunden.SelectedItem)
            sGUID_preselected = frmMainTotal.dg_Kunden.SelectedItem.Row.ItemArray(4).ToString()
          End If
        Else
          If frmMainTotal.dg_Kunden.Items.Count > 0 Then
            If frmMainTotal.dg_Kunden.SelectedIndex > 0 Then
              sGUID_preselected = frmMainTotal.dg_Kunden.SelectedItem.Row.ItemArray(4).ToString()
            Else
              sGUID_preselected = ""
            End If
          Else
            sGUID_preselected = ""
          End If
        End If
        frmMainTotal.dg_Kunden.UpdateLayout()
      End Sub
    

    was hier so lange dauert ist "cCust.getCustomers()"

    Und im Backgroundworker selber bestimme ich einen Dispatcher:

    Private Sub worker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
        Dispatcher.Invoke(New ThreadStart(AddressOf dgchange))
      End Sub
    

    Ich frag mich was ich falsch mache? Oder vielleicht habe ich das Prinzip doch nicht richtig verstanden...

     

    danke für jede Hilfe,


    MfG ASkuN
    Mittwoch, 30. März 2011 10:56
  • Do solltest in einem Background Thread, also in dgChange, am besten gar nicht auf UI-Elemente zugreifen.
    Das führt zu diesen Crossthread-Execptions.
    Der UI-Zugriff erfolgt am besten, wenn der BackgroundWorker fertig ist, im RunWorkerCompleted-Event
    dann ist man wieder auf dem UI-Thread

    Ergo solltest Du es etwa so ummodeln:

    Private Sub worker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
      cCust.getCustomers()
    End Sub
    
    Private Sub worker_RunWorkerCompleted( _
    ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
    
      frmMainTotal.Activate()
      Dim i As Integer = -1
      
      frmMainTotal.dg_Kunden.ItemsSource = cCust.dsCustomers.Tables("BIN_Main").DefaultView 'dt.DefaultView
      If Not cPers.GUID = "" Then
       For i = cCust.dsCustomers.Tables("BIN_Main").Rows.Count - 1 To 0 Step -1
        If cCust.dsCustomers.Tables("BIN_Main").Rows(i).Item("StammGUID") = cPers.GUID Then
         Exit For
        End If
       Next
       If i >= 0 Then
        frmMainTotal.dg_Kunden.SelectedIndex = i
        frmMainTotal.dg_Kunden.SelectedItem = frmMainTotal.dg_Kunden.SelectedIndex
        frmMainTotal.dg_Kunden.ScrollIntoView(frmMainTotal.dg_Kunden.SelectedItem)
        sGUID_preselected = frmMainTotal.dg_Kunden.SelectedItem.Row.ItemArray(4).ToString()
       End If
      Else
       If frmMainTotal.dg_Kunden.Items.Count > 0 Then
        If frmMainTotal.dg_Kunden.SelectedIndex > 0 Then
         sGUID_preselected = frmMainTotal.dg_Kunden.SelectedItem.Row.ItemArray(4).ToString()
        Else
         sGUID_preselected = ""
        End If
       Else
        sGUID_preselected = ""
       End If
      End If
      frmMainTotal.dg_Kunden.UpdateLayout()
    End Sub
    


    VB.NET-Fehler bitte ich zu entschuldigen, so welche vorhanden.

    Christoph



    Donnerstag, 31. März 2011 13:32
  • Ich habe es jetzt genau so gemacht, nur leider bekomme ich an einer Stelle ein "NullReferenzExceptionError":

    frmMainTotal.dg_Kunden.ScrollIntoView(frmMainTotal.dg_Kunden.SelectedItem)

     

    Ich habe mal Abgefragt ob überhaupt was in "dg_Kunden.SelecteedItem" vorhanden ist. Vorhanden ist was nur trotzdem bekomme ich leider diesen Fehler.


    MfG ASkuN
    Freitag, 1. April 2011 06:09
  •   frmMainTotal.dg_Kunden.SelectedItem = frmMainTotal.dg_Kunden.SelectedIndex
      frmMainTotal.dg_Kunden.ScrollIntoView(frmMainTotal.dg_Kunden.SelectedItem)
    
    

    Warum setzt du das SelectedItem auf den Wert in SelectedIndex?

    Freitag, 1. April 2011 06:43
    Beantworter
  • Oh, da ist mir ein Fehler Unterlaufen (noch von VB6 Zeiten gewöhnt)

    Ich habe jetzt meinen Code angepasst:

      Private Sub worker_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
        frmMainTotal.Activate()
        Dim i As Integer = -1
    
        frmMainTotal.dg_Kunden.ItemsSource = cCust.dsCustomers.Tables("BIN_Main").DefaultView 'dt.DefaultView
        If Not cPers.GUID = "" Then
          For i = cCust.dsCustomers.Tables("BIN_Main").Rows.Count - 1 To 0 Step -1
            If cCust.dsCustomers.Tables("BIN_Main").Rows(i).Item("StammGUID") = cPers.GUID Then
              Exit For
            End If
          Next
          If i >= 0 Then
            frmMainTotal.dg_Kunden.SelectedIndex = i
            If Not IsNothing(frmMainTotal.dg_Kunden.SelectedItem) Then
              frmMainTotal.dg_Kunden.ScrollIntoView(frmMainTotal.dg_Kunden.SelectedIndex)
              sGUID_preselected = frmMainTotal.dg_Kunden.SelectedItem.Row.ItemArray(4).ToString()
            End If
          End If
        Else
          If frmMainTotal.dg_Kunden.Items.Count > 0 Then
            If frmMainTotal.dg_Kunden.SelectedIndex > 0 Then
              sGUID_preselected = frmMainTotal.dg_Kunden.SelectedItem.Row.ItemArray(4).ToString()
            Else
              sGUID_preselected = ""
            End If
          Else
            sGUID_preselected = ""
          End If
        End If
        frmMainTotal.dg_Kunden.UpdateLayout()
      End Sub
    

    Ich habe noch eine kleine Abfrage eingebaut...ABER...Die Form hängt zwar jetzt nicht mehr, dafür aber das Datagrid dg_Kunden...sobald ich es anklicke bekomme ich einen Fehler das kein Quellcode vorhanden ist.


    MfG ASkuN
    Freitag, 1. April 2011 09:18
  • Kein Quellcode vorhanden ist merkwürdig...
    Bereinige die Projektmappe und erstellste alle Dlls nochmal.
    Evtl. sind Verweise auf Dlls nicht richtig.

     

    Freitag, 1. April 2011 09:35
    Beantworter
  • Ich habe gerade herrausgefunden das das Doppelklick Event vom Datagrid noch aktiv ist und auch funktioniert...nur man dann das Item nicht ändern und es schein so als hätte es sich aufgehangen...

    Edit: Die Projektmappe und die DLL's habe ich alle neu erstellt und auch nochmal die Verweise neu eingebunden (ohne Erfolg)


    MfG ASkuN
    Freitag, 1. April 2011 09:49
  • Paar Anmerkungen:

    frmMainTotal.dg_Kunden.ScrollIntoView(frmMainTotal.dg_Kunden.SelectedIndex)

    Du meintest wohl:

    frmMainTotal.dg_Kunden.ScrollIntoView(frmMainTotal.dg_Kunden.SelectedItem)

    Hier wird ein gebundes Data-Item als Scroll-Ziel erwartet, nicht der index.


    Ansonsten würde ich vermuten dass der Zweig:

     Else
    If frmMainTotal.dg_Kunden.Items.Count > 0 Then
    If frmMainTotal.dg_Kunden.SelectedIndex > 0 Then
    sGUID_preselected = frmMainTotal.dg_Kunden.SelectedItem.Row.ItemArray(4).ToString()

    nie ausgeführt wird, da Du zuvor die ItemsSource setzt  - wobei der SelectedIndex automatisch auf -1 zurückgesetzt wird -
    SelectedIndex wird danach aber nur im anderen If-zweig neu gesetzt.
    Aber anyways.

    frmMainTotal.dg_Kunden.UpdateLayout()
    würde ich am Schluss weglassen, damit soll man sparsamst umgehen.
    Das DataGrid wird sich von selbst aktualisieren, wenn sich die Datenbindung bzw die Selektion
    und die Scrollposition ändert.


    Freitag, 1. April 2011 13:32
  • Wahrscheinlich eine Ausnahme zu der kein Quellcode vorhanden ist;
    bzw keine Stacktrace weil es sich im native Bereich abspielt.
    Freitag, 1. April 2011 13:55
  • Heisst das soviel wie, dass Du einen EventHandler für DataGrid_Click (oder DoubleClick o. ähnlich) hast,
    und bisweilen während RunWorkerCompleted abgearbeitet wird, der DoubleClick-Handler parallel aktiv ist
    und Du dann ein Prob kriegst, wenn Du SelectedIndex/Item setzen willst?

    Freitag, 1. April 2011 13:58
  • Vielen Dank, Christoph Basedau

    Ich probiere mal weiter und schaue was dabei herrauskommt.

    -> Falls noch jemand eine geschicktere Lösung hat wie man dieses Problem beheben könnte

         nur her damit ich freue mich über alles was mich im Ansatz vorran bringt.


    MfG ASkuN
    Montag, 4. April 2011 09:25