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 に答える