protected override bool SetValueInternal(IBindingSourceAccessor targetAccessor, IDataContext context,
                                                 bool throwOnError)
        {
            IBindingPathMembers members = _bindingSource.GetPathMembers(throwOnError);

            if (!members.AllMembersAvailable)
            {
                return(false);
            }

            object             penultimateValue = members.PenultimateValue;
            IBindingMemberInfo lastMember       = members.LastMember;

            object oldValue;
            object newValue = targetAccessor.GetValue(lastMember, context, throwOnError);

            if (lastMember.CanRead && !BindingMemberType.BindingContext.EqualsWithoutNullCheck(lastMember.MemberType))
            {
                oldValue = lastMember.GetValue(penultimateValue, null);
                if (ReferenceEquals(oldValue, newValue) || newValue.IsUnsetValueOrDoNothing())
                {
                    return(false);
                }
            }
            else
            {
                oldValue = BindingConstants.UnsetValue;
                if (newValue.IsUnsetValueOrDoNothing())
                {
                    return(false);
                }
            }

            ValueAccessorChangingEventArgs args = null;

            if (ValueChanging != null)
            {
                args = RaiseValueChanging(context, penultimateValue, lastMember, oldValue, newValue);
                if (args != null)
                {
                    if (args.Cancel)
                    {
                        return(false);
                    }
                    if (!ReferenceEquals(newValue, args.NewValue))
                    {
                        newValue = args.NewValue;
                        if (newValue.IsUnsetValueOrDoNothing())
                        {
                            return(false);
                        }
                    }
                }
            }
            newValue = BindingServiceProvider.ValueConverter(lastMember, lastMember.Type, newValue);
            if (Equals(oldValue, newValue))
            {
                return(false);
            }
            if (BindingMemberType.Event.EqualsWithoutNullCheck(lastMember.MemberType))
            {
                TryRegisterEvent((BindingActionValue)oldValue, newValue, context);
                RaiseValueChanged(context, penultimateValue, lastMember, oldValue, newValue, args);
            }
            else
            {
                if (_closure != null)
                {
                    _closure.Unsubscribe(false, _isOneTime);
                }
                lastMember.SetSingleValue(penultimateValue, newValue);
                if (ValueChanged != null)
                {
                    RaiseValueChanged(context, penultimateValue, lastMember, oldValue, newValue, args);
                }
            }
            return(true);
        }
        protected override bool SetValueInternal(IBindingSourceAccessor targetAccessor, IDataContext context,
                                                 bool throwOnError)
        {
            IBindingPathMembers members = _bindingSource.GetPathMembers(throwOnError);
            object penultimateValue     = members.PenultimateValue;

            if (penultimateValue.IsUnsetValue() || (penultimateValue == null && !members.AllMembersAvailable))
            {
                if (members.Path.IsDebuggable)
                {
                    DebugInfo($"Binding cannot set value for path {members.Path.Path}", new object[] { members });
                }
                return(false);
            }

            IBindingMemberInfo lastMember = members.LastMember;
            object             oldValue;
            object             newValue = targetAccessor.GetValue(lastMember, context, throwOnError);

            if (lastMember.CanRead && !BindingMemberType.BindingContext.EqualsWithoutNullCheck(lastMember.MemberType))
            {
                if (_disableEqualityChecking && !BindingMemberType.Event.EqualsWithoutNullCheck(lastMember.MemberType))
                {
                    oldValue = BindingConstants.UnsetValue;
                }
                else
                {
                    oldValue = lastMember.GetValue(penultimateValue, null);
                }
                if (ReferenceEquals(oldValue, newValue) || newValue.IsUnsetValueOrDoNothing())
                {
                    if (members.Path.IsDebuggable)
                    {
                        DebugInfo($"Binding ignores setter because old value: '{oldValue}' equals to new value '{newValue}'", new[] { members, oldValue, newValue });
                    }
                    return(false);
                }
            }
            else
            {
                oldValue = BindingConstants.UnsetValue;
                if (newValue.IsUnsetValueOrDoNothing())
                {
                    if (members.Path.IsDebuggable)
                    {
                        DebugInfo($"Binding ignores setter for value '{newValue}'", new[] { members, newValue });
                    }
                    return(false);
                }
            }

            ValueAccessorChangingEventArgs args = null;

            if (ValueChanging != null)
            {
                args = RaiseValueChanging(context, penultimateValue, lastMember, oldValue, newValue);
                if (args != null)
                {
                    if (args.Cancel)
                    {
                        return(false);
                    }
                    if (!ReferenceEquals(newValue, args.NewValue))
                    {
                        newValue = args.NewValue;
                        if (newValue.IsUnsetValueOrDoNothing())
                        {
                            if (members.Path.IsDebuggable)
                            {
                                DebugInfo($"Binding ignores setter for value '{newValue}'", new[] { members, newValue });
                            }
                            return(false);
                        }
                    }
                }
            }
            newValue = BindingServiceProvider.ValueConverter(lastMember, lastMember.Type, newValue);
            if (Equals(oldValue, newValue))
            {
                if (members.Path.IsDebuggable)
                {
                    DebugInfo($"Binding ignores setter because old value: '{oldValue}' equals to new value '{newValue}'", new[] { members, oldValue, newValue });
                }
                return(false);
            }
            if (BindingMemberType.Event.EqualsWithoutNullCheck(lastMember.MemberType))
            {
                TryRegisterEvent((BindingActionValue)oldValue, newValue, context, members);
                RaiseValueChanged(context, penultimateValue, lastMember, oldValue, newValue, args);
            }
            else
            {
                _closure?.Unsubscribe(false, _isOneTime);
                lastMember.SetSingleValue(penultimateValue, newValue);
                if (members.Path.IsDebuggable)
                {
                    DebugInfo($"Binding set value: '{newValue}' for source: '{penultimateValue}' with path: '{lastMember.Path}'", new[] { newValue, penultimateValue, lastMember });
                }
                if (ValueChanged != null)
                {
                    RaiseValueChanged(context, penultimateValue, lastMember, oldValue, newValue, args);
                }
            }
            return(true);
        }
