1

我正在尝试将多个图像异步加载到 ui 中。

加载图像时(从路径创建位图),应将图像设置为窗口上矩形的填充。

当我将位图图像的创建也放在 Dispatcher.Invoke 方法中时,代码就可以工作了。但显然我希望在胎面而不是在调用中完成繁重的工作(创建位图)。

我尝试了几种解决方案,包括 backgroundworker,但我无法让它工作。现在我有以下代码:

private void Window_ContentRendered(object sender, EventArgs e)
{
    Thread loadThread = new Thread(new ThreadStart(LoadImagesAsync));
    loadThread.Start();
}

private void LoadImagesAsync()
{
    IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES);

    for (int i = 0; i < NUMBER_OF_IMAGES; i++)
    {
        var bitm = new BitmapImage(new Uri(images.ElementAt(i)));                

        this.Dispatcher.Invoke(() =>
        {
            Grid grid = (Grid)grd_photoBox.Children[i];

            var rectangle = (from e in grid.Children.OfType<Rectangle>()
                                where e is Rectangle
                                select e).First();

            ImageBrush brush = new ImageBrush(bitm);

            rectangle.Fill = brush;
        });
    }
}

我得到以下异常:

The calling thread cannot access this object because a different thread owns it.

有什么线索吗?

4

3 回答 3

3

如果是大图像,请使用以下代码,它将直接重新缩放图像并加载到其他线程然后主线程,以确保立即加载图像。编辑以下值以更改加载格式:

bitm.DecodePixelWidth = 200;
bitm.DecodePixelHeight = 100;

private void LoadImagesAsync()
        {
            IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES);

            for (int i = 0; i < NUMBER_OF_IMAGES; i++)
            {
                int j = i;
                var bitm = new BitmapImage();

                bitm.BeginInit();
                bitm.CacheOption = BitmapCacheOption.OnLoad;
                bitm.UriSource = new Uri(images.ElementAt(i));
                bitm.DecodePixelWidth = 200;
                bitm.DecodePixelHeight = 100;
                bitm.EndInit();

                ImageBrush brush = new ImageBrush(bitm);
                brush.Freeze();

                this.Dispatcher.BeginInvoke(new Action(() => 
                {
                    Grid grid = (Grid)grd_photoBox.Children[j];

                    var rectangle = (from e in grid.Children.OfType<Rectangle>()
                                        where e is Rectangle
                                        select e).First();

                    rectangle.Fill = brush;
                }));
            }
        }
于 2013-03-19T21:12:06.383 回答
1

诀窍是冻结位图以允许从另一个线程访问。因此,您还必须确保位图在创建时立即加载,因为默认行为是延迟加载。

var bitm = new BitmapImage();
bitm.BeginInit();
bitm.CacheOption = BitmapCacheOption.OnLoad; // load immediately
bitm.UriSource = new Uri(images.ElementAt(i));
bitm.EndInit();
bitm.Freeze();
于 2013-03-19T19:29:01.063 回答
0

我尝试了下面的代码,它对我有用。

Task<IEnumerable<string>>.Factory.StartNew(() => System.IO.Directory.GetFiles(
            imagePath,
            "*.jpg")).
            ContinueWith(task =>
                        {
                            foreach (var item in task.Result)
                            {
                                this.Dispatcher.BeginInvoke((Action)(() =>
                                {
                                    var img = new Image
                                                    {
                                                        Source =
                                                            new BitmapImage(
                                                            new Uri(item))
                                                    };
                                    LayoutRoot.Children.Add(img);

                                }));

                            }
                        });

LayoutRoot 是我在 xaml 中的网格。

希望它会有所帮助。

于 2013-03-19T18:23:26.060 回答