c# - 异步图像加载到列表框中

标签 c# wpf asynchronous wpf-controls

所以我正在构建一个 WPF 控件,它需要从磁盘加载(和显示)400 到 600 个图像(每个图像的大小约为 200Kb。)。接下来是控件的代码隐藏。

private List<BitmapImage> pages = new List<BitmapImage>();

        private BackgroundWorker worker;

        public PagesListBox()
        {
            InitializeComponent();
            worker = new BackgroundWorker();
            worker.WorkerSupportsCancellation = false;
            worker.WorkerReportsProgress = false;
            worker.DoWork += worker_DoWork;
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            List<BitmapImage> pagesList = new List<BitmapImage>();
            var files = DirectoryServices.GetFiles(Properties.Settings.Default.PagesScanDirectory, new string[] { "*.tiff", "*.jpg", "*.png", "*.bmp" });
            foreach (var file in files)
            {
                Uri uri = new Uri(file);
                pagesList.Add(new BitmapImage(uri));
            }
            e.Result = pagesList;
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Pages.ItemsSource = (List<BitmapImage>)e.Result;
        }

        internal void LoadPages()
        {
            worker.RunWorkerAsync();
        }

        internal List<BitmapImage> AttachPages()
        {
            List<BitmapImage> attachedPages = new List<BitmapImage>();

            foreach (BitmapImage eachItem in Pages.SelectedItems)
            {
                attachedPages.Add(eachItem);
                pages.Remove(eachItem);
            }
            Pages.ItemsSource = null;
            Pages.ItemsSource = pages;

            return attachedPages;
        }

我尝试将页面列表分配给 View (我不能使用后台工作程序),但它失败了。

是否有任何其他异步加载图像的方法(可能更新 UI)或我正在尝试的后台 worker 的这种方法很好。而且,如果没问题,我该如何解决异常(在完成的事件中):

Must create DependencySource on same Thread as the DependencyObject.

谢谢

最佳答案

为了简化您的代码,使用 ObservableCollection<> 而不是 List<> 并且只分配一次 ItemsSource 属性。

线程错误是因为您正在创建位图并将其添加到后台工作线程而不是主 UI 线程上的列表。要解决此问题,请使用 DispatcherHelper(取自 Laurent Bugnion 的 MVVMLight Framwwork)。

如果您要进行大量 WPF 开发,我建议您将 MVVM 视为一种应用程序设计方法,而不是仅仅按照“Winforms 方式”进行操作,尽管这是一种完全不同的思维方式。

...
DispatcherHelper.Initialise()
...


private ObservableCollection<BitmapImage> _Pages = new ObservableCollection<BitmapImage>();

public PagesListBox()
{
    InitializeComponent();
    BackgroundWorker worker = new BackgroundWorker();
    worker.WorkerSupportsCancellation = false;
    worker.WorkerReportsProgress = false;
    worker.DoWork += worker_DoWork;
    this.ItemSource = _Pages;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
     var files = DirectoryServices.GetFiles(Properties.Settings.Default.PagesScanDirectory, new string[] { "*.tiff", "*.jpg", "*.png", "*.bmp" });
    foreach (var file in files)
    {
        DispatcherHelper.CheckBeginInvokeOnUI(()=>
        {
            Uri uri = new Uri(file);
            _Pages.Add(new BitmapImage(uri));
        });
    }
}


public static class DispatcherHelper
{
    public static Dispatcher UIDispatcher { get; private set; }

    public static void CheckBeginInvokeOnUI(Action action)
    {
        if (UIDispatcher.CheckAccess())
            action();
        else
            UIDispatcher.BeginInvoke(action);
    }

    public static void Initialize()
    {
        if (UIDispatcher != null)
            return;

        UIDispatcher = Dispatcher.CurrentDispatcher;
    }
}

关于c# - 异步图像加载到列表框中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10134259/

相关文章:

sql-server - Entity Framework 4 - Trim Database Char(50) value for Name on legacy database

java - 等待异步调用先完成,然后在 Java 中继续

javascript - 什么是延迟api调用的好方法?

c# - Roslyn 的哪些部分可以与 VS 2013 一起使用?

c# - 根据参数在 Razor 中切换 Case

javascript - Keydown 功能在 aspx 页面上不起作用。!

WPF ValueConverter 绑定(bind) - 出了点问题

c# - 使用反射在异步方法中获取方法名称不会返回预期结果

c# - 如何使用 List<Object[]> 在 WPF 中填充 DataGrid?

c# - 在没有第二个线程的帮助下异步执行代码?