예제 #3
0
        protected virtual IBindingMemberInfo GetExplicitBindingMember([NotNull] Type sourceType, [NotNull] string path)
        {
            path = path.Trim();
            string[] indexerArgs = null;
            if (path.StartsWith("[", StringComparison.Ordinal) && path.EndsWith("]", StringComparison.Ordinal))
            {
                indexerArgs = path
                              .RemoveBounds()
                              .Split(BindingReflectionExtensions.CommaSeparator, StringSplitOptions.RemoveEmptyEntries);
            }

            var types = BindingReflectionExtensions.SelfAndBaseTypes(sourceType);

            foreach (var type in types)
            {
                if (indexerArgs == null)
                {
                    PropertyInfo property = type.GetPropertyEx(path, PropertyFlags);
                    if (property != null)
                    {
                        return(new BindingMemberInfo(path, property, sourceType));
                    }
                }
                else
                {
                    PropertyInfo candidate      = null;
                    int          valueTypeCount = -1;
                    foreach (var property in type.GetPropertiesEx(PropertyFlags))
                    {
                        var indexParameters = property.GetIndexParameters();
                        if (indexParameters.Length != indexerArgs.Length)
                        {
                            continue;
                        }
                        try
                        {
                            int count = 0;
                            for (int i = 0; i < indexParameters.Length; i++)
                            {
                                var arg       = indexerArgs[i];
                                var paramType = indexParameters[i].ParameterType;
                                if (arg.StartsWith("\"", StringComparison.Ordinal) && arg.EndsWith("\"", StringComparison.Ordinal))
                                {
                                    if (paramType != typeof(string))
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    BindingServiceProvider.ValueConverter(Empty, paramType, arg);
                                    if (paramType.IsValueType())
                                    {
                                        count++;
                                    }
                                }
                            }
                            if (valueTypeCount < count)
                            {
                                candidate      = property;
                                valueTypeCount = count;
                            }
                        }
                        catch
                        {
                            ;
                        }
                    }
                    if (candidate != null)
                    {
                        return(new BindingMemberInfo(path, candidate, sourceType));
                    }
                    if (type.IsArray && type.GetArrayRank() == indexerArgs.Length)
                    {
                        return(new BindingMemberInfo(path, type));
                    }
                }
                EventInfo @event = type.GetEventEx(path, EventFlags);
                if (@event != null)
                {
                    return(new BindingMemberInfo(path, @event, null));
                }

                FieldInfo field = type.GetFieldEx(path, FieldFlags);
                if (field != null)
                {
                    return(new BindingMemberInfo(path, field, sourceType));
                }
            }

            if (typeof(IDynamicObject).IsAssignableFrom(sourceType))
            {
                return(new BindingMemberInfo(path, false));
            }
            if (typeof(ExpandoObject).IsAssignableFrom(sourceType))
            {
                return(new BindingMemberInfo(path, true));
            }


            if (path.EndsWith(AttachedMemberConstants.ChangedEventPostfix, StringComparison.Ordinal))
            {
                var memberName = path.Substring(0, path.Length - 7);
                var member     = GetBindingMember(sourceType, memberName, false, false);
                if (member != null && member.CanObserve)
                {
                    return(new BindingMemberInfo(path, null, member));
                }
            }
            return(null);
        }