dotnet/wpf · error · InvalidOperationException

SR.BitmapCacheBrush_TransformChanged

Error message

SR.BitmapCacheBrush_TransformChanged

What it means

BitmapCacheBrush does not support a Transform other than the default (null); the CoerceTransform coercion callback throws whenever a Transform is assigned. Transforms must be applied to the cached content or the rendering element, not the brush.

Solutions

  1. Remove the Transform assignment from BitmapCacheBrush
  2. Apply the transform to the Target visual or to the element using the brush (RenderTransform)
  3. If a transform on the cached rendering is required, restructure so the transform is baked into the cached visual

Example fix

// before
var brush = new BitmapCacheBrush { Target = visual, Transform = new TranslateTransform(10, 0) };
// after
var brush = new BitmapCacheBrush { Target = visual };
visual.RenderTransform = new TranslateTransform(10, 0);
Defensive patterns

Strategy: validation

Validate before calling

if (brush is BitmapCacheBrush && brush.Transform != null) throw new InvalidOperationException("BitmapCacheBrush does not support Transform");

Type guard

bool supportsTransform(Brush b) => b is not BitmapCacheBrush;

Try / catch

try { cacheBrush.Transform = t; }
catch (InvalidOperationException) { targetVisual.RenderTransform = t; /* apply elsewhere */ }

Prevention

When it happens

Trigger: Setting BitmapCacheBrush.Transform to any Transform instance (e.g. TranslateTransform, RotateTransform) in code, XAML (<BitmapCacheBrush><BitmapCacheBrush.Transform>...</...>), or via binding/animation.

Common situations: Developers porting brush code from TileBrush/ImageBrush (which support Transform) to BitmapCacheBrush and carrying over the Transform assignment.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/7321f4d0ec4bc3fa. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/BitmapCacheBrush.cs:362

        {
            Debug.Assert(_reentrancyFlag); // Exit must be matched with Enter. See Enter comments.
            _reentrancyFlag = false;
        }       

        private static object CoerceOpacity(DependencyObject d, object value)
        {
            if ((double)value != (double)OpacityProperty.GetDefaultValue(typeof(BitmapCacheBrush)))
            {
                throw new InvalidOperationException(SR.BitmapCacheBrush_OpacityChanged);
            }
            return 1.0;
        }

        private static object CoerceTransform(DependencyObject d, object value)
        {
            if ((Transform)value != (Transform)TransformProperty.GetDefaultValue(typeof(BitmapCacheBrush)))
            {
                throw new InvalidOperationException(SR.BitmapCacheBrush_TransformChanged);
            }
            return null;
        }

        private static object CoerceRelativeTransform(DependencyObject d, object value)
        {
            if ((Transform)value != (Transform)RelativeTransformProperty.GetDefaultValue(typeof(BitmapCacheBrush)))
            {
                throw new InvalidOperationException(SR.BitmapCacheBrush_RelativeTransformChanged);
            }
            return null;
        }

        private static void StaticInitialize(Type typeofThis)
        {             
            OpacityProperty.OverrideMetadata(typeofThis, new IndependentlyAnimatedPropertyMetadata(1.0, propertyChangedCallback: null, CoerceOpacity));
            TransformProperty.OverrideMetadata(typeofThis, new UIPropertyMetadata(null, propertyChangedCallback: null, CoerceTransform));
            RelativeTransformProperty.OverrideMetadata(typeofThis, new UIPropertyMetadata(null, propertyChangedCallback: null, CoerceRelativeTransform));

View on GitHub (pinned to 81131a70a4)