An object-oriented programming language developed by Microsoft that can be used in .NET.
Hi @RogerSchlueter-7899 ,
Thank you for providing a clear description and confirming that Laps contains all the added items. That detail was especially helpful because it shows that the lap-saving logic is running and that the problem is with how the bound collection is updated.
I recreated a minimal WPF project using your posted code as closely as possible, adding only the components required to build and run it. I was able to reproduce the issue: the first lap appeared correctly, but additional clicks of the Lap button did not update the UI:
After changing the collection to ObservableCollection(Of Lap) and ensuring that Laps.Add(...) runs on the UI thread, all laps appeared correctly in the DataGrid.
Result after the fix:
I have also prepared two minimal project files: MainWindow.xaml.txt , MainWindow.xaml.vb.txt
The posted code has two separate issues.
1. List(Of Lap) does not notify the DataGrid
Your property is currently declared as:
Public Property Laps As List(Of Lap)
List(Of T) does not send collection-change notifications when Add() or Remove() is called.
This line:
RaiseEvent PropertyChanged(
Me,
New PropertyChangedEventArgs(NameOf(Laps)))
indicates that the Laps property itself has changed. However, the code does not assign a new list to Laps. It only modifies the contents of the existing list:
Laps.Add(...)
For this scenario, use ObservableCollection(Of Lap), which notifies WPF whenever an item is added, removed, or the collection is cleared.
2. Task.Run modifies the bound collection from a worker thread
The following code runs SaveLap() on a thread-pool thread:
Task.Run(
Sub()
SaveLap()
End Sub)
This means that both Laps.Add(...) and PropertyChanged are executed outside the WPF UI thread.
The exception you received after switching to ObservableCollection confirms that, at the time of the exception, the collection was still being changed from a thread other than its Dispatcher thread:
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
Dispatching only PropertyChanged is not sufficient. The collection modification itself, specifically Laps.Add(...), must run on the UI thread.
Because SaveLap() performs only a small amount of work and the button click already runs on the UI thread, Task.Run is unnecessary here.
The complete implementation is included in the attached project files. The essential changes are shown below.
Public ReadOnly Property Laps As New ObservableCollection(Of Lap)()
Private Sub CreateLap(
sender As Object,
e As RoutedEventArgs
) Handles btnLap.Click
SaveLap()
End Sub
Private Sub SaveLap()
Dim duration As TimeSpan =
CurrentTime - PreviousLapTime
LapCount += 1
Laps.Add(
New Lap With {
.Count = LapCount,
.Duration = duration
})
PreviousLapTime = CurrentTime
End Sub
Your existing DataGrid binding can remain essentially unchanged.
There is no need to raise PropertyChanged(NameOf(Laps)) after each Add(). ObservableCollection sends the required collection notification automatically.
The Duration calculation above preserves the behavior of your original code:
- The first lap is the elapsed time from Start to the first Lap click.
- Each subsequent lap is the time since the previous Lap click.
If pressing Start should also remove the laps from the previous session, add:
Laps.Clear()
The corrected minimal project successfully displays every lap. Although the provided code does not include enough lifecycle and binding context to determine exactly why only the first lap appeared in your original application, the two problems visible in the posted code are resolved by:
- Replacing
List(Of Lap)withObservableCollection(Of Lap). - Removing
Task.Runand modifying the collection on the UI thread.
If the exception remains after applying this version, please share only the current Laps declaration, constructor or DataContext setup, CreateLap(), and SaveLap(). That should be sufficient to identify any remaining background code path. Please remove any private or business-sensitive information before posting.
If this instruction is applicable to your situation, I would greatly appreciate it if you could follow the instruction here so others experiencing similar behavior can benefit from it as well.