Проблемы с параметризацией ValidationRules со свойствами зависимостей

поэтому я написал следующие DP и ValidationRule:

public class ComparisonValue : DependencyObject
{
    public Object ComparisonObject
    {
        get { return (Object)GetValue(ComparisonObjectProp); }
        set { 
            SetValue(ComparisonObjectProp, value); 
        }
    }
    public static readonly DependencyProperty ComparisonObjectProp =
        DependencyProperty.Register("ComparisonObject", typeof(object), typeof(ComparisonValue), new UIPropertyMetadata(null));
}

public class ObjectComparisonValidator : ValidationRule
{
    private ComparisonValue _ObjectToCompare;
    public ComparisonValue ObjectToCompare
    {
        get
        {
            return _ObjectToCompare;
        }
        set
        {
            _ObjectToCompare = value;
        }

    }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (value != null)
        {
            if (!value.Equals(ObjectToCompare.ComparisonObject))
            {
                return new ValidationResult(false, "Values are not equal");
            }
            else
            {
                return new ValidationResult(true, null);
            }
        }
        else
        {
            if (value != ObjectToCompare.ComparisonObject)
            {
                return new ValidationResult(false, "Values are not equal");
            }
            else
            {
                return new ValidationResult(true, null);
            }
        }
    }
}

Затем в моем XAML у меня есть следующая разметка:

<UserControl.Resources>
    <l:EnumToStringConverter x:Key="CustomEnumConverter"/>
    <l:BooleanToBrushConverter x:Key="BooleanToBrushConverter"/>
    <l:ObjectComparisonValidator x:Key="ObjectComparisonValidator"/>
    <l:ComparisonValue x:Key="ComparisonValue"/>
</UserControl.Resources>

....

            <TextBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Height="25" Text="{Binding Path=NetworkKey.Value, UpdateSourceTrigger=PropertyChanged}">
                <TextBox.Background>
                    <Binding Path="NetworkKey.Changed" Converter="{StaticResource BooleanToBrushConverter}">
                        <Binding.ConverterParameter>
                            <x:Array Type="Brush">
                                <SolidColorBrush Color="Yellow"/>
                                <SolidColorBrush Color="White"/>
                            </x:Array>
                        </Binding.ConverterParameter>
                    </Binding>
                </TextBox.Background>
            </TextBox>

....

            <TextBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Height="25">                    
                <TextBox.Text>
                    <Binding Path="DuplicateNetworkKey.Value" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <l:ObjectComparisonValidator>
                                <l:ObjectComparisonValidator.ObjectToCompare>
                                    <l:ComparisonValue ComparisonObject="{Binding Path=NetworkKey.Value}"/>
                                </l:ObjectComparisonValidator.ObjectToCompare>
                            </l:ObjectComparisonValidator>
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
                <TextBox.Background>
                    <Binding Path="DuplicateNetworkKey.Changed" Converter="{StaticResource BooleanToBrushConverter}">
                        <Binding.ConverterParameter>
                            <x:Array Type="Brush">
                                <SolidColorBrush Color="Yellow"/>
                                <SolidColorBrush Color="White"/>
                            </x:Array>
                        </Binding.ConverterParameter>
                    </Binding>
                </TextBox.Background>
            </TextBox>

Теперь проблема, с которой я столкнулся, заключается в том, что вызывается метод Validate для правила проверки, но когда запускается привязка для NetworkKey, Setter в ComparisonValue для объекта никогда не вызывается, поэтому каждый раз, когда выполняется правило проверки, свойство ComparisonObject ObjectComparisonValidator.ObjectToCompare имеет значение null, поэтому проверка не выполняется. Что не так с привязкой, которую я имею для ComparisonObject?

просто для небольшого пояснения, тип NetworkKey и DuplicateKey (реквизиты в виртуальной машине) являются классами INPC. Вот код для них:

public class ValueField<T> : AChangeReportingViewModel, INotifyPropertyChanged
{
    private T _OriginalVal;
    public T OriginalVal
    {
        get
        {
            return _OriginalVal;
        }
        set
        {
            _OriginalVal = value;
            Value = value;
            Changed = false;
            PropertyChanged(this, new PropertyChangedEventArgs("OriginalVal"));
        }
    }
    private T _Value;
    public T Value
    {
        get
        {
            return _Value;
        }
        set
        {
            _Value = value;
            if (_Value == null)
            {
                if (_OriginalVal != null) Changed = true;
            }
            else
            {
                Changed = !_Value.Equals(_OriginalVal);
            }
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
    }
    private Boolean _Changed;
    public Boolean Changed
    {
        get
        {
            return _Changed;
        }
        set
        {
            if (_Changed != value)
            {
                if (value) ChangeMade();
                else ChangeReversed();
            }
            _Changed = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Changed"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

person Mark W    schedule 02.06.2015    source источник


Ответы (1)


<Binding Path="DuplicateNetworkKey.Value" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <l:ObjectComparisonValidator>
                            <l:ObjectComparisonValidator.ObjectToCompare>
                                <l:ComparisonValue ComparisonObject="{Binding Path=NetworkKey.Value}"/>
                            </l:ObjectComparisonValidator.ObjectToCompare>
                        </l:ObjectComparisonValidator>
                    </Binding.ValidationRules>
                </Binding>

Внутренний объект привязки не является частью визуального дерева и поэтому не наследует контекст данных родителя. Чтобы выполнить привязку за пределами визуального дерева, используйте привязку x:Reference:

<l:ComparisonValue ComparisonObject="{Binding Source={x:Reference Root} 
                                      Path=DataContext.NetworkKey.Value}"/>

Это похоже на привязку ElementName, но вы не можете делать это за пределами визуального дерева. Обратите внимание, что «Root» в этом примере — это имя корневого элемента пользовательского интерфейса.

person BradleyDotNET    schedule 02.06.2015
comment
Это довольно простой обходной путь... гораздо лучше, чем другие решения, которые я нашел, такие как создание ресурсов прокси-сервера и еще много чего. Спасибо! - person Mark W; 03.06.2015