stride3d/stride · error · InvalidOperationException
This BehaviorCollection has already been attached to a…
Error message
This BehaviorCollection has already been attached to a dependency object.
What it means
BehaviorCollection.Attach throws InvalidOperationException when the collection's AssociatedObject is already set to a different dependency object. Each BehaviorCollection instance may be attached to exactly one object for its lifetime; re-attaching is an unsupported state transition.
Solutions
- Create a new BehaviorCollection for each dependency object instead of reusing one.
- Detach from the old object (set AssociatedObject to null / use Detach if available) before re-attaching.
- Store behaviors as per-instance resources rather than shared StaticResource; use DynamicResource or x:Shared="False".
- Guard with ReferenceEquals(AssociatedObject, target) checks — Attach is a no-op for the same object.
Example fix
// before var shared = (BehaviorCollection)Application.Current.Resources["MyBehaviors"]; shared.Attach(controlA); shared.Attach(controlB); // throws // after var forA = new BehaviorCollection(); forA.AddRange(shared); forA.Attach(controlA);
Defensive patterns
Strategy: try-catch
Validate before calling
if (behaviors.AssociatedObject != null && !ReferenceEquals(behaviors.AssociatedObject, target))
behaviors = CloneBehaviors(behaviors); // make a per-control copy
behaviors.Attach(target); Type guard
static bool CanAttach(BehaviorCollection c, DependencyObject target) => c.AssociatedObject == null || ReferenceEquals(c.AssociatedObject, target);
Try / catch
try { behaviors.Attach(control); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already been attached"))
{
var copy = new BehaviorCollection();
copy.AddRange(behaviors);
copy.Attach(control);
} Prevention
- Never share BehaviorCollection instances via StaticResource; use x:Shared="False" or per-instance creation
- Detach before re-attaching to another object
- Assume Attach is one-shot per collection instance
When it happens
Trigger: Calling Attach on a BehaviorCollection whose AssociatedObject is non-null and different from the new dependencyObject; reusing a BehaviorCollection across windows/controls; re-attaching a collection stored in a shared resource.
Common situations: Sharing a BehaviorCollection defined in App.xaml resources between multiple controls; recycling controls in virtualized lists while keeping behavior collections; calling Attach twice after re-templating.
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
- No handler was previously registered for this dependency…
- The given is already registered as a clipboard listener.
- No Collection item identifier associated to the given…
- Package RootDirectory is null
- Cannot find the specified AssetItem instance in the session
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/cbbdde6e34ddc114.
Report an issue: GitHub.
Appendix: source
Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Interactivity/BehaviorCollection.cs:44
public BehaviorCollection Clone()
{
var clone = new BehaviorCollection();
foreach (var behavior in Items)
{
clone.Add((Behavior)behavior.Clone());
}
return clone;
}
public void Attach([NotNull] DependencyObject dependencyObject)
{
if (dependencyObject == null) throw new ArgumentNullException(nameof(dependencyObject));
// Aleady attached
if (ReferenceEquals(AssociatedObject, dependencyObject))
return;
if (AssociatedObject != null)
throw new InvalidOperationException("This BehaviorCollection has already been attached to a dependency object.");
AssociatedObject = dependencyObject;
var behaviors = Microsoft.Xaml.Behaviors.Interaction.GetBehaviors(dependencyObject);
foreach (var behavior in this)
{
behaviors.Add(behavior);
}
}
public void Detach()
{
if (AssociatedObject != null)
{
var behaviors = Microsoft.Xaml.Behaviors.Interaction.GetBehaviors(AssociatedObject);
foreach (var behavior in this)
{
behaviors.Remove(behavior);
}View on GitHub (pinned to 96fad776d2)