There is a third-party control that binds to the collection implementing CollectionChagned . The problem is that the collection is updated too often, which is why the UI hangs when drawing.

What ways can be achieved "thinning" of processing the CollectionChagned event.

PS a collection too from indirect, I cannot independently cause OnCollectionChanged .

  • Hmm, well, we miss some of the events, but then the GUI and not all the changes will display ... Do you have a lot of elements in the collection? - Andrei NOP
  • I'm not sure that when drawing only new elements are taken into account. The collection itself is not large, you can, in principle, make the replacement of the entire collection .. - Gardes
  • You can try to write a decorator, swallowing some of the events. But if the collection is small, you can periodically do something like List2 = List1.ToList() , where List1 is your rapidly changing collection, and List2 is a new collection that is tied in the GUI - Andrey NOP
  • one
    I had the same problem, I used Reactive Extensions - Throttle - tym32167
  • one
    @ tym32167, lazy + you need to get home from work + the code from the pastebin is not needed because This solution does not work as needed. Maybe in the evening, and maybe tomorrow will publish. And maybe someone will publish a good solution before me, I would also be happy to see - Andrey NOP

1 answer 1

If the collection is small, then you can periodically make it a dump and display it in the GUI instead of the original collection.

I sketched this example: the original collection is filled with a timer every 20 ms, a dump is created every 100 ms:

 class MainVm : Vm { public ICommand StartUpdatingCommand { get; } public ICommand StopUpdatingCommand { get; } CancellationTokenSource cancellationTokenSource; public ObservableCollection<int> Collection { get; } IEnumerable<int> collectionDump; public IEnumerable<int> CollectionDump { get => collectionDump; set => Set(ref collectionDump, value, nameof(CollectionDump)); } public MainVm() { StartUpdatingCommand = new DelegateCommand(_ => StartUpdating()); StopUpdatingCommand = new DelegateCommand(_ => StopUpdating()); Collection = new ObservableCollection<int>(); CollectionDump = Collection.ToArray(); var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(20) }; timer.Tick += delegate { Collection.Add(10); Collection.Add(20); if (Collection.Count > 100) Collection.Clear(); }; timer.Start(); } private async void StartUpdating() { if (cancellationTokenSource != null) return; cancellationTokenSource = new CancellationTokenSource(); try { while (!cancellationTokenSource.IsCancellationRequested) { CollectionDump = Collection.ToArray(); await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationTokenSource.Token); } } catch (OperationCanceledException) { } finally { cancellationTokenSource = null; } } private void StopUpdating() { cancellationTokenSource?.Cancel(); } } 

Marking the contents of the window:

 <Grid Margin="5"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <ListBox ItemsSource="{Binding CollectionDump}"/> <UniformGrid Grid.Row="1" Margin="0,5,0,0" HorizontalAlignment="Center" Rows="1"> <UniformGrid.Resources> <Style TargetType="Button"> <Setter Property="Padding" Value="10,2"/> <Setter Property="Margin" Value="2.5"/> </Style> </UniformGrid.Resources> <Button Content="Start updating" Command="{Binding StartUpdatingCommand}"/> <Button Content="Stop updating" Command="{Binding StopUpdatingCommand}"/> </UniformGrid> </Grid> 

Pay attention, binding it to CollectionDump