Add Element By Element to ListView Without blocking UI

天大地大妈咪最大 提交于 2020-01-03 05:57:11

问题


I am developing a Wpf application which retrieves the data from a database using EF.

I have some ListView controls which are filled with some tables of the database so in order to prevent from blocking the UI while retrieving the data I do as follows:

        Task tsk = Task.Factory.StartNew(() =>
        {
            ItemsSource = Database.SomeTable();
        });

The ItemsSource variable is an ObservableCollection which is bound to the ItemsSource property of a ListView.

The thing is that, as expected, while loading the data the UI keeps responsive. My problem is that the ListView is empty until all the data is loaded. So I would like to see element by element appearing in the ListView. Is there a way to do that?? I have tried which a foreach loop with no luck.

Thanks in advance.


回答1:


This can be accomplished by dispatching the addition of new elements to your observable collection using the Disptacher's BeginInvoke method, called from your task. Something like:

//MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ListView ItemsSource="{Binding MyList}" Grid.Row="0" />
        <Button Content="Load" Click="OnLoadClicked" Grid.Row="1" Height="30" />
    </Grid>
</Window>

//MainWindow.xaml.cs

using System;
using System.Collections.ObjectModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private VM _vm = new VM();
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = _vm;
        }

        private void OnLoadClicked(object sender, RoutedEventArgs e)
        {
            Load10Rows();            
        }

        private void Load10Rows()
        {
            Task.Factory.StartNew(() =>
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                _vm.MyList.Add(DateTime.Now.ToString());
                            }), DispatcherPriority.Background);
                        // Just to simulate some work on the background
                        Thread.Sleep(1000);
                    }
                });
        }
    }

    public class VM
    {
        private ObservableCollection<string> _myList;
        public VM()
        {
            _myList = new ObservableCollection<string>();
        }

        public ObservableCollection<string> MyList
        {
            get { return _myList; }
        }
    }
}

If you have a large amount of records you may want to chunk it, otherwise just call the Disptacher for each record.




回答2:


Perhaps using Task.Delay to allow the UI to render the changes before adding the next item in the foreach will work

Example:

private async Task AddItems()
{
    foreach (var item in Database.SomeTable())
    {
        ItemsSource.Add(item);
        await Task.Delay(1);
    }
}


来源:https://stackoverflow.com/questions/19579734/add-element-by-element-to-listview-without-blocking-ui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!