Skip to content

ArgumentException when using several converters with same TFrom type #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Hellfim opened this issue Jun 3, 2023 · 0 comments · Fixed by #24
Closed

ArgumentException when using several converters with same TFrom type #23

Hellfim opened this issue Jun 3, 2023 · 0 comments · Fixed by #24
Assignees
Labels
bug Something isn't working

Comments

@Hellfim
Copy link
Contributor

Hellfim commented Jun 3, 2023

Suppose you have following files:

MyView.uxml
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <ui:VisualElement style="flex-grow: 1; align-items: center; justify-content: center;">
        <MyCustomControl binding-bool-path="ResultProperty, ResultToBooleanConverter" text="Label" style="font-size: 130px;" />
        <MyCustomControl binding-bool-path="ResultProperty, InvertedResultToBooleanConverter" text="Label Inv" style="font-size: 130px;" />
    </ui:VisualElement>
</ui:UXML>
Result.cs
    public enum Result
    {
        Defeat,
        Victory,
    }
ResultToBooleanConverter.cs
    public class ResultToBooleanConverter : PropertyValueConverter<Result, Boolean>
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override Boolean Convert(Result value)
        {
            return value == Result.Victory;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override Result ConvertBack(Boolean value)
        {
            return value ? Result.Victory : Result.Defeat;
        }
    }
InvertedResultToBooleanConverter.cs
    public class InvertedResultToBooleanConverter : PropertyValueConverter<Result, Boolean>
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override Boolean Convert(Result value)
        {
            return value != Result.Victory;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override Result ConvertBack(Boolean value)
        {
            return value ? Result.Defeat : Result.Victory;
        }
    }
MyView.cs
    public class MyView : DocumentView<MyViewModel>
    {
        protected override IValueConverter[] GetValueConverters()
        {
            return new IValueConverter[] { new ResultToBooleanConverter(), new InvertedResultToBooleanConverter() };
        }
    }
MyViewModel.cs
    public class MyViewModel : IBindingContext
    {
        public IProperty<Result> ResultProperty { get; }

        public TestCaseViewModel()
        {
            ResultProperty = new Property<Result>(Result.Victory);
        }
    }
MyCustomControl.cs
    [UxmlElement]
    public partial class MyCustomControl : VisualElement, IBindableElement
    {
        [UxmlAttribute("binding-bool-path")]
        private String _bindingBoolPath { get; set; }
        private PropertyBindingData _isDisplayPathBindingData;

        private IReadOnlyProperty<Boolean> _boolProperty;

        public void SetBindingContext(IBindingContext context, IObjectProvider objectProvider)
        {
            if (String.IsNullOrWhiteSpace(_bindingBoolPath))
            {
                return;
            }

            _isDisplayPathBindingData ??= _bindingBoolPath.ToPropertyBindingData();

            _boolProperty = objectProvider.RentProperty<Boolean>(context, _isDisplayPathBindingData);
            _boolProperty.ValueChanged += OnBoolPropertyValueChanged;

            UpdateControlValue(_boolProperty.Value);
        }

        public void ResetBindingContext(IObjectProvider objectProvider)
        {
            UpdateControlValue(false);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected virtual void UpdateControlValue(Boolean newValue)
        {
            Debug.Log($"Value changed to: {newValue}");
        }

        private void OnBoolPropertyValueChanged(Object sender, Boolean flag)
        {
            UpdateControlValue(flag);
        }
    }

This configuration produces following exception

Exception
ArgumentException: An item with the same key has already been added. Key: -1662977815
System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <835c05e113da4a69bb097e93a682f230>:0)
System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <835c05e113da4a69bb097e93a682f230>:0)
UnityMvvmToolkit.Core.Internal.ObjectHandlers.ValueConverterHandler.RegisterValueConverter (UnityMvvmToolkit.Core.Interfaces.IValueConverter valueConverter) (at D:/Projects/Bin/UnityMvvmToolkit/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ValueConverterHandler.cs:74)
UnityMvvmToolkit.Core.Internal.ObjectHandlers.ValueConverterHandler.RegisterValueConverters (UnityMvvmToolkit.Core.Interfaces.IValueConverter[] converters) (at D:/Projects/Bin/UnityMvvmToolkit/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ValueConverterHandler.cs:43)
UnityMvvmToolkit.Core.Internal.ObjectHandlers.ValueConverterHandler..ctor (UnityMvvmToolkit.Core.Interfaces.IValueConverter[] valueConverters) (at D:/Projects/Bin/UnityMvvmToolkit/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ValueConverterHandler.cs:18)
UnityMvvmToolkit.Core.BindingContextObjectProvider..ctor (UnityMvvmToolkit.Core.Interfaces.IValueConverter[] converters, System.Collections.Generic.IReadOnlyDictionary`2[TKey,TValue] collectionItemTemplates) (at D:/Projects/Bin/UnityMvvmToolkit/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/BindingContextObjectProvider.cs:26)
UnityMvvmToolkit.Common.MonoBehaviourView`1[TBindingContext].GetObjectProvider () (at D:/Projects/Bin/UnityMvvmToolkit/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Common/MonoBehaviourView.cs:75)
UnityMvvmToolkit.Common.MonoBehaviourView`1[TBindingContext].SetBindingContext () (at D:/Projects/Bin/UnityMvvmToolkit/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Common/MonoBehaviourView.cs:99)
UnityMvvmToolkit.Common.MonoBehaviourView`1[TBindingContext].Awake () (at D:/Projects/Bin/UnityMvvmToolkit/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Common/MonoBehaviourView.cs:28)
@Hellfim Hellfim added the bug Something isn't working label Jun 3, 2023
@ChebanovDD ChebanovDD mentioned this issue Jun 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants