简体   繁体   English

WPF应用程序中后台工作者中的图像

[英]Images in Background Workers in WPF Application

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: 我有以下代码片段,可用于创建要添加到滚动查看器中的列表,作为WPF应用程序中的绑定:

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;

    }
}

This worked fine until I added a BackgroundWorker to process this. 在我添加BackgroundWorker进行处理之前,此方法一直很好。 Now, when execution gets to 现在,当执行到

Image thumbnail = new Image();

I get the following exception: 我得到以下异常:

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

Two questions: 两个问题:

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

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. 我希望它以这种方式工作,因为我处理的最大记录具有180张图像,并会产生大约10-15秒的挂起。

Do not create Image elements in code behind. 不要在后面的代码中创建Image元素。 Instead, use an ItemControl with an appropriate ItemTemplate: 而是使用带有适当ItemTemplate的ItemControl:

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

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. 冻结BitmapImage使其跨线程访问很重要。

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;
    }
}

which is initialized like this: 初始化如下:

private ViewModel viewModel = new ViewModel();

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

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

An alternative view model method could load the BitmapImages directly from a FileStream instead of an Uri: 另一种视图模型方法可以直接从FileStream而不是Uri加载BitmapImages:

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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM