que property event ejemplo change wpf data-binding inotifypropertychanged

wpf - event - Problema INotifyPropertyChanged



raise event on property change c# (7)

Al principio quiero decir que la muestra a continuación es una simplificación excesiva. Supongamos que ha atado el control de WPF.

<Window Title="Window1" Height="300" Width="300"> <Grid> <StackPanel> <TextBox Text="{Binding Name}" Margin="10"/> <Button HorizontalAlignment="Center" Content="Click Me" Margin="5" Padding="2" Click="OnButtonClick" /> </StackPanel> </Grid> </Window>

La ventana está ligada a la clase Person que implementa INotifyPropertyChanged y tiene el nombre setter en forma

public string Name { get { return _name; } set { _name = "Some Name"; OnPropertyChanged("Name"); } }

Es decir, _name tiene asignado "Some Name" cada vez que el usuario intenta cambiarlo de la IU. Pero esta muestra no funciona. Cambié el nombre en TextBox a algún valor. Presiono la pestaña Forcing Focus para moverme al botón y el valor en TextBox permanece sin cambios aunque se activó el evento PropertyChanged.

¿Podría explicarme por qué sucede? Según entiendo, el evento PropertyChanged fuerza a la IU a volver a leer los valores de las propiedades y mostrarlos, pero en mi valor de ejemplo en el cuadro de texto de datos no se actualiza.

De nuevo. Entiendo que esta es una implementación deficiente de la propiedad pero quiero repetir que esto es una simplificación excesiva. Es solo una muestra. Pero de todos modos, PropertyChanged señala que la propiedad se modificó y debe actualizarse, pero no es así.


El TextBox ignora el evento PropertyChanged porque es el iniciador del evento.

Alguna aclaración:

El TextBox (o el enlace en el cuadro de texto) sabe que es el iniciador porque recibe el evento PropertyChanged en la misma llamada. Al hacer una llamada asincrónica, el cuadro de texto (o enlace) no tiene manera de saber que es el iniciador, por lo que procesará el evento como si alguien más lo hubiera actualizado

Si agrega un segundo cuadro de texto a su IU, verá que el 2º cuadro de texto cambia cuando edita el 1er y al revés.


La razón es porque has codificado el ''Some Name'' en el setter. Cuando cambiaste el valor del cuadro de texto, en realidad se está llamando al colocador y vuelve a configurar "Some Name" como propertyValue para que no parezca cambiar en la interfaz de usuario. Ponga _name = value y todo funcionará como esperaba,


Reemplazando setter en forma

set { _name = "Some Name"; Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.DataBind, (SendOrPostCallback)delegate { OnPropertyChanged("Name"); }, null); }

resuelve el problema, pero todavía está abierto. ¿Por qué debería hacer una llamada asíncrona en lugar de señalizar sincrónicamente que mi propiedad ha sido modificada?


Si no me equivoco, el comportamiento de enlace predeterminado de la propiedad Text en el TextBox es TwoWay, por lo que debería funcionar. Puede forzarlo a TwoWay en el XAML de esta manera:

<Window Title="Window1" Height="300" Width="300"> <Grid> <StackPanel> <TextBox Text="{Binding Name, Mode=TwoWay}" Margin="10"/> <Button HorizontalAlignment="Center" Content="Click Me" Margin="5" Padding="2" Click="OnButtonClick" /> </StackPanel> </Grid> </Window>

Tenga en cuenta el Mode=TwoWay en la declaración de enlace.

Si eso no funciona, entonces sospecho que se está lanzando una excepción en el código que dispara el evento, o asigna la propiedad y debe buscar eso.

Parece que hay una posibilidad de que esté realizando una llamada para cambiar el valor de un hilo que no es el de UI. Si este es el caso, entonces tiene que ordenar la llamada para activar el evento de propiedad cambiada en el subproceso de UI, o hacer el cambio al valor en el subproceso de interfaz de usuario.

Cuando un objeto está vinculado a un elemento de la interfaz de usuario, los cambios en el objeto que pueden afectar a la interfaz de usuario se deben realizar en la secuencia de la interfaz de usuario.


public string MyField { get { return _myField; } set { if (_myField == value) return; _myField = value; OnPropertyChanged("MyField"); } }

Esta es la implementación correcta de la propiedad.

Cuando cambie la propiedad, asegúrese de que la misma instancia EXACTA del objeto esté vinculada a un control. De lo contrario, se notificará el cambio pero el control nunca lo obtendrá porque el control no está enlazado correctamente.


Como Bubblewrap ya señaló, esto es por diseño: el cuadro de texto asume que si establece una propiedad vinculada a algún valor, el colocador no cambiará el valor. Según Microsoft , no cambiarán este comportamiento ya que esto rompería el código existente.

Si desea cambiar el valor (sí, existen razones perfectamente buenas para hacerlo), debe usar una solución, por ejemplo, agregando un convertidor ficticio. Hay una entrada de blog (no escrita por mí) que describe esta técnica en detalle.


La solución del convertidor ficticio sugerida por Heinzi (que se describe aquí ) no funciona cuando UpdateSourceTrigger de enlace es PropertyChanged . Pero, ¿y si esto es lo que necesitamos?

Parece que hacer el enlace asincrónico es el truco, por ejemplo:

SelectedIndex="{Binding SelectedIndex, IsAsync=True}"