WPF PropertyChanged в UserControl DependencyProperty не запускается каждый раз - PullRequest
0 голосов
/ 08 января 2019

В течение многих часов я исследовал следующую ситуацию: у меня есть окно, определенное xaml, которое использует usercontrol (ToggleButton) с некоторыми свойствами зависимостей.

Базовая модель представления окна содержит некоторые логические объекты, которые представляют состояние устройств (вкл / выкл), а другие представляют запрос на переключение устройства с истинным / ложным флангом (к ним подключен ПЛК, и связь работает нормально ).

Следовательно, в пользовательском контроле есть 2 DP:

Тот, который переключает устройства (режим привязки OneWayToSource с UpdateSourceTrigger.Explicit работает нормально (показывая мне, что основы, такие как общий DataContext, хороши и нигде не "нарушены").

Однако привязка, указывающая другой DP (состояние устройства с режимом привязки OneWay), показывает следующие признаки:

  1. Устройство (PLC-) выключено (ложно) перед запуском программы

    Результат: По умолчанию для свойства DeviceState установлено значение false. Set вызывается впервые при включении устройства (базовый объект viewmodel изменяется на true, сообщает об этом через PropertyChanged уведомление) и DependencyPropertyChanged является вызывается правильно. Далее переключается на выкл / вкл (ложь / истина) снова не приводит к повторному вызову "set" (хотя PropertyChanged на базовый объект снова вызывается).

  2. Устройство включено (true) перед запуском программы

    Результат: Обработчик DP запускается в начало программы и без изменений false или true позволяет вызывать его снова.

Я уже пытался отследить это:

  1. Реализован DummyDebugConverter .

    Результат: я вижу, что он также выстрелил только один раз. Так что не давая мне никакой дополнительной подсказки

  2. Проанализировал окно вывода и обнаружил следующее сообщение:

    Информация System.Windows.Data: 21: BindingExpression не может получить значение из нулевого элемента данных. Это может произойти, когда привязка отсоединена или когда связывается с типом Nullable, который не имеет значения. BindingExpression: Path = bLightState.Value; DataItem = 'ControlPanelModel' (HashCode = 45596481); целевой элемент - AdsButton (Name = 'btnLight'); Свойство target - DeviceState (тип Boolean)

    Отладка этого не дала мне подсказку. Мои контрольные точки, например в отладочном конвертере или методе set нигде не показывал мне нулевое значение. Все значения в конструкторе viewmodel инициализируются значениями по умолчанию. Но я вижу сообщение всегда только один раз и полагаю, что оно как-то связано с проблемой.

  3. Использовал то же выражение привязки для целей тестирования на некоторых других элементах (метка и кнопка переключения) помимо моего usercontrol. Они работают хорошо и обновляют свои значения, как и ожидалось, как только объект в модели представления изменяется (желаемое поведение). Сообщение в 2 не удовлетворяет, если я удалю свой пользовательский контроль.

Итак, я прихожу к выводу, что ошибка в моем определении DP.

Вот соответствующие фрагменты кода:

AdsButton.xaml.cs

    [Description("When set to true the device is shown as on"), Category("Default")]
    public bool DeviceState
    {
        get { return (bool)GetValue(DeviceStateProperty); }
        set { SetValue(DeviceStateProperty, value); }
    }

public static readonly DependencyProperty DeviceStateProperty =
            DependencyProperty.Register(
                "DeviceState", typeof(bool),
                typeof(AdsButton), 
                new FrameworkPropertyMetadata(
                  false, 
                  FrameworkPropertyMetadataOptions.None,
                  DeviceStateChanged, 
                  CoerceDeviceStateProperty,
                  true,
                  UpdateSourceTrigger.Explicit));

        private static void DeviceStateChanged(DependencyObject d, 
               DependencyPropertyChangedEventArgs e)
        {
            (d as AdsButton).DeviceState = (bool) e.NewValue;
        }

        private static object CoerceDeviceStateProperty(DependencyObject d, object value)
        {
            return value ?? false;
        }

ControlPanel.xaml

      <src:AdsButton x:Name="btnLight"  
                  Value="{Binding Path=bLight.Value, Mode=OneWayToSource}"
                  DeviceState="{Binding Path=bLightState.Value, Mode=OneWay}" />
      <Label Content="{Binding bLightState.Value, Mode=OneWay}" />
      <ToggleButton Content="Button" IsChecked="{Binding bLightState.Value, Mode=OneWay}" />

Так кто-нибудь знает: почему мой собственный DP реагирует иначе, чем в стандартных элементах управления?

1 Ответ

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

Благодаря первоначальному комментарию Роджера ... ответ очевиден:

Установка самого DP в методе сеттера перезаписывает привязку с фиксированным значением (которое фактически удаляет его), но только если новое значение отличается от старого.

...