如何编辑在非UI线程WritableBitmap.BackBuffer?线程、编辑、BackBuffer、UI

2023-09-02 10:51:44 作者:咸蛋骚人/:。

我的应用程序运行时CPU重algorythms编辑图像放置在一个WPF窗口。我需要的版本将在后台线程中完成的。然而尝试编辑WritableBitmap的后备缓冲非UI线程抛出InvalidOperationException异常。

My application runs CPU-heavy algorythms to edit an Image placed at a WPF window. I need the edition to be done in a background thread. However trying to edit the BackBuffer of WritableBitmap in non UI thread throws InvalidOperationException.

    private WriteableBitmap writeableBitmap;

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        // Create WritableBitmap in UI thread.
        this.writeableBitmap = new WriteableBitmap(10, 10, 96, 96, PixelFormats.Bgr24, null);
        this.image1.Source = this.writeableBitmap;

        // Run code in non UI thread.
        new Thread(
            () =>
            {
                // 'Edit' bitmap in non UI thread.
                this.writeableBitmap.Lock(); // Exception: The calling thread cannot access this object because a different thread owns it.

                // ... At this place the CPU is highly loaded, we edit this.writeableBitmap.BackBuffer.

                this.writeableBitmap.Unlock();
            }).Start();
    }

我看了几十说明书,所有的人都告诉我做后备缓冲版在UI线程(即的 MSDN )。

如何编辑WritableBitmap.BackBuffer在非UI线程没有任何无用的缓冲区拷贝/克隆?

How to edit the WritableBitmap.BackBuffer in a non UI thread without any useless buffer copying/cloning?

推荐答案

MSDN建议写入后备缓冲区在后台线程。只有某些pre型和后期的更新操作都需要进行UI线程。因此,尽管在后台线程进行实际更新,UI线程可以自由地做其它事情:

MSDN suggests writing to the backbuffer in a background thread. Only certain pre- and post update operations need to be carried out on the UI thread. So while the background thread is doing the actual updating, the UI thread is free to do other things:

        //Put this code in a method that is called from the background thread
        long pBackBuffer = 0, backBufferStride = 0;
        Application.Current.Dispatcher.Invoke(() =>
        {//lock bitmap in ui thread
            _bitmap.Lock();
            pBackBuffer = (long)_bitmap.BackBuffer;//Make pointer available to background thread
            backBufferStride = Bitmap.BackBufferStride;
        });
        //Back to the worker thread
        unsafe
        {
            //Carry out updates to the backbuffer here
            foreach (var update in updates)
            {
                long bufferWithOffset = pBackBuffer + GetBufferOffset(update.X, update.Y, backBufferStride);
                *((int*)bufferWithOffset) = update.Color;
            }
        }
        Application.Current.Dispatcher.Invoke(() =>
        {//UI thread does post update operations
            _bitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, width, height));
            _bitmap.Unlock();
        });