首页 > 解决方案 > 当项目被添加到它的 ItemsSource 时,我如何显示被逐一添加到 ListView 的项目?

问题描述

我在 WPF 中使用 ListView 来显示一些图像,这是通过使用 Image 对象填充 ObservableCollection 并将该列表设置为 ItemsSource 来完成的。我的实现如下所示:

    public partial class MainWindow : Window
{
    public ObservableCollection<Image> imageList;

    public MainWindow()
    {
        InitializeComponent();
        imageList = new ObservableCollection<Image>();
        ImageView.ItemsSource = imageList;
    }

    private void loadImages(object sender, RoutedEventArgs e)
    {
        List<string> filePaths = Directory.GetFiles(@"C:\SomeImages")
        foreach (string filePath in filePaths)
        {
            Image image = new Image();
            BitmapImage bimage = new BitmapImage();
            bimage.BeginInit();
            bimage.UriSource = new Uri(filePath, UriKind.Absolute);
            bimage.EndInit();
            image.Source = bimage;
            imageList.Add(image);
        }
    }
}

我的目的是让 UI 在每次 foreach 循环迭代时更新一次,因为可观察列表已填满。然而,在将控制权返回给 UI 之前,foreach 循环会完全填满列表,然后同时显示所有图片。由于大约有 100 张图片,这会使程序滞后几秒钟。

有什么办法可以让程序一次更新一个 UI 元素,并且还可能保持 UI 响应?

标签: c#wpf

解决方案


听起来您需要以异步方式加载图像

private async void loadImages(object sender, RoutedEventArgs e)
{
    await Task.Run(() =>
    {
        var filePaths = Directory.EnumerateFiles(@"C:\SomeImages");

        foreach (string filePath in filePaths)
        {
            var bimage = new BitmapImage();
            bimage.BeginInit();
            bimage.CacheOption = BitmapCacheOption.OnLoad;
            bimage.UriSource = new Uri(filePath, UriKind.Absolute);
            bimage.EndInit();
            bimage.Freeze();

            Dispatcher.Invoke(() => imageList.Add(new Image { Source = bimage }));
        }
    });
}

但是你不应该在后面的代码中创建 UI 元素。将 Image 元素移动到 ListBox 的 ItemTemplate:

<ListBox x:Name="ImageView">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Image Source="{Binding}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

将后面的代码更改为:

private readonly ObservableCollection<ImageSource> imageList
    = new ObservableCollection<ImageSource>();

public MainWindow()
{
    InitializeComponent();
    ImageView.ItemsSource = imageList;
}

并将 BitmapImages 直接添加到列表中:

Dispatcher.Invoke(() => imageList.Add(bimage)); 

推荐阅读