HandyOrg/HandyControl · error · InvalidOperationException

ExceptionStringTable.CannotHostBehaviorCollectionMultipleTim…

Error message

ExceptionStringTable.CannotHostBehaviorCollectionMultipleTimesExceptionMessage

What it means

A BehaviorCollection is already attached to some object if its AssociatedObject is non-null. Interaction.OnBehaviorsChanged throws InvalidOperationException CannotHostBehaviorCollectionMultipleTimesExceptionMessage when the new collection assigned to a second element is already hosted elsewhere, preserving the one-collection-per-host invariant.

Solutions

  1. Give each host its own new BehaviorCollection instance.
  2. Remove the collection from the previous host so its AssociatedObject is cleared before reassigning.
  3. Use x:Shared="False" for collection resources in XAML so each reference gets a fresh instance.
  4. Define collections per-control in a Style Setter rather than sharing instances.

Example fix

// before
var collection = new BehaviorCollection { new MyBehavior() };
element1.SetValue(Interaction.BehaviorsProperty, collection);
element2.SetValue(Interaction.BehaviorsProperty, collection); // 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 (sharedCollection.AssociatedObject != null)
    sharedCollection = new BehaviorCollection(sharedCollection); // clone before re-hosting

Type guard

static bool CanHostCollection(BehaviorCollection c) => c.AssociatedObject == null;

Try / catch

try { Interaction.SetBehaviors(element, collection); }
catch (InvalidOperationException ex) when (ex.Message.Contains("BehaviorCollectionMultipleTimes")) {
    // assign a fresh BehaviorCollection instance
}

Prevention

When it happens

Trigger: Assigning the same BehaviorCollection instance to Interaction.GetBehaviors(obj2) (via the BehaviorsProperty change handler) when that collection's AssociatedObject is already set to another element.

Common situations: Sharing a BehaviorCollection instance between two controls in code; moving a control in the visual tree so its Behaviors property value gets reused; copying dependency property values that carry the same collection instance; resource reuse in styles where the collection is a shared resource.

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/7141d8b4b850f7a7. Report an issue: GitHub.

Appendix: source

Thrown at src/Shared/System.Windows.Interactivity/Interaction.cs:51

        {
            behaviorCollection = new BehaviorCollection();
            obj.SetValue(BehaviorsProperty, behaviorCollection);
        }
        return behaviorCollection;
    }

    private static void OnBehaviorsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var oldValue = (BehaviorCollection) args.OldValue;
        var newValue = (BehaviorCollection) args.NewValue;
        if (Equals(oldValue, newValue))
            return;
        if (oldValue?.AssociatedObject != null)
            oldValue.Detach();
        if (newValue == null || obj == null)
            return;
        if (newValue.AssociatedObject != null)
            throw new InvalidOperationException(ExceptionStringTable
                .CannotHostBehaviorCollectionMultipleTimesExceptionMessage);
        newValue.Attach(obj);
    }

    private static void OnTriggersChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var oldValue = args.OldValue as TriggerCollection;
        var newValue = args.NewValue as TriggerCollection;
        if (Equals(oldValue, newValue))
            return;
        if (oldValue?.AssociatedObject != null)
            oldValue.Detach();
        if (newValue == null || obj == null)
            return;
        if (newValue.AssociatedObject != null)
            throw new InvalidOperationException(ExceptionStringTable
                .CannotHostTriggerCollectionMultipleTimesExceptionMessage);
        newValue.Attach(obj);

View on GitHub (pinned to 2c0875ebd6)