C
C#2y ago
Cyclonit

❔ Refresh WriteableBitmap

Hi, I would like to use a WriteableBitmap in my application. However, the Image control does not update when the backing WriteableBitmap changes. The examples I could find online appear to use WriteableBitmap.AddDirtyRect to trigger the update. But in my case this does not nothing. My control looks like this:
<UserControl ... />
<Image x:Name="bitmap"
Source="{Binding Bitmap}"
Opacity=".25">
</Image>
</UserControl>
<UserControl ... />
<Image x:Name="bitmap"
Source="{Binding Bitmap}"
Opacity=".25">
</Image>
</UserControl>
And the relevant code within the ViewModel:
public class BitGridViewModel : ObservableBase
{
private static readonly Color trueColor = Color.FromArgb(0xAA, 0xFF, 0x00, 0x00);
private static readonly Color falseColor = Color.FromArgb(0xAA, 0xFF, 0xFF, 0xFF);

public WriteableBitmap Bitmap
{
get => _bitmap;
set => SetProperty(ref _bitmap, value);
}
private WriteableBitmap _bitmap;

...

// https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.writeablebitmap?view=windowsdesktop-7.0
private static void DrawPixel(WriteableBitmap bitmap, int x, int y, Color color)
{
if (bitmap.Format != PixelFormats.Bgr32)
throw new ArgumentException();

try
{
bitmap.Lock();

unsafe
{
// determine the pixel's address within the Bitmap, depends on the Bitmap's PixelFormat
IntPtr pBackBufferAddr = bitmap.BackBuffer;
IntPtr pixelAddr = pBackBufferAddr + y * bitmap.BackBufferStride + x * 4;

// compute the pixel's color, depends on the Bitmap's PixelFormat
int colorData = (color.R << 16) | (color.G << 8) | (color.B << 0);

// set the pixel
*((int*)pixelAddr) = colorData;
}

bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
}
finally
{
bitmap.Unlock();
}
}
}
public class BitGridViewModel : ObservableBase
{
private static readonly Color trueColor = Color.FromArgb(0xAA, 0xFF, 0x00, 0x00);
private static readonly Color falseColor = Color.FromArgb(0xAA, 0xFF, 0xFF, 0xFF);

public WriteableBitmap Bitmap
{
get => _bitmap;
set => SetProperty(ref _bitmap, value);
}
private WriteableBitmap _bitmap;

...

// https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.writeablebitmap?view=windowsdesktop-7.0
private static void DrawPixel(WriteableBitmap bitmap, int x, int y, Color color)
{
if (bitmap.Format != PixelFormats.Bgr32)
throw new ArgumentException();

try
{
bitmap.Lock();

unsafe
{
// determine the pixel's address within the Bitmap, depends on the Bitmap's PixelFormat
IntPtr pBackBufferAddr = bitmap.BackBuffer;
IntPtr pixelAddr = pBackBufferAddr + y * bitmap.BackBufferStride + x * 4;

// compute the pixel's color, depends on the Bitmap's PixelFormat
int colorData = (color.R << 16) | (color.G << 8) | (color.B << 0);

// set the pixel
*((int*)pixelAddr) = colorData;
}

bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
}
finally
{
bitmap.Unlock();
}
}
}
5 Replies
JakenVeina
JakenVeina2y ago
it looks like what you want is WritableBitmap.Invalidate()
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Cyclonit
CyclonitOP2y ago
WriteableBitmap does not have a method called "Invalidate()". I tried using InvalidateVisual on the control, but that doesn't change anything either.
JakenVeina
JakenVeina2y ago
welp so, based on the documentation, what you're supposed to do to get refreshes to trigger properly is either A) use WritePixels() whenever you change the bitmap B) Manually trigger refreshes of some or all of the bitmap with Lock()/AddDirtyRect()/Unlock() preferrably A) if either of those isn't doing it, I'd have to guess your setup is wrong
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server