Hallo Leute,
ich arbeite mich gerade in das Thema asynchrone Programmierung an (dank dem sehr guten Vorlage Programm von @Nofear23m "WpfNotes2" eigentlich nicht so schwierig).
Leider scheitere ich gerade an folgendem Szenario:
Ich habe eine View erzeugt in der alle Einträge einer "Tabelle" in Form eine ICollectionView angezeigt werden. Um einen Eintrag zu editieren wird ein "Edit" Relaycommand ausgeführt, das dann die weiteren Daten für das Objekt selbst lädt.
Das Objekt selbst (Klasse "User") hat eine n:m Relation zu Usergroups die Join Entity heißt UserUsergroups.
Code für das Edit Command: (Das Optionale EditItem ist nur eine Möglichkeit der Edit auch ein Item vorzugeben)
Die Funktion LoadData im UserVM lädt mir dann die restlichen Daten:
Code für LoadData
Die asynchrone Funktion LoadCompleteData:
Die Deklaration der Observable Collection und der ICollectionView:
Der Code funktioniert auch im ganzen, die Daten werden geladen und korrekt angezeigt.
Ich musste relativ lange rumbasteln da ich trotz Dispatcher immer wieder Probleme mit dem GUI Thread bekommen habe.
Die Lösung war für mich das ich im Constructor die ObservableCollection "vordeklariere"...
Die ICollectionView ist dann an eine Datagrid gebunden (Screenshot zeigt die Situation in der GUI):
Will ich jetzt aus dieser ObservableCollection einen Eintrag lösche, fange ich mir mit Interaction die "Del" Taste und übergebe Sie mit EventToCmd an ein Relaycommand meines Viewmodels: (es folgt der Execute Code):
und hier beginnt mein Problem, ich erhalte eine:
System.NullReferenceException: 'Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.' => die __UserUsergroups ObservableCollection ist "NOTHING" obwohl sie nicht nothing ist und Elemente hält.
Ich habe versucht auch den Dispatcher wegzulassen, bringt auch nichts.
Meine Vermutung ist das die __UserUsergroups in einem anderen Thread "wohnt" und ich Sie daher nicht sehe???
Habe natürlich auch versucht die UserUsergroups ICollectionView einfach nur zu refreshen aber das interessiert die UI auch nicht wirklich.
Daher die Frage, ist mein asynchrones laden falsch? Mein Asynchrones Löschen??
Hoffe es kann mir hierbei jemand helfen. Danke
ich arbeite mich gerade in das Thema asynchrone Programmierung an (dank dem sehr guten Vorlage Programm von @Nofear23m "WpfNotes2" eigentlich nicht so schwierig).
Leider scheitere ich gerade an folgendem Szenario:
Ich habe eine View erzeugt in der alle Einträge einer "Tabelle" in Form eine ICollectionView angezeigt werden. Um einen Eintrag zu editieren wird ein "Edit" Relaycommand ausgeführt, das dann die weiteren Daten für das Objekt selbst lädt.
Das Objekt selbst (Klasse "User") hat eine n:m Relation zu Usergroups die Join Entity heißt UserUsergroups.
Code für das Edit Command: (Das Optionale EditItem ist nur eine Möglichkeit der Edit auch ein Item vorzugeben)
VB.NET-Quellcode
- Private Sub EditExecute(Optional EditItem As UserVM = Nothing)
- Dim DiaServ = ServiceContainer.GetService(Of IDialogWindowService)
- Dim vItemToEdit As UserVM
- If EditItem Is Nothing Then
- If Users.CurrentItem Is Nothing Then Exit Sub
- vItemToEdit = CType(Users.CurrentItem, UserVM)
- Else
- vItemToEdit = EditItem
- End If
- 'Load the entire data from Database and after finished show the edit dialog:
- If vItemToEdit.LoadData() Then DiaServ.ShowNonModalDialog("edit", New SingleEntityContainerVM(vItemToEdit), Me, False, True)
- vItemToEdit.Dispose()
- End Sub
Die Funktion LoadData im UserVM lädt mir dann die restlichen Daten:
Code für LoadData
VB.NET-Quellcode
- Friend Function LoadData() As Boolean
- VMisBusy = True
- Dim result = Task.Run(Function() LoadCompleteData()).GetAwaiter.GetResult
- UserUsergroups = CollectionViewSource.GetDefaultView(__UserUsergroups)
- With UserUsergroups
- .MoveCurrentToFirst()
- .SortDescriptions.Add(New SortDescription("UsergroupId", ListSortDirection.Ascending))
- End With
- VMisBusy = False
- Return result
- End Function
Die asynchrone Funktion LoadCompleteData:
VB.NET-Quellcode
- Private Async Function LoadCompleteData() As Task(Of Boolean)
- Try
- If Id = Guid.Empty Then Return False
- Dim vResult = Await _BL.GetAllUserDataAsync(_Model, True).ConfigureAwait(True)
- If vResult.ErrorStr IsNot Nothing Then Throw New Exception(vResult.ErrorStr)
- _Model = vResult._Model
- RaisePropertyChanged()
- __UserUsergroups?.ToList.ForEach(Sub(x) x.Dispose())
- ServiceContainer.GetService(Of IDispatcherService).Invoke(Sub()
- If __UserUsergroups Is Nothing Then __UserUsergroups = New ObservableCollection(Of UserUsergroupVM)
- _Model.UserUsergroups?.ToList.ForEach(Sub(x) __UserUsergroups.Add(New UserUsergroupVM(x)))
- End Sub)
- AllAvailableUsergroups.Clear()
- Using BL As New UsergroupBL
- Dim query = Await BL.GetAllAsync(False).ConfigureAwait(True)
- query.ToList.ForEach(Sub(x) AllAvailableUsergroups.Add(New Tuple(Of Guid, String)(x.Id, x.Groupname)))
- End Using
- AllAvailableTenants.Clear()
- Using BL As New TenantBL
- Dim query = Await BL.GetAllAsync(False).ConfigureAwait(True)
- query.ToList.ForEach(Sub(x) AllAvailableTenants.Add(New Tuple(Of Guid, String)(x.Id, x.CompanyName1)))
- End Using
- 'Add an empty Tenant:
- AllAvailableTenants.Insert(0, New Tuple(Of Guid, String)(Guid.Empty, "---"))
- 'Languages:
- AllAvailableLanguages.Clear()
- AllAvailableLanguages = TranslationManager.Instance.GetAvailableLanguages
- Return True
- Catch ex As Exception
- ServiceContainer.GetService(Of IErrorDialogService).ShowDialog(ex)
- Return False
- End Try
- End Function
Die Deklaration der Observable Collection und der ICollectionView:
VB.NET-Quellcode
Der Code funktioniert auch im ganzen, die Daten werden geladen und korrekt angezeigt.
Ich musste relativ lange rumbasteln da ich trotz Dispatcher immer wieder Probleme mit dem GUI Thread bekommen habe.
Die Lösung war für mich das ich im Constructor die ObservableCollection "vordeklariere"...
Die ICollectionView ist dann an eine Datagrid gebunden (Screenshot zeigt die Situation in der GUI):
Will ich jetzt aus dieser ObservableCollection einen Eintrag lösche, fange ich mir mit Interaction die "Del" Taste und übergebe Sie mit EventToCmd an ein Relaycommand meines Viewmodels: (es folgt der Execute Code):
VB.NET-Quellcode
- Private Async Sub DeleteUsergroupExecute()
- Dim vIsDeleted As Boolean = Await _BLUserUsergroup.DeleteAsync(CType(UserUsergroups?.CurrentItem, UserUsergroupVM).Id).ConfigureAwait(True)
- If vIsDeleted Then
- ServiceContainer.GetService(Of IDispatcherService).Invoke(Sub() __UserUsergroups.Remove(CType(UserUsergroups?.CurrentItem, UserUsergroupVM)))
- UserUsergroups.MoveCurrentToFirst()
- UserUsergroups.Refresh()
- End If
- End Sub
und hier beginnt mein Problem, ich erhalte eine:
System.NullReferenceException: 'Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.' => die __UserUsergroups ObservableCollection ist "NOTHING" obwohl sie nicht nothing ist und Elemente hält.
Ich habe versucht auch den Dispatcher wegzulassen, bringt auch nichts.
Meine Vermutung ist das die __UserUsergroups in einem anderen Thread "wohnt" und ich Sie daher nicht sehe???
Habe natürlich auch versucht die UserUsergroups ICollectionView einfach nur zu refreshen aber das interessiert die UI auch nicht wirklich.
Daher die Frage, ist mein asynchrones laden falsch? Mein Asynchrones Löschen??
Hoffe es kann mir hierbei jemand helfen. Danke
mfG.
Stephan
Stephan