How to edit a WritableBitmap.BackBuffer in non UI thread?
In WPF cross thread calls are done using the Dispatcher class.
In your case in the no-UI thread you need to get the instance of the Dispatcher of the thread where WritableBitmap is created.
On that dispatcher then call Invoke (or BeginInvoke if you want it asynchron)
Invoke then calls a delegate function where the BackBuffer is edited
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();
});
As Clemens said, this is impossible.
You have three choices:
1) Do your editing in a buffer and blit when finished as Clemens suggests.
2) Do the editing in very small chunks and schedule them at a nice priority on the GUI thread. If you keep your work chunks small enough, the GUI will remain responsive, but obviously this complicates the edit code.
3) Combine 1 & 2. Edit small chunks in another thread, then blit each chunk as it completes. This keeps GUI responsive without using memory for a full back buffer.
In addition to what Klaus78 said, i would suggest the following approach:
Perform asynchronous "bitmap editing" code on a separate buffer (e.g.
byte[]
) in a ThreadPool thread by means of QueueUserWorkItem. Do not create a new Thread every time you need to perform an asynchronous operation. That's what ThreadPool was made for.Copy the edited buffer by WritePixels in the WriteableBitmap's Dispatcher. No need for Lock/Unlock.
Example:
private byte[] buffer = new buffer[...];
private void UpdateBuffer()
{
ThreadPool.QueueUserWorkItem(
o =>
{
// write data to buffer...
Dispatcher.BeginInvoke((Action)(() => writeableBitmap.WritePixels(..., buffer, ...)));
});
}