dotnet/wpf · error · ArgumentException

SR.Format(SR.PropertyNotBindable, dp.Name)

Error message

SR.Format(SR.PropertyNotBindable, dp.Name)

What it means

CreateBindingExpression validates that the target DependencyProperty allows data binding: it must be writable and its FrameworkPropertyMetadata must have IsDataBindingAllowed (not read-only and not restrictions like not-data-bindable). Binding a read-only or non-bindable property is rejected with an ArgumentException naming the property.

Solutions

  1. Bind only to writable, data-bindable dependency properties — check dp.ReadOnly and FrameworkPropertyMetadata.IsDataBindingAllowed first
  2. For read-only values, bind the opposite direction (bind another property to the read-only one via OneWay from it), or use the read-only DP's ChangeMachine/Listen via descriptor
  3. Expose your own bindable DP and synchronize it from the read-only source if binding input is required

Example fix

// before
label.SetBinding(UIElement.ActualWidthProperty, new Binding("Width")); // ArgumentException: PropertyNotBindable
// after
label.SetBinding(Label.WidthProperty, new Binding("Width"));
Defensive patterns

Strategy: validation

Validate before calling

var md = dp.GetMetadata(target.GetType()) as FrameworkPropertyMetadata;
if (dp.ReadOnly || md == null || !md.IsDataBindingAllowed) throw new ArgumentException($"{dp.Name} is not data-bindable");

Type guard

static bool IsBindable(DependencyProperty dp, DependencyObject d) => !dp.ReadOnly && dp.GetMetadata(d.DependencyObjectType) is FrameworkPropertyMetadata fmd && fmd.IsDataBindingAllowed;

Try / catch

try { target.SetBinding(dp, binding); } catch (ArgumentException ex) when (ex.Message.Contains("bindable") || ex.ParamName == "dp") { /* bind a writable DP instead */ }

Prevention

When it happens

Trigger: Calling BindingOperations.SetBinding (or creating a BindingExpression) targeting a read-only dependency property (e.g. UIElement.HasStroke... style read-only DPs), or a property whose metadata sets IsDataBindingAllowed=false (e.g. reads-only triggers properties).

Common situations: Attempting to bind to read-only DPs like ActualWidth, ItemsControl.Items, or trigger-only properties; framework migrations exposing properties as read-only; generic helper code that binds any DP without checking dp.ReadOnly.

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/49916924a22c91d4. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingExpression.cs:394

            get { return GetReference(_dataItem) == DisconnectedItem; }
        }

        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        // Create a new BindingExpression from the given Bind description
        internal static BindingExpression CreateBindingExpression(DependencyObject d,
                                                DependencyProperty dp,
                                                Binding binding,
                                                BindingExpressionBase parent)
        {
            FrameworkPropertyMetadata fwMetaData = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata;

            if ((fwMetaData != null && !fwMetaData.IsDataBindingAllowed) || dp.ReadOnly)
                throw new ArgumentException(SR.Format(SR.PropertyNotBindable, dp.Name), nameof(dp));

            // create the BindingExpression
            BindingExpression bindExpr = new BindingExpression(binding, parent);

            bindExpr.ResolvePropertyDefaultSettings(binding.Mode, binding.UpdateSourceTrigger, fwMetaData);

            // Two-way Binding with an empty path makes no sense
            if (bindExpr.IsReflective && binding.XPath == null &&
                    (binding.Path == null || String.IsNullOrEmpty(binding.Path.Path)))
                throw new InvalidOperationException(SR.TwoWayBindingNeedsPath);

            return bindExpr;
        }


        // Note: For Nullable types, DefaultValueConverter is created for the inner type of the Nullable.
        //       Nullable "Drill-down" service is not provided for user provided Converters.
        internal void SetupDefaultValueConverter(Type type)

View on GitHub (pinned to 81131a70a4)