强制依赖项属性始终调用PropretyChangedCallback

时间:2018-12-21 14:30:23

标签: c# wpf data-binding

我有一个带有“ SetState” DependencyProperty的CustomControl。这绑定到具有转换器的MultiBinding(单向)。一切正常。

因此,所有内容均已正确更新,激发了PropertyChanged事件,转换器获取值,生成输出值,但如果(例如)为true且转换器也屈服为true,则SetState属性未更新。由于我要执行重置逻辑(请参见下面的代码),因此我希望SetState始终被更新,即使它将被设置为与当前值相同。 (如果转换器导致false且SetState为true,则SetState将按预期正确更新为false)


MWE(即时输入错误,请输入我的错误)

查看

    <local:CustomControl>
        <local:CustomControl.SetState>
            <MultiBinding Converter="{local:MyConverter}">
                <Binding Path="MyProp1" Mode="OneWay" UpdateSourceTrigger="PropertyChanged"/>
                <Binding Path="MyProp2" Mode="OneWay" UpdateSourceTrigger="PropertyChanged"/>
            </MultiBinding>
        </local:CustomControl.SetState>
    </local:CustomControl>

自定义控件

   public class CustomControl : FrameworkElement
   {
      public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(
              nameof(SetState),
              typeof(bool),
              typeof(CustomControl),
              new FrameworkPropertyMetadata(false, (s, e) =>
              {
                 ((CustomControl)s).SetState = (bool)e.NewValue;
              }));

      private bool _state;

      // For brevity i have used a boolean in the MWE
      public bool SetState
      {
         get { return _state; }
         set
         {
            // This is not called when the binding produces the same value as this property already has
            // but i want this to be set anyway to trigger the reset logic even though SetState property already equal the value being set.

            // Custom reset logic here

            _state = value;
         }
      }
   }

转换器

  internal class MyConverter : MarkupExtension, IMultiValueConverter
   {
      private static MyConverter _instance;

      public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
      {
         // Imagine some complex logic here
         return ((bool)value[0] || (bool)value[1]);
      }

      public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
      {
         throw new NotImplementedException();
      }

      public override object ProvideValue(IServiceProvider serviceProvider)
      {
         return _instance ?? (_instance = new MyConverter());
      }
   }

查看模型

   internal class MyViewModel : INotifyPropertyChanged
   {
      private bool _myProp1;
      private bool _myProp2;

      // Imagine the properties being altered at run-time

      public bool MyProp1
      {
         get { return _myProp1; }
         private set { _myProp1 = value; OnPropertyChanged(); }
      }

      public bool MyProp2
      {
         get { return _myProp2; }
         private set { _myProp2 = value; OnPropertyChanged(); }
      }

      public event PropertyChangedEventHandler PropertyChanged;

      private void OnPropertyChanged([CallerMemberName] string propertyName = null)
      {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
   }

1 个答案:

答案 0 :(得分:0)

该解决方案最终是simple,因为DependencyProperty使用CoerceValueCallback而不是PropertyChangedCallback。始终调用前者,只有在实际更改值时才调用后者。

所以在代码中它变成了

  public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(
          nameof(SetState),
          typeof(bool),
          typeof(CustomControl),
      new PropertyMetadata(false, null,
         (d, v) =>
         {
            ((CollapsibleColumnDefinition)d).IsExpanded = (bool)v;
            return v;
         }));

我短暂地尝试手动强制刷新依赖项属性(请注意bug),但是CoerceValueCallback确实可以实现我想要的并且更干净。