dotnet/wpf · error · ArgumentException

SR.SharingNonSharableExpression

Error message

SR.SharingNonSharableExpression

What it means

During SetValueCommon, if the new value is an Expression (binding/expression markup extension) that is not Attachable (i.e. its Attachable property is false), WPF throws ArgumentException(SR.SharingNonSharableExpression). Expressions must be attachable to be shared/assigned onto dependency properties; non-attachable expressions cannot be shared across DependencyObjects or attached in the current context.

Solutions

  1. Create a fresh Binding/Expression instance per target instead of sharing one instance.
  2. Use BindingOperations.SetBinding with a properly constructed Binding whose properties allow attachment.
  3. If writing a custom Expression/MarkupExtension, implement and set Attachable correctly (allow multiple attach or clone on attach).

Example fix

// before
var binding = new Binding("Name") { Source = vm };
control1.SetBinding(TextBlock.TextProperty, binding);
control2.SetBinding(TextBlock.TextProperty, binding); // shared
// after
control1.SetBinding(TextBlock.TextProperty, new Binding("Name") { Source = vm });
control2.SetBinding(TextBlock.TextProperty, new Binding("Name") { Source = vm });
Defensive patterns

Strategy: type-guard

Validate before calling

if (value is Expression expr && !expr.Attachable)
    throw new InvalidOperationException("Expression is not attachable; create a new instance per target.");

Type guard

bool IsShareableExpression(object v) => v is not Expression e || e.Attachable;

Try / catch

try { target.SetValue(TargetProperty, exprValue); }
catch (ArgumentException ex) when (ex.Message.Contains("attachable") || ex.Message.Contains("Expression"))
{
    target.SetBinding(TargetProperty, CreateFreshBinding()); // new instance per target
}

Prevention

When it happens

Trigger: Assigning an expression instance (BindingBase, custom Expression) with Attachable == false to a DP via SetValue; reusing a single expression object across multiple targets when it was created non-shareable (e.g. a Binding whose-source state forbids sharing).

Common situations: Caching one Binding object and applying it to many controls; programmatically building expressions with incorrect internal flags; expressions deserialized from XAML that lost attachable state.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/DependencyObject.cs:666

            // First try to validate the value; only after this validation fails should we
            // do the more expensive checks (type checks) for the less common scenarios
            if (!newValueHasExpressionMarker)
            {
                bool isValidValue = isInternal ? dp.IsValidValueInternal(value) : dp.IsValidValue(value);

                // for properties of type "object", we have to always check for expression & deferredreference
                if (!isValidValue || dp.IsObjectType)
                {
                    // 2nd most common is expression
                    newExpr = value as Expression;
                    if (newExpr != null)
                    {
                        // For Expressions, perform additional validation
                        // Make sure Expression is "attachable"
                        if (!newExpr.Attachable)
                        {
                            throw new ArgumentException(SR.SharingNonSharableExpression);
                        }

                        // Check dispatchers of all Sources
                        // CALLBACK
                        newSources = newExpr.GetSources();
                        ValidateSources(this, newSources, newExpr);
                    }
                    else
                    {
                        // and least common is DeferredReference
                        isDeferredReference = (value is DeferredReference);
                        if (!isDeferredReference)
                        {
                            if (!isValidValue)
                            {
                                // it's not a valid value & it's not an expression, so throw
                                throw new ArgumentException(SR.Format(SR.InvalidPropertyValue, value, dp.Name));
                            }

View on GitHub (pinned to 81131a70a4)