首页 文章

如何在DependencyProperty中传播PropertyChanged更改

提问于
浏览
11

我有一个实现INotifyPropertyChanged的类 . 该类的一个实例在Window中声明为DependencyProperty,例如,

public IMyClass MyClass
    {
        get { return (IMyClass)GetValue(MyClassProperty); }
        set { SetValue(MyClassProperty, value); }
    }
    public static readonly DependencyProperty MyClassProperty=
        DependencyProperty.Register("MyClass", typeof(IMyClass), typeof(MainWindow), new UIPropertyMetadata(null));

在XAML中,我有一个绑定到此类的元素

Text="{Binding MyClass, Converter={StaticResource someConverter}}

每当我在MyClass中更改属性时,我都希望触发someConverter . 但是,它只会在我完全换掉MyClass时发生 . 有没有办法将DependencyProperty更新绑定到MyClass PropertyChanged?

Update. 本着AresAvatar的精神's solution, here'我们到目前为止所拥有的 . 剩下的问题是如何调用InvalidateProperty(没有让MyClass跟踪它......)

public IMyClass MyClass
    {
        get { return (IMyClass)GetValue(MyClassProperty); }
        set { SetValue(MyClassProperty, value); }
    }
    public static readonly DependencyProperty MyClassProperty =
        DependencyProperty.Register("MyClass", typeof(IMyClass), typeof(MainWindow),
        new UIPropertyMetadata(null, new PropertyChangedCallback(OnMyClassChanged)));

    private static void OnMyClassChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue != null)
        {
            ((IMyClass)e.OldValue).PropertyChanged -= ((MainWindow)d).MyClass_PropertyChanged;
        }

        if (e.NewValue != null)
        {
            ((IMyClass)e.NewValue).PropertyChanged += ((MainWindow)d).MyClass_PropertyChanged;
        }
    }

    private void MyClass_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        this.InvalidateProperty(MyClassProperty);  <----- still does not refresh binding, but called.
    }

3 回答

  • 1

    转换器不应该做比简单转换更多的工作,你的问题听起来像转换器使用对象的许多属性来创建一些组合值 . 使用MultiBinding而不是挂钩到您需要的对象的所有不同属性,这样 MultiBinding 上的MultiValueConverter将在这些属性发生任何变化时触发 .

    此外,由于您似乎创建了文本,因此您可以在不使用任何转换器的情况下离开,因为_2611542可能就足够了 .

  • 7

    在MyClass中,实现NotifyPropertyChanged事件 . 然后将属性更改的回调添加到MyClass DependencyProperty . 在DP的属性更改回调中,将新的MyClass NotifyPropertyChanged事件挂钩到第二个回调函数(并使用 - =运算符取消挂起前一个值,如果有的话) . 在第二个回调函数中,调用DependencyObject.InvalidateProperty以便更新绑定 .

    Edit: 您可能需要触发绑定更新:

    BindingExpressionBase exp = BindingOperations.GetBindingExpressionBase(this, Container.MyClassProperty);
    if (exp != null)
        exp.UpdateTarget();
    
    class MyClass : INotifyPropertyChanged
    {
        /// <summary>
        /// Event raised when a property is changed
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
    
        /// <summary>
        /// Raises the property changed event
        /// </summary>
        /// <param name="e">The arguments to pass</param>
        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }
    
        /// <summary>
        /// Notify for property changed
        /// </summary>
        /// <param name="name">Property name</param>
        protected void NotifyPropertyChanged(string name)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(name));
        }
    
    
        /// <summary>
        /// The parent container object
        /// </summary>
        public Container Parent { get; set; }
    
    
        // Some data
        int x;
    }
    
    
    class Container : DependencyObject
    {
        public static readonly DependencyProperty MyClassProperty = DependencyProperty.Register("MyClass", typeof(MyClass), typeof(Container), new FrameworkPropertyMetadata(MyClassPropChanged));
    
        public MyClass MyClass
        {
            get { return (MyClass)GetValue(MyClassProperty); }
            set { SetValue(MyClassProperty, value); }
        }
    
        void MyClassPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Container ct = d as Container;
            if (ct == null)
                return;
    
            MyClass oldc = e.OldValue as MyClass;
            if (oldc != null)
            {
                oldc.PropertyChanged -= new PropertyChangedEventHandler(MyClass_PropertyChanged);
                oldc.Parent = null;
            }
            MyClass newc = e.NewValue as MyClass;
            if (newc != null)
            {
                newc.Parent = ct;
                newc.PropertyChanged += new PropertyChangedEventHandler(MyClass_PropertyChanged);
            }
        }
    
    
        void MyClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            MyClass mc = sender as MyClass;
            if (mc == null || mc.Parent == null)
                return;
            mc.Parent.InvalidateProperty(Container.MyClassProperty);
        }
    }
    
  • 1

    我发现的唯一技术是在策略性放置的事件处理程序(如LostFocus)中调用绑定的UpdateSource方法 .

    private void mycontrol_LostFocus(object sender, RoutedEventArgs e)
    {
        if (mycontrol.IsModified)
        {
            var binding = mycontrol.GetBindingExpression(MyControl.FooBarProperty);
            binding.UpdateSource();
        }
    }
    

    如果您不关心chattiness或者您的控件不关注输入焦点,则可以在mycontrol_PropertyChanged事件或类似事件中执行此操作 . 但是,在每次更改属性或每次击键时强制执行转换周期都可能会影响验证 .

相关问题