WPF应用程序中后台工作者中的图像 [英] Images in Background Workers in WPF Application

查看:49
本文介绍了WPF应用程序中后台工作者中的图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码片段,可用于创建一个列表,以将其添加到滚动查看器中,作为WPF应用程序中的绑定:

I have the following code snippet that I use to create a List to add to a scrollviewer as a binding in a WPF application:

private void LoadThumbs(object sender, DoWorkEventArgs e)
{
        //ClearScreen();
        int max = (int)e.Argument;
        int current = 0;



        foreach (string filename in filenames)
        {
            Image thumbnail = new Image();
            Uri image_path = new Uri(filename);
            BitmapImage image = new BitmapImage(image_path);

            Thickness thumb_margin = thumbnail.Margin;
            thumb_margin.Bottom = 2.5;
            thumb_margin.Top = 2.5;
            thumb_margin.Left = 2.5;
            thumb_margin.Right = 2.5;

            thumbnail.Margin = thumb_margin;
            thumbnail.Width = 100;

            image.DecodePixelWidth = 200;

            thumbnail.Source = image;
            thumbnail.Tag = filename;

            thumbnail.MouseDown += image_Click;
            thumbnail.MouseEnter += hand_Over;
            thumbnail.MouseLeave += normal_Out;

            images.Add(thumbnail);

            thumbnail = null;

    }
}

这很好,直到我添加BackgroundWorker来处理它.现在,执行到

This worked fine until I added a BackgroundWorker to process this. Now, when execution gets to

Image thumbnail = new Image();

我收到以下异常:

System.InvalidOperationException: 'The calling thread must be STA, because many UI components require this.'

两个问题:

(1)如何处理此代码以允许后台工作人员在Image上工作,或者,(2)是否有更好的方法来做我正在做的工作,以允许BackgroundWorker工作?

(1) How can I process this code to allow the background worker to work on Image, or, (2) is there a better way to do what I am doing to allow for the BackgroundWorker to work?

我在多线程环境中的工作经验为零.我希望它能以这种方式工作,因为我处理的最大记录有180张图像,并会产生大约10-15秒的挂起.

I have zero experience working in a multi-threaded environment. I want it to work this way because the largest record I process has 180 images and creates about a 10-15 second hang.

推荐答案

请勿在后面的代码中创建Image元素.而是使用带有适当ItemTemplate的ItemControl:

Do not create Image elements in code behind. Instead, use an ItemControl with an appropriate ItemTemplate:

<ScrollViewer>
    <ItemsControl ItemsSource="{Binding Images}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

将其绑定到如下所示的视图模型,该模型能够异步加载图像文件.冻结BitmapImage以便使其可以跨线程访问非常重要.

Bind it to a view model like shown below, which is capable of asynchronously loading the image files. It is important that the BitmapImages are frozen to make them cross-thread accessible.

public class ViewModel
{
    public ObservableCollection<ImageSource> Images { get; }
        = new ObservableCollection<ImageSource>();

    public async Task LoadImagesAsync(IEnumerable<string> filenames)
    {
        foreach (var filename in filenames)
        {
            Images.Add(await Task.Run(() => LoadImage(filename)));
        }
    }

    public ImageSource LoadImage(string filename)
    {
        var bitmap = new BitmapImage();
        bitmap.BeginInit();
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.DecodePixelWidth = 200;
        bitmap.UriSource = new Uri(filename);
        bitmap.EndInit();
        bitmap.Freeze();
        return bitmap;
    }
}

按如下方式初始化:

private ViewModel viewModel = new ViewModel();

public MainWindow()
{
    InitializeComponent();
    DataContext = viewModel;
}

private async void Button_Click(object sender, RoutedEventArgs e)
{
    ...
    await viewModel.LoadImagesAsync(..., "*.jpg"));
}


另一种视图模型方法可以直接从FileStream而不是Uri加载BitmapImages:


An alternative view model method could load the BitmapImages directly from a FileStream instead of an Uri:

public ImageSource LoadImage(string filename)
{
    using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        var bitmap = new BitmapImage();
        bitmap.BeginInit();
        bitmap.DecodePixelWidth = 200;
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.StreamSource = stream;
        bitmap.EndInit();
        bitmap.Freeze();
        return bitmap;
    }
}

这篇关于WPF应用程序中后台工作者中的图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