property event ejemplo change c# wpf xaml data-binding dependency-properties

ejemplo - raise event on property change c#



Cómo propagar cambios PropertyChanged en DependencyProperty (3)

En MyClass, implemente un evento NotifyPropertyChanged. A continuación, agregue una devolución de llamada cambiada de propiedad a su MyClass DependencyProperty. En la propiedad de la DP cambio de devolución de llamada, conecte su nuevo evento MyClass NotifyPropertyChanged a una segunda función de devolución de llamada (y desenganche el valor anterior, si lo hay, con un operador - =). En la segunda función de devolución de llamada, llame a DependencyObject.InvalidateProperty para que el enlace se actualice.

Editar: es posible que deba activar una actualización vinculante con:

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); } }

Tengo una clase que implementa INotifyPropertyChanged. Una instancia de esta clase se declara como DependencyProperty en una ventana, por ejemplo,

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));

En el XAML, tengo un elemento que está vinculado a esta clase usando

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

Cada vez que cambio una propiedad en MyClass, me gustaría que se active algún Convertidor. Sin embargo, solo sucede cuando cambio por completo MyClass. ¿Hay alguna forma de vincular las actualizaciones de DependencyProperty a MyClass PropertyChanged?

Actualizar. En el espíritu de la solución de AresAvatar, esto es lo que tenemos hasta ahora. El problema restante es cómo llamar a InvalidateProperty (sin que MyClass lo rastree ...)

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. }


La única técnica que he encontrado es llamar al método UpdateSource del enlace en un controlador de eventos estratégicamente ubicado, como LostFocus.

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

Si no le importa la conversación o si su control no toma el foco de entrada, puede hacerlo en el evento mycontrol_PropertyChanged o similar. Sin embargo, forzar un ciclo de conversión en cada cambio de propiedad o cada golpe de teclado puede interferir con la validación.


Los convertidores no deberían hacer más trabajo que las conversiones simples, su pregunta parece que el convertidor usa muchas propiedades del objeto para crear un valor combinado. Usa un MultiBinding que se engancha en todas las diferentes propiedades del objeto que necesites, de esa forma el MultiValueConverter en ese MultiBinding se MultiBinding si alguna de esas propiedades cambia.

Además, dado que pareces crear texto, puedes escapar sin usar ningún convertidor, ya que StringFormat puede ser suficiente.