diff --git a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
index b662d20223..4e907f610d 100644
--- a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
+++ b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
@@ -2,6 +2,7 @@
using Avalonia.Controls.Metadata;
using Avalonia.Layout;
using Avalonia.Media;
+using Avalonia.Media.Imaging;
using Avalonia.Utilities;
namespace Avalonia.Controls.Primitives
@@ -31,6 +32,8 @@ namespace Avalonia.Controls.Primitives
protected bool ignorePropertyChanged = false;
+ private WriteableBitmap? _backgroundBitmap;
+
///
/// Initializes a new instance of the class.
///
@@ -38,6 +41,26 @@ namespace Avalonia.Controls.Primitives
{
}
+ ///
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ // Bitmaps were released when detached from the visual tree so they must be re-built
+ UpdateBackground();
+ }
+
+ ///
+ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnDetachedFromVisualTree(e);
+
+ // Clean-up all bitmaps
+ // https://github.com/AvaloniaUI/Avalonia/issues/9051
+ _backgroundBitmap?.Dispose();
+ _backgroundBitmap = null;
+ }
+
///
/// Updates the visual state of the control by applying latest PseudoClasses.
///
@@ -110,7 +133,19 @@ namespace Avalonia.Controls.Primitives
if (bitmap != null)
{
- Background = new ImageBrush(ColorPickerHelpers.CreateBitmapFromPixelData(bitmap, pixelWidth, pixelHeight));
+ if (_backgroundBitmap != null)
+ {
+ // Re-use the existing WriteableBitmap
+ // This assumes the height, width and byte counts are the same and must be set to null
+ // elsewhere if that assumption is ever not true.
+ ColorPickerHelpers.UpdateBitmapFromPixelData(_backgroundBitmap, bitmap);
+ }
+ else
+ {
+ _backgroundBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bitmap, pixelWidth, pixelHeight);
+ }
+
+ Background = new ImageBrush(_backgroundBitmap);
}
}
}
@@ -399,6 +434,11 @@ namespace Avalonia.Controls.Primitives
}
else if (change.Property == BoundsProperty)
{
+ // If the control's overall dimensions have changed the background bitmap size also needs to change.
+ // This means the existing bitmap must be released to be recreated correctly in UpdateBackground().
+ _backgroundBitmap?.Dispose();
+ _backgroundBitmap = null;
+
UpdateBackground();
}
else if (change.Property == ValueProperty ||
diff --git a/src/Avalonia.Controls.ColorPicker/Helpers/ColorPickerHelpers.cs b/src/Avalonia.Controls.ColorPicker/Helpers/ColorPickerHelpers.cs
index c1904a3c30..f2683e4677 100644
--- a/src/Avalonia.Controls.ColorPicker/Helpers/ColorPickerHelpers.cs
+++ b/src/Avalonia.Controls.ColorPicker/Helpers/ColorPickerHelpers.cs
@@ -617,7 +617,6 @@ namespace Avalonia.Controls.Primitives
PixelFormat.Bgra8888,
AlphaFormat.Premul);
- // Warning: This is highly questionable
using (var frameBuffer = bitmap.Lock())
{
Marshal.Copy(bgraPixelData.ToArray(), 0, frameBuffer.Address, bgraPixelData.Count);
@@ -625,5 +624,23 @@ namespace Avalonia.Controls.Primitives
return bitmap;
}
+
+ ///
+ /// Updates the given with new, raw BGRA pre-multiplied alpha pixel data.
+ /// WARNING: The bitmap's width, height and byte count MUST not have changed and MUST be enforced externally.
+ ///
+ /// The existing to update.
+ /// The bitmap (in raw BGRA pre-multiplied alpha pixels).
+ public static void UpdateBitmapFromPixelData(
+ WriteableBitmap bitmap,
+ IList bgraPixelData)
+ {
+ using (var frameBuffer = bitmap.Lock())
+ {
+ Marshal.Copy(bgraPixelData.ToArray(), 0, frameBuffer.Address, bgraPixelData.Count);
+ }
+
+ return;
+ }
}
}