HandyOrg/HandyControl · error · InvalidOperationException

ExceptionStringTable.CannotHostBehaviorMultipleTimesExceptio…

Error message

ExceptionStringTable.CannotHostBehaviorMultipleTimesExceptionMessage

What it means

A Behavior instance in System.Windows.Interactivity can be attached to only one DependencyObject at a time. Attaching it while it is already associated with another object throws InvalidOperationException with CannotHostBehaviorMultipleTimesExceptionMessage. This guards the one-to-one invariant between a behavior and its AssociatedObject.

Solutions

  1. Create a new behavior instance for each attached object instead of sharing one instance.
  2. Detach the behavior from its current host (oldHost.Interaction.Behaviors.Remove(behavior)) before attaching it to a new object.
  3. Check behavior.AssociatedObject == null before calling Attach.
  4. Clear/rebuild the Behaviors collection on the previous host when moving the behavior.

Example fix

// before
var behavior = new MyBehavior();
element1.SetValue(Interaction.BehaviorsProperty, new BehaviorCollection { behavior });
element2.SetValue(Interaction.BehaviorsProperty, new BehaviorCollection { behavior }); // throws
// after
element1.SetValue(Interaction.BehaviorsProperty, new BehaviorCollection { new MyBehavior() });
element2.SetValue(Interaction.BehaviorsProperty, new BehaviorCollection { new MyBehavior() });
Defensive patterns

Strategy: validation

Validate before calling

if (behavior.AssociatedObject != null && !ReferenceEquals(behavior.AssociatedObject, target))
    behavior = (Behavior)Activator.CreateInstance(behavior.GetType()); // fresh instance per host
behavior.Attach(target);

Type guard

static bool CanAttach(Behavior b, DependencyObject target) =>
    b.AssociatedObject == null && target != null && b.AssociatedType.IsInstanceOfType(target);

Try / catch

try { behavior.Attach(target); }
catch (InvalidOperationException ex) when (ex.Message.Contains("CannotHostBehaviorMultipleTimes")) {
    // create a new instance of the behavior for this host
}

Prevention

When it happens

Trigger: Calling behavior.Attach(newObject) (directly or via BehaviorCollection.ItemAdded) on a behavior whose AssociatedObject is already non-null and different from newObject.

Common situations: Reusing a single behavior instance across multiple controls; adding the same behavior to a second element's Interaction.Behaviors collection; a collection property-change firing twice so the same behavior is attached twice; re-attaching after forgetting the old host still holds it.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of HandyOrg/HandyControl@2c0875ebd6 (2026-09-14). Data as JSON: /api/errors/67d2228479199e69. Report an issue: GitHub.

Appendix: source

Thrown at src/Shared/System.Windows.Interactivity/Behavior.cs:41

            return _associatedObject;
        }
    }

    protected Type AssociatedType
    {
        get
        {
            ReadPreamble();
            return _associatedType;
        }
    }

    public void Attach(DependencyObject dependencyObject)
    {
        if (!Equals(dependencyObject, AssociatedObject))
        {
            if (AssociatedObject != null)
                throw new InvalidOperationException(ExceptionStringTable
                    .CannotHostBehaviorMultipleTimesExceptionMessage);
            if (dependencyObject != null && !AssociatedType.IsInstanceOfType(dependencyObject))
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
                    ExceptionStringTable.TypeConstraintViolatedExceptionMessage,
                    new object[] { GetType().Name, dependencyObject.GetType().Name, AssociatedType.Name }));
            WritePreamble();
            _associatedObject = dependencyObject;
            WritePostscript();
            OnAssociatedObjectChanged();
            OnAttached();
        }
    }

    public void Detach()
    {
        OnDetaching();
        WritePreamble();
        _associatedObject = null;

View on GitHub (pinned to 2c0875ebd6)