Получение проверки IDataErrorInfo для обновления в дочернем UserControl при вызове привязанного ViewModel OnPropertyChanged, но значение остается тем же - PullRequest
0 голосов
/ 08 января 2019

У меня определен повторно используемый UserControl, который будет использоваться несколько раз в родительской форме для представления различных экземпляров настроенного объекта. Этот UserControl имеет несколько TextBox, представляющих настраиваемые свойства. Для одного из этих свойств значение должно быть уникальным для всех экземпляров UserControl многократного использования.

Моя родительская форма использует эти пользовательские элементы управления следующим образом:

<namespace:ReusableControl
  Property1="{Binding Path=ViewModelProperty1a, Mode=TwoWay}"
  Property2="{Binding Path=ViewModelProperty2a, Mode=TwoWay}"
  UniqueProperty="{Binding Path=VMUniquePropertya, Mode=TwoWay}"/>

<namespace:ReusableControl
  Property1="{Binding Path=ViewModelProperty1b, Mode=TwoWay}"
  Property2="{Binding Path=ViewModelProperty2b, Mode=TwoWay}"
  UniqueProperty="{Binding Path=VMUniquePropertyb, Mode=TwoWay}"/>
И свойство UserControl выглядит так:
<TextBox 
  x:Name="UniquePropertyTextBox"
  Text="{Binding Path=UniqueProperty,
  RelativeSource={RelativeSource AncestorType=local:ReusableControl}, 
  Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" 
/>

Код для UserControl содержит проверку IDataErrorInfo:

public string this[string columnName]
{
    get
    {
        string error = string.Empty;
        switch (columnName)
        {
        case nameof(UniqueProperty):
            if (!((MyViewModel)DataContext).UniquePropertiesAreUnique())
            {
                error = "not unique";
            }
            break;
        //Other cases here, omitted from example
        }
        return error;
    }
}

//-------------------------------
//Just to show the codebehind for the property:
public string UniqueProperty
        {
            get { return (string)GetValue(UniquePropertyDP); }
            set { SetValue(UniquePropertyDP, value); }
        }

        public static readonly DependencyProperty UniquePropertyDP=
            DependencyProperty.Register(
                "UniqueProperty",
                typeof(string),
                typeof(ReusableControl),
                new PropertyMetadata(string.Empty));

Кажется, все подключено правильно и связано; значения обновляются, когда пользовательский интерфейс изменяется по желанию. Если я изменяю одно из уникальных значений свойств так, чтобы оно больше не было уникальным, я получаю красную рамку вокруг этого текстового поля, но здесь возникает проблема - красная граница появляется только вокруг текстового поля, которое я только что изменил, а не оба экземпляра UniqueProperty. В ViewModel, когда изменяется любое из значений UniqueProperty, он запускает OnPropertyChanged для другого, но это все равно не приводит к появлению границы проверки. Если я заменю OnPropertyChange явным вызовом, чтобы обновить значение, т. Е.

//In the setter for VMUniquePropertyb:
var temp = VMUniquePropertya;
VMUniquePropertya = null;
VMUniquePropertya = temp;
Затем я получаю границу проверки, которая появляется в обоих текстовых полях, когда это значение изменяется в соответствии с другим, и обе границы исчезают, когда любое значение снова изменяется на уникальное. Конечно, это взлом, а также вызовет бесконечный цикл, если используется на обоих свойствах. Как я могу достичь того же результата с OnPropertyChanged?

1 Ответ

0 голосов
/ 09 января 2019

Я нашел решение, которое работает для меня. Возможно, есть лучшие способы сделать это, но это работает довольно хорошо.

Используя CoerceValueCallback в DependencyProperty, мы можем выполнять код всякий раз, когда значение свойства переоценивается, а не только когда оно действительно изменяется. Это сработает, когда событие PropertyChange произойдет в ViewModel, потому что привязка переоценена. Это выглядит так:

public string UniqueProperty
        {
            get { return (string)GetValue(UniquePropertyDP); }
            set { SetValue(UniquePropertyDP, value); }
        }

public static readonly DependencyProperty UniquePropertyDP=
    DependencyProperty.Register(
        "UniqueProperty",
        typeof(string),
        typeof(ReusableControl),
        new PropertyMetadata(string.Empty, null, UniquePropertyCoerceValueCallback));

private static object UniquePropertyCoerceValueCallback(DependencyObject d, object value)
{
    ((ReusableControl)d).UniquePropertyTextBox.GetBindingExpression(TextBox.TextProperty)
        .UpdateTarget();

    return value;
}
Когда значение одного из уникальных свойств изменяется и ViewModel запускает событие PropertyChange для другого уникального свойства в ViewModel, свойство DependencyProperty в UserControl будет принудительно вызываться, вызывая этот обратный вызов и обновляя проверку.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...