From 98ce69acbd92f2eeb27e7f3861b42362b07f40aa Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Sun, 4 Jun 2023 18:08:31 +0800 Subject: [PATCH 1/9] Add ValueConverterHandler constructor test. --- .../TestValueConverters/IntToBoolConverter.cs | 16 ++++++++++++++++ .../InvertedIntToBoolConverter.cs | 16 ++++++++++++++++ .../ValueConverterHandlerTests.cs | 18 ++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/IntToBoolConverter.cs create mode 100644 tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/InvertedIntToBoolConverter.cs diff --git a/tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/IntToBoolConverter.cs b/tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/IntToBoolConverter.cs new file mode 100644 index 0000000..ab6c85a --- /dev/null +++ b/tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/IntToBoolConverter.cs @@ -0,0 +1,16 @@ +using UnityMvvmToolkit.Core.Converters.PropertyValueConverters; + +namespace UnityMvvmToolkit.Test.Unit.TestValueConverters; + +public class IntToBoolConverter : PropertyValueConverter +{ + public override bool Convert(int value) + { + return value == 1; + } + + public override int ConvertBack(bool value) + { + return value ? 1 : 0; + } +} \ No newline at end of file diff --git a/tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/InvertedIntToBoolConverter.cs b/tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/InvertedIntToBoolConverter.cs new file mode 100644 index 0000000..b69b189 --- /dev/null +++ b/tests/UnityMvvmToolkit.Test.Unit/TestValueConverters/InvertedIntToBoolConverter.cs @@ -0,0 +1,16 @@ +using UnityMvvmToolkit.Core.Converters.PropertyValueConverters; + +namespace UnityMvvmToolkit.Test.Unit.TestValueConverters; + +public class InvertedIntToBoolConverter : PropertyValueConverter +{ + public override bool Convert(int value) + { + return value == 0; + } + + public override int ConvertBack(bool value) + { + return value ? 0 : 1; + } +} \ No newline at end of file diff --git a/tests/UnityMvvmToolkit.Test.Unit/ValueConverterHandlerTests.cs b/tests/UnityMvvmToolkit.Test.Unit/ValueConverterHandlerTests.cs index 5761cf5..8628df4 100644 --- a/tests/UnityMvvmToolkit.Test.Unit/ValueConverterHandlerTests.cs +++ b/tests/UnityMvvmToolkit.Test.Unit/ValueConverterHandlerTests.cs @@ -5,12 +5,30 @@ using UnityMvvmToolkit.Core.Interfaces; using UnityMvvmToolkit.Core.Internal.Helpers; using UnityMvvmToolkit.Core.Internal.ObjectHandlers; +using UnityMvvmToolkit.Test.Unit.TestValueConverters; namespace UnityMvvmToolkit.Test.Unit; [SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")] public class ValueConverterHandlerTests { + [Fact] + public void RegisterValueConverters_ShouldNotThrow_WhenConvertersHaveTheSameTypes() + { + // Arrange + var valueConverters = new IValueConverter[] + { + new IntToBoolConverter(), + new InvertedIntToBoolConverter() + }; + + // Assert + FluentActions + .Invoking(() => new ValueConverterHandler(valueConverters)) + .Should() + .NotThrow(); + } + [Theory] [MemberData(nameof(PropertyConverterDataSets))] [MemberData(nameof(ParameterConverterDataSets))] From 3097fa1d6149b337762dad365f0c18e7dc6562cc Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 10:07:09 +0800 Subject: [PATCH 2/9] Resolve #27. Fix binding to field commands. --- .../BindingContextObjectProvider.cs | 10 +--- .../ObjectHandlers/ObjectWrapperHandler.cs | 48 ++++++++++++------- .../Core/BindingContextObjectProvider.cs | 10 +--- .../ObjectHandlers/ObjectWrapperHandler.cs | 48 ++++++++++++------- 4 files changed, 64 insertions(+), 52 deletions(-) diff --git a/src/UnityMvvmToolkit.Core/BindingContextObjectProvider.cs b/src/UnityMvvmToolkit.Core/BindingContextObjectProvider.cs index ed4c326..1694cc1 100644 --- a/src/UnityMvvmToolkit.Core/BindingContextObjectProvider.cs +++ b/src/UnityMvvmToolkit.Core/BindingContextObjectProvider.cs @@ -114,15 +114,7 @@ public TCommand GetCommand(IBindingContext context, string propertyNam throw new InvalidOperationException($"Command '{propertyName}' not found."); } - var propertyInfo = (PropertyInfo) memberInfo; - - if (typeof(TCommand).IsAssignableFrom(propertyInfo.PropertyType)) - { - return (TCommand) propertyInfo.GetValue(context); - } - - throw new InvalidCastException( - $"Can not cast the {propertyInfo.PropertyType} command to the {typeof(TCommand)} command."); + return _objectWrapperHandler.GetCommand(context, memberInfo); } public IBaseCommand RentCommandWrapper(IBindingContext context, CommandBindingData bindingData) diff --git a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index b525cce..217f703 100644 --- a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -53,12 +53,14 @@ public void CreateValueConverterInstances(int capacity, WarmupType warmupType public TProperty GetProperty(IBindingContext context, BindingData bindingData, MemberInfo memberInfo) { + var property = GetMemberValue(context, memberInfo, out var propertyType); + var targetType = typeof(TValueType); - var contextProperty = GetMemberValue(context, memberInfo, out var sourceType); + var sourceType = propertyType.GenericTypeArguments[0]; - if (targetType == sourceType) + if (targetType == sourceType && string.IsNullOrWhiteSpace(bindingData.ConverterName)) { - return (TProperty) contextProperty; + return (TProperty) property; } var converterId = @@ -71,7 +73,7 @@ public TProperty GetProperty(IBindingContext context, Bin return (TProperty) propertyWrappers .Dequeue() .AsPropertyWrapper() - .SetProperty(contextProperty); + .SetProperty(property); } } else @@ -88,24 +90,35 @@ public TProperty GetProperty(IBindingContext context, Bin var args = new object[] { valueConverter }; var wrapperType = typeof(PropertyWrapper<,>).MakeGenericType(sourceType, targetType); - return (TProperty) ObjectWrapperHelper.CreatePropertyWrapper(wrapperType, args, converterId, - contextProperty); + return (TProperty) ObjectWrapperHelper.CreatePropertyWrapper(wrapperType, args, converterId, property); + } + + public TCommand GetCommand(IBindingContext context, MemberInfo memberInfo) + { + var command = GetMemberValue(context, memberInfo, out var commandType); + + if (typeof(TCommand).IsAssignableFrom(commandType)) + { + return (TCommand) command; + } + + throw new InvalidCastException( + $"Can not cast the '{commandType}' command to the '{typeof(TCommand)}' command."); } public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBindingData bindingData, MemberInfo memberInfo) { - var propertyInfo = (PropertyInfo) memberInfo; - var propertyType = propertyInfo.PropertyType; + var command = GetMemberValue(context, memberInfo, out var commandType); - if (propertyType.IsGenericType == false || - propertyType.GetInterface(nameof(IBaseCommand)) == null) + if (commandType.IsGenericType == false || + commandType.GetInterface(nameof(IBaseCommand)) == null) { throw new InvalidCastException( - $"Can not cast the {propertyType} command to the {typeof(ICommand<>)} command."); + $"Can not cast the '{commandType}' command to the '{typeof(ICommand<>)}' command."); } - var commandValueType = propertyType.GenericTypeArguments[0]; + var commandValueType = commandType.GenericTypeArguments[0]; var commandId = HashCodeHelper.GetCommandWrapperId(context.GetType(), commandValueType, bindingData.PropertyName); @@ -126,7 +139,7 @@ public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBinding return commandWrappers .Dequeue() .AsCommandWrapper() - .SetCommand(commandId, propertyInfo.GetValue(context)) + .SetCommand(commandId, command) .RegisterParameter(bindingData.ElementId, bindingData.ParameterValue); } } @@ -143,7 +156,6 @@ public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBinding var args = new object[] { valueConverter }; var wrapperType = typeof(CommandWrapper<>).MakeGenericType(commandValueType); - var command = propertyInfo.GetValue(context); commandWrapper = ObjectWrapperHelper .CreateCommandWrapper(wrapperType, args, converterId, commandId, command) @@ -297,24 +309,26 @@ private void ReturnWrapper(IObjectWrapper wrapper) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private object GetMemberValue(IBindingContext context, MemberInfo memberInfo, out Type memberValueType) + private static object GetMemberValue(IBindingContext context, MemberInfo memberInfo, out Type memberType) { switch (memberInfo.MemberType) { case MemberTypes.Field: { var fieldInfo = (FieldInfo) memberInfo; - memberValueType = fieldInfo.FieldType.GenericTypeArguments[0]; + memberType = fieldInfo.FieldType; return fieldInfo.GetValue(context); } + case MemberTypes.Property: { var propertyInfo = (PropertyInfo) memberInfo; - memberValueType = propertyInfo.PropertyType.GenericTypeArguments[0]; + memberType = propertyInfo.PropertyType; return propertyInfo.GetValue(context); } + default: throw new ArgumentOutOfRangeException(); } diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/BindingContextObjectProvider.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/BindingContextObjectProvider.cs index ed4c326..1694cc1 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/BindingContextObjectProvider.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/BindingContextObjectProvider.cs @@ -114,15 +114,7 @@ public TCommand GetCommand(IBindingContext context, string propertyNam throw new InvalidOperationException($"Command '{propertyName}' not found."); } - var propertyInfo = (PropertyInfo) memberInfo; - - if (typeof(TCommand).IsAssignableFrom(propertyInfo.PropertyType)) - { - return (TCommand) propertyInfo.GetValue(context); - } - - throw new InvalidCastException( - $"Can not cast the {propertyInfo.PropertyType} command to the {typeof(TCommand)} command."); + return _objectWrapperHandler.GetCommand(context, memberInfo); } public IBaseCommand RentCommandWrapper(IBindingContext context, CommandBindingData bindingData) diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index b525cce..217f703 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -53,12 +53,14 @@ public void CreateValueConverterInstances(int capacity, WarmupType warmupType public TProperty GetProperty(IBindingContext context, BindingData bindingData, MemberInfo memberInfo) { + var property = GetMemberValue(context, memberInfo, out var propertyType); + var targetType = typeof(TValueType); - var contextProperty = GetMemberValue(context, memberInfo, out var sourceType); + var sourceType = propertyType.GenericTypeArguments[0]; - if (targetType == sourceType) + if (targetType == sourceType && string.IsNullOrWhiteSpace(bindingData.ConverterName)) { - return (TProperty) contextProperty; + return (TProperty) property; } var converterId = @@ -71,7 +73,7 @@ public TProperty GetProperty(IBindingContext context, Bin return (TProperty) propertyWrappers .Dequeue() .AsPropertyWrapper() - .SetProperty(contextProperty); + .SetProperty(property); } } else @@ -88,24 +90,35 @@ public TProperty GetProperty(IBindingContext context, Bin var args = new object[] { valueConverter }; var wrapperType = typeof(PropertyWrapper<,>).MakeGenericType(sourceType, targetType); - return (TProperty) ObjectWrapperHelper.CreatePropertyWrapper(wrapperType, args, converterId, - contextProperty); + return (TProperty) ObjectWrapperHelper.CreatePropertyWrapper(wrapperType, args, converterId, property); + } + + public TCommand GetCommand(IBindingContext context, MemberInfo memberInfo) + { + var command = GetMemberValue(context, memberInfo, out var commandType); + + if (typeof(TCommand).IsAssignableFrom(commandType)) + { + return (TCommand) command; + } + + throw new InvalidCastException( + $"Can not cast the '{commandType}' command to the '{typeof(TCommand)}' command."); } public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBindingData bindingData, MemberInfo memberInfo) { - var propertyInfo = (PropertyInfo) memberInfo; - var propertyType = propertyInfo.PropertyType; + var command = GetMemberValue(context, memberInfo, out var commandType); - if (propertyType.IsGenericType == false || - propertyType.GetInterface(nameof(IBaseCommand)) == null) + if (commandType.IsGenericType == false || + commandType.GetInterface(nameof(IBaseCommand)) == null) { throw new InvalidCastException( - $"Can not cast the {propertyType} command to the {typeof(ICommand<>)} command."); + $"Can not cast the '{commandType}' command to the '{typeof(ICommand<>)}' command."); } - var commandValueType = propertyType.GenericTypeArguments[0]; + var commandValueType = commandType.GenericTypeArguments[0]; var commandId = HashCodeHelper.GetCommandWrapperId(context.GetType(), commandValueType, bindingData.PropertyName); @@ -126,7 +139,7 @@ public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBinding return commandWrappers .Dequeue() .AsCommandWrapper() - .SetCommand(commandId, propertyInfo.GetValue(context)) + .SetCommand(commandId, command) .RegisterParameter(bindingData.ElementId, bindingData.ParameterValue); } } @@ -143,7 +156,6 @@ public ICommandWrapper GetCommandWrapper(IBindingContext context, CommandBinding var args = new object[] { valueConverter }; var wrapperType = typeof(CommandWrapper<>).MakeGenericType(commandValueType); - var command = propertyInfo.GetValue(context); commandWrapper = ObjectWrapperHelper .CreateCommandWrapper(wrapperType, args, converterId, commandId, command) @@ -297,24 +309,26 @@ private void ReturnWrapper(IObjectWrapper wrapper) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private object GetMemberValue(IBindingContext context, MemberInfo memberInfo, out Type memberValueType) + private static object GetMemberValue(IBindingContext context, MemberInfo memberInfo, out Type memberType) { switch (memberInfo.MemberType) { case MemberTypes.Field: { var fieldInfo = (FieldInfo) memberInfo; - memberValueType = fieldInfo.FieldType.GenericTypeArguments[0]; + memberType = fieldInfo.FieldType; return fieldInfo.GetValue(context); } + case MemberTypes.Property: { var propertyInfo = (PropertyInfo) memberInfo; - memberValueType = propertyInfo.PropertyType.GenericTypeArguments[0]; + memberType = propertyInfo.PropertyType; return propertyInfo.GetValue(context); } + default: throw new ArgumentOutOfRangeException(); } From 940c1402f2066db755a90fd890870a3bf3380c68 Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 10:12:12 +0800 Subject: [PATCH 3/9] Revert converter check. --- .../Internal/ObjectHandlers/ObjectWrapperHandler.cs | 2 +- .../Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index 217f703..b3ec59d 100644 --- a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -58,7 +58,7 @@ public TProperty GetProperty(IBindingContext context, Bin var targetType = typeof(TValueType); var sourceType = propertyType.GenericTypeArguments[0]; - if (targetType == sourceType && string.IsNullOrWhiteSpace(bindingData.ConverterName)) + if (targetType == sourceType) { return (TProperty) property; } diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index 217f703..b3ec59d 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -58,7 +58,7 @@ public TProperty GetProperty(IBindingContext context, Bin var targetType = typeof(TValueType); var sourceType = propertyType.GenericTypeArguments[0]; - if (targetType == sourceType && string.IsNullOrWhiteSpace(bindingData.ConverterName)) + if (targetType == sourceType) { return (TProperty) property; } From d0775f5add50b45d7341836901d0e0be9336e94b Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 10:28:42 +0800 Subject: [PATCH 4/9] Add field command tests. --- .../BindingContextObjectProviderTests.cs | 24 +++++++++++-------- .../TestBindingContext/MyBindingContext.cs | 2 ++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs b/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs index 143767d..869b0b3 100644 --- a/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs +++ b/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs @@ -391,17 +391,18 @@ public void GetCommand_ShouldReturnCommand_WhenDataIsValid() var objectProvider = new BindingContextObjectProvider(Array.Empty()); var bindingContext = new MyBindingContext(); - ICommand incrementCommand; - ICommand decrementCommand; - // Act - incrementCommand = - objectProvider.GetCommand(bindingContext, nameof(MyBindingContext.IncrementCommand)); + var fieldCommand = objectProvider + .GetCommand(bindingContext, nameof(MyBindingContext.FieldCommand)); + + var incrementCommand = objectProvider + .GetCommand(bindingContext, nameof(MyBindingContext.IncrementCommand)); - decrementCommand = - objectProvider.GetCommand(bindingContext, nameof(MyBindingContext.DecrementCommand)); + var decrementCommand = objectProvider + .GetCommand(bindingContext, nameof(MyBindingContext.DecrementCommand)); // Assert + fieldCommand.Should().NotBeNull().And.BeAssignableTo(); incrementCommand.Should().NotBeNull().And.BeAssignableTo(); decrementCommand.Should().NotBeNull().And.BeAssignableTo(); } @@ -452,7 +453,7 @@ public void GetCommand_ShouldThrow_WhenCommandTypeIsNotAssignableFromPropertyTyp .Should() .Throw() .WithMessage( - $"Can not cast the {typeof(IReadOnlyProperty)} command to the {typeof(ICommand)} command."); + $"Can not cast the '{typeof(IReadOnlyProperty)}' command to the '{typeof(ICommand)}' command."); } [Fact] @@ -460,6 +461,7 @@ public void RentCommandWrapper_ShouldReturnCommand_WhenDataIsValid() { // Arrange const string commandName = nameof(MyBindingContext.SetValueCommand); + const string fieldCommandName = nameof(MyBindingContext.SetValueFieldCommand); var objectProvider = new BindingContextObjectProvider(new IValueConverter[] { @@ -468,14 +470,16 @@ public void RentCommandWrapper_ShouldReturnCommand_WhenDataIsValid() var bindingContext = new MyBindingContext(); - IBaseCommand setValueCommand; var setValueCommandBindingData = $"{commandName}, 5".ToCommandBindingData(0); + var setValueFieldCommandBindingData = $"{fieldCommandName}, 5".ToCommandBindingData(0); // Act - setValueCommand = objectProvider.RentCommandWrapper(bindingContext, setValueCommandBindingData); + var setValueCommand = objectProvider.RentCommandWrapper(bindingContext, setValueCommandBindingData); + var setValueFieldCommand = objectProvider.RentCommandWrapper(bindingContext, setValueFieldCommandBindingData); // Assert setValueCommand.Should().NotBeNull(); + setValueFieldCommand.Should().NotBeNull(); } [Fact] diff --git a/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs b/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs index 854fe46..6a229ac 100644 --- a/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs +++ b/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs @@ -27,6 +27,7 @@ public MyBindingContext(string title = "Title", int intValue = default) DecrementCommand = new MyCommand(() => Count--); SetValueCommand = new Command(value => Count = value); + SetValueFieldCommand = new Command(value => Count = value); } public int Count @@ -46,4 +47,5 @@ public int Count public IMyCommand DecrementCommand { get; } public ICommand SetValueCommand { get; } + public ICommand SetValueFieldCommand; } \ No newline at end of file From cd70cd0431802e3e56005a392d96b8f10b3f3fe7 Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 12:14:01 +0800 Subject: [PATCH 5/9] Resolve #28. Fix ignoring converter issue when types match. --- .../Interfaces/IProperty.T.cs | 2 +- .../Interfaces/IProperty.cs | 6 + .../ObjectHandlers/ObjectWrapperHandler.cs | 7 +- .../ReadOnlyPropertyWrapper.TSource.TValue.cs | 69 ++++++++++ .../Runtime/Core/Interfaces/IProperty.T.cs | 2 +- .../Runtime/Core/Interfaces/IProperty.cs | 6 + .../Runtime/Core/Interfaces/IProperty.cs.meta | 11 ++ .../ObjectHandlers/ObjectWrapperHandler.cs | 7 +- .../ReadOnlyPropertyWrapper.TSource.TValue.cs | 69 ++++++++++ ...OnlyPropertyWrapper.TSource.TValue.cs.meta | 11 ++ .../BindingContextObjectProviderTests.cs | 124 +++++++++++++----- .../TestBindingContext/MyBindingContext.cs | 15 +++ .../InvertBoolParamConverter.cs | 12 ++ .../InvertBoolPropConverter.cs | 16 +++ 14 files changed, 320 insertions(+), 37 deletions(-) create mode 100644 src/UnityMvvmToolkit.Core/Interfaces/IProperty.cs create mode 100644 src/UnityMvvmToolkit.Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs.meta create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs.meta create mode 100644 tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolParamConverter.cs create mode 100644 tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolPropConverter.cs diff --git a/src/UnityMvvmToolkit.Core/Interfaces/IProperty.T.cs b/src/UnityMvvmToolkit.Core/Interfaces/IProperty.T.cs index 0c6e928..44fa324 100644 --- a/src/UnityMvvmToolkit.Core/Interfaces/IProperty.T.cs +++ b/src/UnityMvvmToolkit.Core/Interfaces/IProperty.T.cs @@ -2,7 +2,7 @@ namespace UnityMvvmToolkit.Core.Interfaces { - public interface IProperty : IReadOnlyProperty + public interface IProperty : IReadOnlyProperty, IProperty { new T Value { get; set; } diff --git a/src/UnityMvvmToolkit.Core/Interfaces/IProperty.cs b/src/UnityMvvmToolkit.Core/Interfaces/IProperty.cs new file mode 100644 index 0000000..d7d1334 --- /dev/null +++ b/src/UnityMvvmToolkit.Core/Interfaces/IProperty.cs @@ -0,0 +1,6 @@ +namespace UnityMvvmToolkit.Core.Interfaces +{ + public interface IProperty + { + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index b3ec59d..5d0b24d 100644 --- a/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -58,7 +58,7 @@ public TProperty GetProperty(IBindingContext context, Bin var targetType = typeof(TValueType); var sourceType = propertyType.GenericTypeArguments[0]; - if (targetType == sourceType) + if (targetType == sourceType && string.IsNullOrWhiteSpace(bindingData.ConverterName)) { return (TProperty) property; } @@ -88,7 +88,10 @@ public TProperty GetProperty(IBindingContext context, Bin } var args = new object[] { valueConverter }; - var wrapperType = typeof(PropertyWrapper<,>).MakeGenericType(sourceType, targetType); + + var wrapperType = property is IProperty + ? typeof(PropertyWrapper<,>).MakeGenericType(sourceType, targetType) + : typeof(ReadOnlyPropertyWrapper<,>).MakeGenericType(sourceType, targetType); return (TProperty) ObjectWrapperHelper.CreatePropertyWrapper(wrapperType, args, converterId, property); } diff --git a/src/UnityMvvmToolkit.Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs b/src/UnityMvvmToolkit.Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs new file mode 100644 index 0000000..7567c85 --- /dev/null +++ b/src/UnityMvvmToolkit.Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.CompilerServices; +using UnityMvvmToolkit.Core.Attributes; +using UnityMvvmToolkit.Core.Interfaces; +using UnityMvvmToolkit.Core.Internal.Interfaces; + +namespace UnityMvvmToolkit.Core.Internal.ObjectWrappers +{ + internal sealed class ReadOnlyPropertyWrapper : IReadOnlyProperty, IPropertyWrapper + { + private readonly IPropertyValueConverter _valueConverter; + + private int _converterId; + private bool _isInitialized; + + private TValue _value; + + [Preserve] + public ReadOnlyPropertyWrapper(IPropertyValueConverter valueConverter) + { + _converterId = -1; + _valueConverter = valueConverter; + } + + public int ConverterId => _converterId; + + public TValue Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value; + } + + #pragma warning disable 67 + public event EventHandler ValueChanged; + #pragma warning restore 67 + + public IPropertyWrapper SetConverterId(int converterId) + { + if (_converterId != -1) + { + throw new InvalidOperationException("Can not change converter ID."); + } + + _converterId = converterId; + + return this; + } + + public IPropertyWrapper SetProperty(object readOnlyProperty) + { + if (_isInitialized) + { + throw new InvalidOperationException( + $"{nameof(ReadOnlyPropertyWrapper)} was not reset."); + } + + _value = _valueConverter.Convert(((IReadOnlyProperty) readOnlyProperty).Value); + _isInitialized = true; + + return this; + } + + public void Reset() + { + _value = default; + _isInitialized = false; + } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.T.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.T.cs index 0c6e928..44fa324 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.T.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.T.cs @@ -2,7 +2,7 @@ namespace UnityMvvmToolkit.Core.Interfaces { - public interface IProperty : IReadOnlyProperty + public interface IProperty : IReadOnlyProperty, IProperty { new T Value { get; set; } diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs new file mode 100644 index 0000000..d7d1334 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs @@ -0,0 +1,6 @@ +namespace UnityMvvmToolkit.Core.Interfaces +{ + public interface IProperty + { + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs.meta new file mode 100644 index 0000000..72b7b98 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Interfaces/IProperty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd5b6d3eceadc2b4cb87d500f0c8fcda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs index b3ec59d..5d0b24d 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectHandlers/ObjectWrapperHandler.cs @@ -58,7 +58,7 @@ public TProperty GetProperty(IBindingContext context, Bin var targetType = typeof(TValueType); var sourceType = propertyType.GenericTypeArguments[0]; - if (targetType == sourceType) + if (targetType == sourceType && string.IsNullOrWhiteSpace(bindingData.ConverterName)) { return (TProperty) property; } @@ -88,7 +88,10 @@ public TProperty GetProperty(IBindingContext context, Bin } var args = new object[] { valueConverter }; - var wrapperType = typeof(PropertyWrapper<,>).MakeGenericType(sourceType, targetType); + + var wrapperType = property is IProperty + ? typeof(PropertyWrapper<,>).MakeGenericType(sourceType, targetType) + : typeof(ReadOnlyPropertyWrapper<,>).MakeGenericType(sourceType, targetType); return (TProperty) ObjectWrapperHelper.CreatePropertyWrapper(wrapperType, args, converterId, property); } diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs new file mode 100644 index 0000000..7567c85 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.CompilerServices; +using UnityMvvmToolkit.Core.Attributes; +using UnityMvvmToolkit.Core.Interfaces; +using UnityMvvmToolkit.Core.Internal.Interfaces; + +namespace UnityMvvmToolkit.Core.Internal.ObjectWrappers +{ + internal sealed class ReadOnlyPropertyWrapper : IReadOnlyProperty, IPropertyWrapper + { + private readonly IPropertyValueConverter _valueConverter; + + private int _converterId; + private bool _isInitialized; + + private TValue _value; + + [Preserve] + public ReadOnlyPropertyWrapper(IPropertyValueConverter valueConverter) + { + _converterId = -1; + _valueConverter = valueConverter; + } + + public int ConverterId => _converterId; + + public TValue Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value; + } + + #pragma warning disable 67 + public event EventHandler ValueChanged; + #pragma warning restore 67 + + public IPropertyWrapper SetConverterId(int converterId) + { + if (_converterId != -1) + { + throw new InvalidOperationException("Can not change converter ID."); + } + + _converterId = converterId; + + return this; + } + + public IPropertyWrapper SetProperty(object readOnlyProperty) + { + if (_isInitialized) + { + throw new InvalidOperationException( + $"{nameof(ReadOnlyPropertyWrapper)} was not reset."); + } + + _value = _valueConverter.Convert(((IReadOnlyProperty) readOnlyProperty).Value); + _isInitialized = true; + + return this; + } + + public void Reset() + { + _value = default; + _isInitialized = false; + } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs.meta new file mode 100644 index 0000000..751c8dd --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/ObjectWrappers/ReadOnlyPropertyWrapper.TSource.TValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f4e5e968dba769c4d95fb8583b99fa9d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs b/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs index 869b0b3..c24a9c3 100644 --- a/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs +++ b/tests/UnityMvvmToolkit.Test.Integration/BindingContextObjectProviderTests.cs @@ -8,6 +8,7 @@ using UnityMvvmToolkit.Core.Internal.ObjectHandlers; using UnityMvvmToolkit.Core.Internal.ObjectWrappers; using UnityMvvmToolkit.Test.Integration.TestBindingContext; +using UnityMvvmToolkit.Test.Integration.TestValueConverters; using UnityMvvmToolkit.Test.Unit.TestBindingContext; namespace UnityMvvmToolkit.Test.Integration; @@ -160,11 +161,10 @@ public void RentProperty_ShouldReturnProperty_WhenDataIsValid() Count = countValue, }; - IProperty countProperty; var countPropertyBindingData = nameof(MyBindingContext.Count).ToPropertyBindingData(); // Act - countProperty = objectProvider.RentProperty(bindingContext, countPropertyBindingData); + var countProperty = objectProvider.RentProperty(bindingContext, countPropertyBindingData); // Assert countProperty @@ -179,7 +179,7 @@ public void RentProperty_ShouldReturnProperty_WhenDataIsValid() } [Fact] - public void RentPropertyWithConverter_ShouldReturnProperty_WhenDataIsValid() + public void RentProperty_ShouldReturnProperty_WhenConverterIsSet() { // Arrange const int countValue = 69; @@ -194,11 +194,10 @@ public void RentPropertyWithConverter_ShouldReturnProperty_WhenDataIsValid() Count = countValue, }; - IProperty countProperty; var countPropertyBindingData = nameof(MyBindingContext.Count).ToPropertyBindingData(); // Act - countProperty = objectProvider.RentProperty(bindingContext, countPropertyBindingData); + var countProperty = objectProvider.RentProperty(bindingContext, countPropertyBindingData); // Assert countProperty @@ -213,7 +212,37 @@ public void RentPropertyWithConverter_ShouldReturnProperty_WhenDataIsValid() } [Fact] - public void RentPropertyWithConverter_ShouldReturnReadOnlyProperty_WhenPropertyInstanceIsNotReadOnly() + public void RentProperty_ShouldConvertPropertyValue_WhenSourceAndTargetTypesMatch() + { + // Arrange + const bool resultBoolValue = true; + + var objectProvider = new BindingContextObjectProvider(new IValueConverter[] + { + new InvertBoolPropConverter() + }); + + var bindingContext = new MyBindingContext(); + + var boolPropertyBindingData = $"BoolProperty, {nameof(InvertBoolPropConverter)}".ToPropertyBindingData(); + + // Act + var boolProperty = objectProvider.RentProperty(bindingContext, boolPropertyBindingData); + + // Assert + boolProperty + .Should() + .NotBeNull() + .And + .BeAssignableTo>() + .And + .BeAssignableTo>(); + + boolProperty.Value.Should().Be(resultBoolValue); + } + + [Fact] + public void RentProperty_ShouldReturnReadOnlyProperty_WhenPropertyInstanceIsNotReadOnly() { // Arrange const int intValue = 25; @@ -225,11 +254,10 @@ public void RentPropertyWithConverter_ShouldReturnReadOnlyProperty_WhenPropertyI var bindingContext = new MyBindingContext(intValue: intValue); - IReadOnlyProperty intProperty; var intPropertyBindingData = nameof(MyBindingContext.IntReadOnlyProperty).ToPropertyBindingData(); // Act - intProperty = objectProvider.RentProperty(bindingContext, intPropertyBindingData); + IReadOnlyProperty intProperty = objectProvider.RentProperty(bindingContext, intPropertyBindingData); // Assert intProperty @@ -300,27 +328,7 @@ public void RentProperty_ShouldThrow_WhenBindingDataIsNotValid() } [Fact] - public void RentPropertyWithConverter_ShouldThrow_WhenPropertyIsReadOnly() - { - // Arrange - var objectProvider = new BindingContextObjectProvider(new IValueConverter[] - { - new IntToStrConverter() - }); - - var bindingContext = new MyBindingContext(); - - var intValueBindingData = nameof(MyBindingContext.IntReadOnlyValue).ToPropertyBindingData(); - - // Assert - objectProvider - .Invoking(sut => sut.RentReadOnlyProperty(bindingContext, intValueBindingData)) - .Should() - .Throw(); - } - - [Fact] - public void RentPropertyWithConverter_ShouldThrow_WhenConverterIsNotSet() + public void RentProperty_ShouldThrow_WhenConverterIsNotSet() { // Arrange var objectProvider = new BindingContextObjectProvider(Array.Empty()); @@ -345,11 +353,10 @@ public void RentReadOnlyProperty_ShouldReturnProperty_WhenDataIsValid() var objectProvider = new BindingContextObjectProvider(Array.Empty()); var bindingContext = new MyBindingContext(titleValue); - IReadOnlyProperty titleProperty; var titlePropertyBindingData = nameof(MyBindingContext.Title).ToPropertyBindingData(); // Act - titleProperty = objectProvider.RentReadOnlyProperty(bindingContext, titlePropertyBindingData); + var titleProperty = objectProvider.RentReadOnlyProperty(bindingContext, titlePropertyBindingData); // Assert titleProperty @@ -363,6 +370,37 @@ public void RentReadOnlyProperty_ShouldReturnProperty_WhenDataIsValid() titleProperty.Value.Should().Be(titleValue); } + [Fact] + public void RentReadOnlyProperty_ShouldConvertPropertyValue_WhenSourceAndTargetTypesMatch() + { + // Arrange + const bool resultBoolValue = true; + + var objectProvider = new BindingContextObjectProvider(new IValueConverter[] + { + new InvertBoolPropConverter() + }); + + var bindingContext = new MyBindingContext(); + + var boolPropertyBindingData = + $"BoolReadOnlyProperty, {nameof(InvertBoolPropConverter)}".ToPropertyBindingData(); + + // Act + var boolProperty = objectProvider.RentReadOnlyProperty(bindingContext, boolPropertyBindingData); + + // Assert + boolProperty + .Should() + .NotBeNull() + .And + .NotBeAssignableTo>() + .And + .BeAssignableTo>(); + + boolProperty.Value.Should().Be(resultBoolValue); + } + [Fact] public void RentReadOnlyProperty_ShouldThrow_WhenBindingDataIsNotValid() { @@ -482,6 +520,30 @@ public void RentCommandWrapper_ShouldReturnCommand_WhenDataIsValid() setValueFieldCommand.Should().NotBeNull(); } + [Fact] + public void RentCommandWrapper_ShouldReturnCommand_WithInvertedParameterValue() + { + // Arrange + const bool resultBoolValue = true; + + var objectProvider = new BindingContextObjectProvider(new IValueConverter[] + { + new InvertBoolParamConverter() + }); + + var bindingContext = new MyBindingContext(); + + var boolCommandBindingData = + $"BoolCommand, {bool.FalseString}, {nameof(InvertBoolParamConverter)}".ToCommandBindingData(0); + + // Act + var boolCommand = objectProvider.RentCommandWrapper(bindingContext, boolCommandBindingData); + boolCommand.Execute(0); + + // Assert + bindingContext.BoolValue.Should().Be(resultBoolValue); + } + [Fact] public void RentCommandWrapper_ShouldThrow_WhenParameterIsNull() { diff --git a/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs b/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs index 6a229ac..ac124ca 100644 --- a/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs +++ b/tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs @@ -4,6 +4,8 @@ using UnityMvvmToolkit.Test.Unit.TestCommands; // ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Local +// ReSharper disable NotAccessedField.Local // ReSharper disable UnusedAutoPropertyAccessor.Global namespace UnityMvvmToolkit.Test.Integration.TestBindingContext; @@ -16,8 +18,19 @@ public class MyBindingContext : IBindingContext [Observable(nameof(IntReadOnlyValue))] private readonly IReadOnlyProperty m_intReadOnlyValue = new ReadOnlyProperty(69); + [Observable] + private readonly IProperty _boolProperty = new Property(false); + + [Observable] + private readonly IReadOnlyProperty _boolReadOnlyProperty = new ReadOnlyProperty(false); + + [Observable] + private readonly ICommand _boolCommand; + public MyBindingContext(string title = "Title", int intValue = default) { + _boolCommand = new Command(value => BoolValue = value); + Title = new ReadOnlyProperty(title); IntReadOnlyProperty = new Property(intValue); @@ -36,6 +49,8 @@ public int Count set => _count.Value = value; } + public bool BoolValue { get; private set; } + public int IntReadOnlyValue => m_intReadOnlyValue.Value; public IReadOnlyProperty Title { get; } diff --git a/tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolParamConverter.cs b/tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolParamConverter.cs new file mode 100644 index 0000000..72ae1c2 --- /dev/null +++ b/tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolParamConverter.cs @@ -0,0 +1,12 @@ +using UnityMvvmToolkit.Core.Converters.ParameterValueConverters; + +namespace UnityMvvmToolkit.Test.Integration.TestValueConverters; + +public class InvertBoolParamConverter : ParameterValueConverter +{ + public override bool Convert(string parameter) + { + bool.TryParse(parameter, out var result); + return !result; + } +} \ No newline at end of file diff --git a/tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolPropConverter.cs b/tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolPropConverter.cs new file mode 100644 index 0000000..660e358 --- /dev/null +++ b/tests/UnityMvvmToolkit.Test.Integration/TestValueConverters/InvertBoolPropConverter.cs @@ -0,0 +1,16 @@ +using UnityMvvmToolkit.Core.Converters.PropertyValueConverters; + +namespace UnityMvvmToolkit.Test.Integration.TestValueConverters; + +public class InvertBoolPropConverter : PropertyValueConverter +{ + public override bool Convert(bool value) + { + return !value; + } + + public override bool ConvertBack(bool value) + { + throw new NotImplementedException(); + } +} \ No newline at end of file From ccba7a5916cdaa301558be0224e68c2bd401c98d Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 12:16:24 +0800 Subject: [PATCH 6/9] Restore pragma warning. --- .../Runtime/UITK/BindableUIElements/Uxmls/BaseButton.Uxml.cs | 2 +- .../UITK/BindableUIElements/Uxmls/BindableButton.Uxml.cs | 2 +- .../Runtime/UITK/BindableUIElements/Uxmls/BindableLabel.Uxml.cs | 2 +- .../UITK/BindableUIElements/Uxmls/BindableListView.T.Uxml.cs | 2 +- .../UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs | 2 +- .../UITK/BindableUIElements/Uxmls/BindableTextField.Uxml.cs | 2 +- .../BindableUIElements/Uxmls/BindingContextProvider.T.Uxml.cs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BaseButton.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BaseButton.Uxml.cs index 00de5e5..82b96cc 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BaseButton.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BaseButton.Uxml.cs @@ -12,7 +12,7 @@ partial class BaseButton // ReSharper disable once InconsistentNaming #pragma warning disable 649 [UnityEngine.SerializeField] private bool Enabled; - #pragma warning disable 649 + #pragma warning restore 649 public override void Deserialize(object visualElement) { diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableButton.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableButton.Uxml.cs index 46f9c8c..92477cd 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableButton.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableButton.Uxml.cs @@ -18,7 +18,7 @@ partial class BindableButton // ReSharper disable once InconsistentNaming #pragma warning disable 649 [UnityEngine.SerializeField] private string Command; - #pragma warning disable 649 + #pragma warning restore 649 public override object CreateInstance() => new BindableButton(); public override void Deserialize(object visualElement) diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableLabel.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableLabel.Uxml.cs index 2499a95..d63f733 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableLabel.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableLabel.Uxml.cs @@ -18,7 +18,7 @@ partial class BindableLabel // ReSharper disable once InconsistentNaming #pragma warning disable 649 [UnityEngine.SerializeField] private string BindingTextPath; - #pragma warning disable 649 + #pragma warning restore 649 public override object CreateInstance() => new BindableLabel(); public override void Deserialize(object visualElement) diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.T.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.T.Uxml.cs index 0df4d5d..231e941 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.T.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableListView.T.Uxml.cs @@ -14,7 +14,7 @@ partial class BindableListView // ReSharper disable once InconsistentNaming #pragma warning disable 649 [UnityEngine.SerializeField] private string BindingItemsSourcePath; - #pragma warning disable 649 + #pragma warning restore 649 public override void Deserialize(object visualElement) { diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs index 196598b..a1cdcac 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableScrollView.T.Uxml.cs @@ -14,7 +14,7 @@ partial class BindableScrollView // ReSharper disable once InconsistentNaming #pragma warning disable 649 [UnityEngine.SerializeField] private string BindingItemsSourcePath; - #pragma warning disable 649 + #pragma warning restore 649 public override void Deserialize(object visualElement) { diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableTextField.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableTextField.Uxml.cs index 4336cc1..0766612 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableTextField.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableTextField.Uxml.cs @@ -18,7 +18,7 @@ partial class BindableTextField // ReSharper disable once InconsistentNaming #pragma warning disable 649 [UnityEngine.SerializeField] private string BindingValuePath; - #pragma warning disable 649 + #pragma warning restore 649 public override object CreateInstance() => new BindableTextField(); public override void Deserialize(object visualElement) diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindingContextProvider.T.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindingContextProvider.T.Uxml.cs index db63760..67ef788 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindingContextProvider.T.Uxml.cs +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindingContextProvider.T.Uxml.cs @@ -14,7 +14,7 @@ partial class BindingContextProvider // ReSharper disable once InconsistentNaming #pragma warning disable 649 [UnityEngine.SerializeField] private string BindingContextPath; - #pragma warning disable 649 + #pragma warning restore 649 public override void Deserialize(object visualElement) { From 618c4fde8daf48e192640cc610d448737104967c Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 13:08:52 +0800 Subject: [PATCH 7/9] Fix ToDo list main view warnings. --- .../Assets/UI Toolkit/Styles/main-view.uss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Unity.Mvvm.ToDoList/Assets/UI Toolkit/Styles/main-view.uss b/samples/Unity.Mvvm.ToDoList/Assets/UI Toolkit/Styles/main-view.uss index 2bba720..5d1e533 100644 --- a/samples/Unity.Mvvm.ToDoList/Assets/UI Toolkit/Styles/main-view.uss +++ b/samples/Unity.Mvvm.ToDoList/Assets/UI Toolkit/Styles/main-view.uss @@ -40,8 +40,8 @@ } .add-task-button--animation { - transition-property: rotate background-color; - transition-duration: 150ms 150ms; + transition-property: rotate, background-color; + transition-duration: 150ms, 150ms; } .add-task-button__icon { From 1cad0b6a10f2c6aecaa29c2b40e06c26f2cc5361 Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 13:09:12 +0800 Subject: [PATCH 8/9] Update packages. --- samples/Unity.Mvvm.Calc/Packages/manifest.json | 4 ++-- samples/Unity.Mvvm.Calc/Packages/packages-lock.json | 4 ++-- samples/Unity.Mvvm.Counter/Packages/manifest.json | 4 ++-- samples/Unity.Mvvm.Counter/Packages/packages-lock.json | 4 ++-- samples/Unity.Mvvm.CounterLegacy/Packages/manifest.json | 4 ++-- samples/Unity.Mvvm.CounterLegacy/Packages/packages-lock.json | 4 ++-- samples/Unity.Mvvm.ToDoList/Packages/manifest.json | 4 ++-- samples/Unity.Mvvm.ToDoList/Packages/packages-lock.json | 4 ++-- src/UnityMvvmToolkit.UnityPackage/Packages/manifest.json | 2 +- src/UnityMvvmToolkit.UnityPackage/Packages/packages-lock.json | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/samples/Unity.Mvvm.Calc/Packages/manifest.json b/samples/Unity.Mvvm.Calc/Packages/manifest.json index 9991cec..1f7a79b 100644 --- a/samples/Unity.Mvvm.Calc/Packages/manifest.json +++ b/samples/Unity.Mvvm.Calc/Packages/manifest.json @@ -3,12 +3,12 @@ "com.chebanovdd.unitymvvmtoolkit": "file:../../../src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit", "com.unity.collab-proxy": "2.0.4", "com.unity.feature.2d": "1.0.0", - "com.unity.ide.rider": "3.0.21", + "com.unity.ide.rider": "3.0.22", "com.unity.ide.visualstudio": "2.0.18", "com.unity.ide.vscode": "1.2.5", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.6.4", + "com.unity.timeline": "1.6.5", "com.unity.ugui": "1.0.0", "com.unity.visualscripting": "1.8.0", "com.unity.modules.ai": "1.0.0", diff --git a/samples/Unity.Mvvm.Calc/Packages/packages-lock.json b/samples/Unity.Mvvm.Calc/Packages/packages-lock.json index 086839c..f118002 100644 --- a/samples/Unity.Mvvm.Calc/Packages/packages-lock.json +++ b/samples/Unity.Mvvm.Calc/Packages/packages-lock.json @@ -129,7 +129,7 @@ } }, "com.unity.ide.rider": { - "version": "3.0.21", + "version": "3.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -181,7 +181,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.6.4", + "version": "1.6.5", "depth": 0, "source": "registry", "dependencies": { diff --git a/samples/Unity.Mvvm.Counter/Packages/manifest.json b/samples/Unity.Mvvm.Counter/Packages/manifest.json index 0547412..ec969a9 100644 --- a/samples/Unity.Mvvm.Counter/Packages/manifest.json +++ b/samples/Unity.Mvvm.Counter/Packages/manifest.json @@ -4,12 +4,12 @@ "com.cysharp.unitask": "2.3.3", "com.unity.collab-proxy": "2.0.4", "com.unity.feature.2d": "1.0.0", - "com.unity.ide.rider": "3.0.21", + "com.unity.ide.rider": "3.0.22", "com.unity.ide.visualstudio": "2.0.18", "com.unity.ide.vscode": "1.2.5", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.6.4", + "com.unity.timeline": "1.6.5", "com.unity.ugui": "1.0.0", "com.unity.visualscripting": "1.8.0", "com.unity.modules.ai": "1.0.0", diff --git a/samples/Unity.Mvvm.Counter/Packages/packages-lock.json b/samples/Unity.Mvvm.Counter/Packages/packages-lock.json index b9da27b..75f9675 100644 --- a/samples/Unity.Mvvm.Counter/Packages/packages-lock.json +++ b/samples/Unity.Mvvm.Counter/Packages/packages-lock.json @@ -136,7 +136,7 @@ } }, "com.unity.ide.rider": { - "version": "3.0.21", + "version": "3.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -188,7 +188,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.6.4", + "version": "1.6.5", "depth": 0, "source": "registry", "dependencies": { diff --git a/samples/Unity.Mvvm.CounterLegacy/Packages/manifest.json b/samples/Unity.Mvvm.CounterLegacy/Packages/manifest.json index 9991cec..1f7a79b 100644 --- a/samples/Unity.Mvvm.CounterLegacy/Packages/manifest.json +++ b/samples/Unity.Mvvm.CounterLegacy/Packages/manifest.json @@ -3,12 +3,12 @@ "com.chebanovdd.unitymvvmtoolkit": "file:../../../src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit", "com.unity.collab-proxy": "2.0.4", "com.unity.feature.2d": "1.0.0", - "com.unity.ide.rider": "3.0.21", + "com.unity.ide.rider": "3.0.22", "com.unity.ide.visualstudio": "2.0.18", "com.unity.ide.vscode": "1.2.5", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.6.4", + "com.unity.timeline": "1.6.5", "com.unity.ugui": "1.0.0", "com.unity.visualscripting": "1.8.0", "com.unity.modules.ai": "1.0.0", diff --git a/samples/Unity.Mvvm.CounterLegacy/Packages/packages-lock.json b/samples/Unity.Mvvm.CounterLegacy/Packages/packages-lock.json index 086839c..f118002 100644 --- a/samples/Unity.Mvvm.CounterLegacy/Packages/packages-lock.json +++ b/samples/Unity.Mvvm.CounterLegacy/Packages/packages-lock.json @@ -129,7 +129,7 @@ } }, "com.unity.ide.rider": { - "version": "3.0.21", + "version": "3.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -181,7 +181,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.6.4", + "version": "1.6.5", "depth": 0, "source": "registry", "dependencies": { diff --git a/samples/Unity.Mvvm.ToDoList/Packages/manifest.json b/samples/Unity.Mvvm.ToDoList/Packages/manifest.json index 2928501..36ff41b 100644 --- a/samples/Unity.Mvvm.ToDoList/Packages/manifest.json +++ b/samples/Unity.Mvvm.ToDoList/Packages/manifest.json @@ -4,13 +4,13 @@ "com.cysharp.unitask": "2.3.3", "com.unity.collab-proxy": "2.0.4", "com.unity.feature.2d": "1.0.0", - "com.unity.ide.rider": "3.0.21", + "com.unity.ide.rider": "3.0.22", "com.unity.ide.visualstudio": "2.0.18", "com.unity.ide.vscode": "1.2.5", "com.unity.nuget.newtonsoft-json": "3.1.0", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.6.4", + "com.unity.timeline": "1.6.5", "com.unity.ugui": "1.0.0", "com.unity.visualscripting": "1.8.0", "com.unity.modules.ai": "1.0.0", diff --git a/samples/Unity.Mvvm.ToDoList/Packages/packages-lock.json b/samples/Unity.Mvvm.ToDoList/Packages/packages-lock.json index 54e906a..d9c0f9f 100644 --- a/samples/Unity.Mvvm.ToDoList/Packages/packages-lock.json +++ b/samples/Unity.Mvvm.ToDoList/Packages/packages-lock.json @@ -136,7 +136,7 @@ } }, "com.unity.ide.rider": { - "version": "3.0.21", + "version": "3.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -195,7 +195,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.6.4", + "version": "1.6.5", "depth": 0, "source": "registry", "dependencies": { diff --git a/src/UnityMvvmToolkit.UnityPackage/Packages/manifest.json b/src/UnityMvvmToolkit.UnityPackage/Packages/manifest.json index 7f13b4d..5103eee 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Packages/manifest.json +++ b/src/UnityMvvmToolkit.UnityPackage/Packages/manifest.json @@ -3,7 +3,7 @@ "com.cysharp.unitask": "2.3.3", "com.unity.collab-proxy": "2.0.4", "com.unity.feature.2d": "1.0.0", - "com.unity.ide.rider": "3.0.21", + "com.unity.ide.rider": "3.0.22", "com.unity.ide.visualstudio": "2.0.18", "com.unity.ide.vscode": "1.2.5", "com.unity.test-framework": "1.1.33", diff --git a/src/UnityMvvmToolkit.UnityPackage/Packages/packages-lock.json b/src/UnityMvvmToolkit.UnityPackage/Packages/packages-lock.json index 644693f..b0948e8 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Packages/packages-lock.json +++ b/src/UnityMvvmToolkit.UnityPackage/Packages/packages-lock.json @@ -130,7 +130,7 @@ } }, "com.unity.ide.rider": { - "version": "3.0.21", + "version": "3.0.22", "depth": 0, "source": "registry", "dependencies": { From ce7c10ab3c87695ca860295eb3d08bfb4db2b449 Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Tue, 6 Jun 2023 13:10:10 +0800 Subject: [PATCH 9/9] Bump package version. --- .../Assets/Plugins/UnityMvvmToolkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json index b43b0b9..1c52547 100644 --- a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/package.json @@ -2,7 +2,7 @@ "name": "com.chebanovdd.unitymvvmtoolkit", "displayName": "Unity MVVM Toolkit", "author": { "name": "ChebanovDD", "url": "https://github.com/ChebanovDD" }, - "version": "1.1.2", + "version": "1.1.3", "unity": "2018.4", "description": "The Unity Mvvm Toolkit allows you to use data binding to establish a connection between the app UI and the data it displays. This is a simple and consistent way to achieve clean separation of business logic from UI.", "keywords": [ "mvvm", "binding", "ui", "toolkit" ],