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 exercise1 > final 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 INotifyPropertyChanged. Este código no pretende ser realista. Simplemente es una manera fácil de que vea la necesidad de las notificaciones de cambios.

  1. Abra MainPage.xaml.cs y busque el método OnShow.

  2. Agregue un año a la propiedad Flag.DateAdopted; para ello llame a .AddYears(1) y asigne el valor devuelto a la propiedad DateAdopted. Tenga en cuenta que tendrá que asignar la propiedad, ya que DateTime 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");
    }
    
  3. 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.

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

  1. Abra Flag.cs en el proyecto FlagData.

  2. Modifique la clase Flag para implementar System.ComponentModel.INotifyPropertyChanged. La implementación requiere un único evento denominado PropertyChanged.

    public class Flag : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        ...
    }
    
  3. Cree un método auxiliar denominado RaisePropertyChanged para generar el evento PropertyChanged. El método acepta un parámetro string 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 nombres System.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 compilador nameof() 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 para null, 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));
        }
    }
    
  4. Convierta la propiedad implementada automáticamente DateAdopted existente en una propiedad de campo de respaldo. Llame al método RaisePropertyChanged 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();
            }
        }
    }
    
  5. 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.

  6. Ejecute la aplicación, desplácese hacia abajo hasta el control DatePicker 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.

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