Ejercicio: Implementación de INotifyPropertyChanged para habilitar actualizaciones inmediatas de la interfaz de usuario
En este ejercicio, agregará notificaciones de cambio a la clase de origen de datos Flag
. Generar un evento permite que los enlaces actualicen la interfaz de usuario inmediatamente cuando los datos cambian.
Este ejercicio es una continuación del anterior. Puede usar la solución existente o comenzar desde la solución exercise1final de la copia del repositorio del ejercicio que ha clonado o descargado.
Cambio de los datos subyacentes
En primer lugar se verá el comportamiento de la aplicación cuando el tipo de origen no implementa . Este código no pretende ser realista. Simplemente es una manera fácil de que vea la necesidad de las notificaciones de cambios.
Abra MainPage.xaml.cs y busque el método .
Agregue un año a la propiedad
Flag.DateAdopted
; para ello llame a.AddYears(1)
y asigne el valor devuelto a la propiedadDateAdopted
. Tenga en cuenta que tendrá que asignar la propiedad, ya que es inmutable. Este código simula los datos nuevos que llegan desde la web, ya que es un cambio de datos que el usuario no realiza a través de la interfaz de usuario.private async void OnShow(object sender, EventArgs e) { CurrentFlag.DateAdopted = CurrentFlag.DateAdopted.AddYears(1); await DisplayAlert(CurrentFlag.Country, $"{CurrentFlag.DateAdopted:D} - {CurrentFlag.IncludesShield}: {CurrentFlag.MoreInformationUrl}", "OK"); }
Ejecute la aplicación y observe que se muestra la fecha actual. Seleccione Show (Mostrar) en la barra de herramientas. Se muestran los detalles de la bandera, pero el año se incrementa en el cuadro de diálogo de alerta. Tome nota del año que se muestra.
Cierre el cuadro de diálogo de alerta. Observe que la interfaz de usuario muestra el año original, incluso aunque los datos cambien en el modelo subyacente.
Implementación de INotifyPropertyChanged
El método OnShow
cambia los datos del objeto Flag
, pero Xamarin.Forms no es consciente de que la propiedad ha cambiado. En este caso, para corregir este problema se implementa INotifyPropertyChanged
en la clase Flag
.
Abra Flag.cs en el proyecto FlagData.
Modifique la clase
Flag
para implementarSystem.ComponentModel.INotifyPropertyChanged
. La implementación requiere un único evento denominadoPropertyChanged
.public class Flag : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; ... }
Cree un método auxiliar denominado
RaisePropertyChanged
para generar el eventoPropertyChanged
. El método acepta un parámetrostring
que es el nombre de texto de la propiedad que ha cambiado.- En .NET 4.5 se incluye un atributo
CallerMemberNameAttribute
en el espacio de nombresSystem.Runtime.CompilerServices
que puede usar para hacer que el compilador identifique la propiedad que ha cambiado. Por ejemplo, vea el siguiente ejemplo de código. También puede hacer que el autor de la llamada pase el nombre mediante la característica del compiladornameof()
de C#. - Asegúrese de probar el evento para
null
antes de generarlo. Use la compatibilidad de comprobación de valores NULL integrada de C#. Para versiones anteriores de C#, pruebe el evento paranull
, o bien asigne el evento a un delegado vacío.
using System.Runtime.CompilerServices; ... public class Flag : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; ... private void RaisePropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
- En .NET 4.5 se incluye un atributo
Convierta la propiedad implementada automáticamente
DateAdopted
existente en una propiedad de campo de respaldo. Llame al métodoRaisePropertyChanged
desde el establecedor.Sugerencias:
- Asegúrese de que el nuevo valor es diferente del antiguo. No resulta eficaz generar una notificación de cambio de propiedad si el valor no ha cambiado.
- Asigne el valor nuevo.
- Genere la notificación de cambio de propiedad mediante el método nuevo.
private DateTime _dateAdopted; ... public DateTime DateAdopted { get { return _dateAdopted; } set { if (_dateAdopted != value) { _dateAdopted = value; // Can pass the property name as a string, // -or- let the compiler do it because of the // CallerMemberNameAttribute on the RaisePropertyChanged method. RaisePropertyChanged(); } } }
Si quiere, puede repetir el paso anterior para las demás propiedades. No se cambiará ninguna de ellas, pero todas tendrán que generar la notificación
PropertyChanged
para notificar correctamente a la interfaz de usuario de una aplicación de producción. En el proyecto completado incluido con los materiales del laboratorio se realiza este paso adicional.Ejecute la aplicación, desplácese hacia abajo hasta el control Current Design was Adopted On (El diseño actual se adoptó el) y seleccione Show (Mostrar). Verá el cambio de fecha cuando se modifica en el objeto
Flag
subyacente.También puede quitar los atributos
x:Name
de todos los objetos XAML que se enlazan. Ahora se quita el campo privado asignado al control, lo que reduce el desorden de IntelliSense.