HandyOrg/HandyControl · error · InvalidOperationException
ExceptionStringTable.DuplicateItemInCollectionExceptionMessa…
Error message
ExceptionStringTable.DuplicateItemInCollectionExceptionMessage
What it means
AttachableCollection<T>.VerifyAdd guards that each item is added at most once and is non-null. On CollectionChanged it verifies additions; if the item already exists in the internal _snapshot it throws InvalidOperationException with a localized message from ExceptionStringTable naming the duplicate type and collection type.
Solutions
- Check Contains before adding: if (!coll.Contains(item)) coll.Add(item)
- Create a new behavior instance per target element instead of sharing one instance
- Use TryGetValue/deduplication logic when wiring behaviors programmatically
Example fix
// before var b = new MyBehavior(); Interaction.GetBehaviors(el1).Add(b); Interaction.GetBehaviors(el2).Add(b); // duplicate — throws // after Interaction.GetBehaviors(el1).Add(new MyBehavior()); Interaction.GetBehaviors(el2).Add(new MyBehavior());
Defensive patterns
Strategy: validation
Validate before calling
if (item == null) throw new ArgumentNullException(nameof(item)); if (!behaviors.Contains(item)) behaviors.Add(item);
Type guard
bool CanAdd<T>(ICollection<T> coll, T item) => item != null && !coll.Contains(item);
Try / catch
try { behaviors.Add(behavior); } catch (InvalidOperationException ex) when (ex.Message.Contains("DuplicateItemInCollectionExceptionMessage") || ex.Message.Contains("already")) { /* item already attached — reuse or skip */ } Prevention
- Never share a single Behavior/Trigger instance across multiple elements
- Create a fresh instance per attach target
- Deduplicate programmatic adds with a Contains check
- Be careful with x:Shared="false" resources that can yield repeated adds
When it happens
Trigger: Adding the same behavior/trigger instance (e.g. a Behavior<T>) to a collection — or to two attachable collections — where it is already present; also triggered indirectly by re-parenting an element that carries an already-attached behavior.
Common situations: Reusing a single Behavior instance across multiple elements or multiple Interaction.GetBehaviors() collections; XAML resource shared via x:Shared="false" duplicates or style setters re-adding the same instance; adding during collection-change reentrancy.
Related errors
- ExceptionStringTable.CannotHostBehaviorMultipleTimesExceptio…
- ExceptionStringTable.TypeConstraintViolatedExceptionMessage
- ExceptionStringTable.DefaultTriggerAttributeInvalidTriggerTy…
- ExceptionStringTable.RetargetedTypeConstraintViolatedExcepti…
- ExceptionStringTable.EventTriggerCannotFindEventNameExceptio…
AI-assisted analysis of HandyOrg/HandyControl@2c0875ebd6 (2026-09-14).
Data as JSON: /api/errors/eebde4331b9802ae.
Report an issue: GitHub.
Appendix: source
Thrown at src/Shared/System.Windows.Interactivity/AttachableCollection`1.cs:69
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
}
protected abstract void OnAttached();
protected abstract void OnDetaching();
internal abstract void ItemAdded(T item);
internal abstract void ItemRemoved(T item);
private void VerifyAdd(T item)
{
if (item == null) throw new ArgumentNullException(nameof(item));
if (_snapshot.Contains(item))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.DuplicateItemInCollectionExceptionMessage, new object[]
{
typeof(T).Name,
GetType().Name
}));
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
var enumerator1 = e.NewItems.GetEnumerator();
try
{
while (enumerator1.MoveNext())
{
var current = (T) enumerator1.Current;View on GitHub (pinned to 2c0875ebd6)