Search code examples
c#wpflistviewbindingrefresh

ListView doesnt refresh while deleting in a loop


I have a ListView which is to bind to an ObservableCollection. When i delete items manually (per button event), the items are getting removed and the ListView gets refreshed immediately.

When i delete the items in a for loop, only the list is getting refreshed at the end of the operation, after all elements are deleted. Before the items are getting deleted, there are some time-consuming operations on them and also notification to the user in another ListView.

So how can it be achieved, that the list gets refreshed after every single deletion of an item.

The question is not, how to delete items in a loop from an list, because this works (in reverse order). The question is, why is the UI not refreshing while deleting the items.

Here i have simplified sample code, which is showing this behaviour:

Xaml

<Window x:Class="ListViewTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ListViewTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>

        <ListView ItemsSource="{Binding LstFiles}" Grid.Column="0" Grid.Row="0"/>
        <Button Content="Los" Name="losBtn" Click="losBtn_Click" Grid.Column="0" Grid.Row="1" />
        <Button Content="del" Name="delBtn" Click="delBtn_Click" Grid.Column="0" Grid.Row="2" />
    </Grid>
</Window>

C# behind

using System.Collections.ObjectModel;
using System.Windows;

namespace ListViewTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public ObservableCollection<string> LstFiles { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            LstFiles = new ObservableCollection<string>();

            for (int i = 0; i < 20; i++)
            {
                LstFiles.Add(string.Format("file_{0}", i));
            }

            DataContext = this;
        }

        private  void losBtn_Click(object sender, RoutedEventArgs e)
        {

            for (int i = LstFiles.Count - 1; i >= 0; i--)
            {
                LstFiles.RemoveAt(i);
                System.Threading.Thread.Sleep(50);
            }   
        }

        private void delBtn_Click(object sender, RoutedEventArgs e)
        {
            LstFiles.RemoveAt(0);
        }
    }
}

The sleep is for simulating the time-consuming operations.


Solution

  • why is the ui not refreshing while deleting the items

    This is because you are calling Thread.Sleep(), which simply blocks the UI thread. You must never call that in a UI application.

    While it's unclear why you want to have this "delete loop" at all (instead of just clearing the ObservableCollection), you may use Task.Delay() instead of Sleep in an async Click handler method:

    private async void losBtn_Click(object sender, RoutedEventArgs e)
    {
        for (int i = LstFiles.Count - 1; i >= 0; i--)
        {
            LstFiles.RemoveAt(i);
            await Task.Delay(50);
        }   
    }
    

    If instead of a simple delay there is some time-consuming operation to be invoked, you may simply wrap that in a Task.Run call:

    private async void losBtn_Click(object sender, RoutedEventArgs e)
    {
        for (int i = LstFiles.Count - 1; i >= 0; i--)
        {
            LstFiles.RemoveAt(i);
            await Task.Run(() =>
            {
                // some long running operation
            });
        }   
    }