Compartir vía


Propiedades enlazables

Las propiedades enlazables de la interfaz de usuario de aplicaciones multiplataforma de .NET (.NET MAUI) amplían la funcionalidad de propiedades de Common Language Runtime (CLR) mediante la copia de seguridad de una propiedad con un tipo BindableProperty, en lugar de con un campo. El propósito de las propiedades enlazables es proporcionar un sistema de propiedades que admita el enlace de datos, los estilos, las plantillas y los valores establecidos a través de relaciones de elementos primarios y secundarios. Además, las propiedades enlazables pueden proporcionar valores predeterminados, validación de valores de propiedad y devoluciones de llamada que supervisan los cambios de propiedad.

En las aplicaciones de .NET MAUI, las propiedades deben implementarse como propiedades enlazables para admitir una o varias de las siguientes características:

  • Actuar como una propiedad de destino válida para el enlace de datos. Para obtener más información sobre las propiedades de destino, consulte Enlaces básicos.
  • Establecer la propiedad a través de un estilo.
  • Proporcionar un valor de propiedad predeterminado distinto del predeterminado para el tipo de la propiedad.
  • Validar el valor de color de la propiedad.
  • Supervisar cambios de propiedad.

Entre los ejemplos de propiedades enlazables de .NET MAUI se incluyen Label.Text, Button.BorderRadius y StackLayout.Orientation. Cada propiedad enlazable tiene un campo public static readonly de tipo BindableProperty correspondiente que se expone en la misma clase y que es el identificador de la propiedad enlazable. Por ejemplo, el campo de identificador enlazable correspondiente para la propiedad Label.Text es Label.TextProperty.

Creación de una propiedad enlazable

El proceso para crear una propiedad enlazable es el siguiente:

  1. Crea una instancia BindableProperty con una de las sobrecargas del método BindableProperty.Create.
  2. Define descriptores de acceso de propiedad para la instancia BindableProperty.

Todas las instancias BindableProperty deben crearse en el subproceso de la interfaz de usuario. Esto significa que solo el código que se ejecuta en el subproceso de la interfaz de usuario puede obtener o establecer el valor de una propiedad enlazable. Sin embargo, BindableProperty se puede tener acceso a instancias desde otros subprocesos serializando el subproceso de la interfaz de usuario. Para obtener más información, consulta Ejecución del código en el subproceso de la interfaz de usuario.

Creación de una propiedad

Para crear una instancia BindableProperty, la clase contenedora debe derivar de la clase BindableObject. Sin embargo, la clase BindableObject es alta en la jerarquía de clases, por lo que la mayoría de las clases usadas para la funcionalidad de la interfaz de usuario admiten propiedades enlazables.

Se puede crear una propiedad enlazable declarando una propiedad public static readonly de tipo BindableProperty. La propiedad enlazable debe establecerse en el valor devuelto de una de las sobrecargas del método BindableProperty.Create. La declaración debe estar dentro del cuerpo de la clase derivada BindableObject, pero fuera de cualquier definición de miembro.

Como mínimo, se debe especificar un identificador al crear un objeto BindableProperty, junto con los parámetros siguientes:

  • Nombre del objeto BindableProperty.
  • Tipo de la propiedad.
  • El tipo del objeto propietario.
  • Valor predeterminado de la propiedad. Esto garantiza que la propiedad siempre devuelve un valor predeterminado específico cuando no se establece y puede ser diferente del valor predeterminado para el tipo de la propiedad. El valor predeterminado se restaurará cuando se llame al método ClearValue en la propiedad enlazable.

Importante

La convención de nomenclatura de las propiedades enlazables es que el identificador de propiedad enlazable debe coincidir con el nombre de propiedad especificado en el método Create, con "Property" anexado a él.

El código siguiente muestra un ejemplo de una propiedad enlazable, con un identificador y valores para los cuatro parámetros necesarios:

public static readonly BindableProperty IsExpandedProperty =
  BindableProperty.Create ("IsExpanded", typeof(bool), typeof(Expander), false);

Esto crea una instancia BindableProperty llamada IsExpandedProperty del tipo bool. La propiedad es propiedad de la clase Expander y tiene un valor predeterminado de false.

Nota:

Expander es un control en .NET MAUI Community Toolkit. Para más información, vea Expander.

Opcionalmente, al crear una instancia BindableProperty, se pueden especificar los parámetros siguientes:

  • Modo de enlace. Se usa para especificar la dirección en la que se propagarán los cambios de valor de propiedad. En el modo de enlace predeterminado, los cambios se propagarán del origen al destino. Para obtener más información, consulte enlaces básicos.
  • Un delegado de validación que se invocará cuando se establezca el valor de propiedad. Para obtener más información, consulte Devoluciones de llamada de validación.
  • Un delegado de cambio de propiedad que se invocará cuando el valor de propiedad haya cambiado. Para más información, consulta Detectar cambios de propiedad.
  • Un delegado que cambia de propiedad que se invocará cuando cambie el valor de propiedad. Este delegado tiene la misma firma que el delegado de cambio de propiedad.
  • Un delegado del valor de coerción que se invocará cuando el valor de propiedad haya cambiado. Para obtener más información, consulta Devoluciones de llamada del valor de coerción.
  • Un objeto Func que se usa para inicializar un valor de propiedad predeterminado. Para obtener más información, consulta Crear un valor predeterminado con Func.

Creación de descriptores de acceso

Los descriptores de acceso de propiedad son necesarios para usar la sintaxis de propiedad para acceder a una propiedad enlazable. El descriptor de acceso Get debe devolver el valor contenido en la propiedad enlazable correspondiente. Esto se puede lograr llamando al método GetValue, pasando el identificador de propiedad enlazable en el que se va a obtener el valor y, a continuación, convirtiendo el resultado en el tipo necesario. El descriptor de acceso Set debe establecer el valor de propiedad enlazable correspondiente. Esto se puede lograr llamando al método SetValue, pasando el identificador de propiedad enlazable en el que se va a establecer el valor y el valor que se va a establecer.

El siguiente ejemplo de código muestra cómo obtener acceso a la propiedad enlazable IsExpanded:

public bool IsExpanded
{
    get => (bool)GetValue(IsExpandedProperty);
    set => SetValue(IsExpandedProperty, value);
}

Consumo de una propiedad enlazable

Una vez creada una propiedad enlazable, se puede consumir desde XAML o código. En XAML, esto se logra mediante la declaración de un espacio de nombres con un prefijo, con la declaración de espacio de nombres que indica el nombre del espacio de nombres CLR y, opcionalmente, un nombre de ensamblado. Para obtener más información, consulta Espacio de nombres de XAML.

En el ejemplo de código siguiente se muestra un espacio de nombres XAML para un tipo personalizado que contiene una propiedad enlazable, que se define dentro del mismo ensamblado que el código de aplicación que hace referencia al tipo personalizado:

<ContentPage ... xmlns:local="clr-namespace:DataBindingDemos" ...>
  ...
</ContentPage>

La declaración de espacio de nombres se usa al establecer la propiedad enlazable IsExpanded, como se muestra en el siguiente ejemplo de código XAML:

<Expander IsExpanded="true">
    ...
</Expander>

El código de C# equivalente se muestra en el ejemplo de código siguiente:

Expander expander = new Expander
{
    IsExpanded = true
};

Escenarios avanzados

Al crear una instancia BindableProperty, hay una serie de parámetros opcionales que se pueden establecer para habilitar escenarios avanzados de propiedades enlazables. En esta sección se exploran estos escenarios.

Detección de cambios de propiedad

Un método de devolución de llamada de cambio de propiedad static se puede registrar con una propiedad enlazable especificando el parámetro propertyChanged para el método BindableProperty.Create. El método de devolución de llamada especificado se invocará cuando el valor de propiedad enlazable haya cambiado.

En el ejemplo de código siguiente se muestra cómo la propiedad enlazable IsExpanded registra el método OnIsExpandedChanged como un método de devolución de llamada de cambio de propiedad:

public static readonly BindableProperty IsExpandedProperty =
    BindableProperty.Create(nameof(IsExpanded), typeof(bool), typeof(Expander), false, propertyChanged: OnIsExpandedChanged);
...

static void OnIsExpandedChanged (BindableObject bindable, object oldValue, object newValue)
{
  // Property changed implementation goes here
}

En el método de devolución de llamada de cambio de propiedad, el parámetro BindableObject se usa para indicar qué instancia de la clase propietaria ha notificado un cambio y los valores de los dos parámetros object representan los valores antiguos y nuevos de la propiedad enlazable.

Devoluciones de llamada de validación

Un método de devolución de llamada de validación static se puede registrar con una propiedad enlazable especificando el parámetro validateValue para el método BindableProperty.Create. El método de devolución de llamada especificado se invocará cuando se establezca el valor de la propiedad enlazable.

En el ejemplo de código siguiente se muestra cómo la propiedad enlazable Angle registra el método IsValidValue como un método de devolución de llamada de validación:

public static readonly BindableProperty AngleProperty =
    BindableProperty.Create("Angle", typeof(double), typeof(MainPage), 0.0, validateValue: IsValidValue);
...

static bool IsValidValue(BindableObject view, object value)
{
    double result;
    double.TryParse(value.ToString(), out result);
    return (result >= 0 && result <= 360);
}

Las devoluciones de llamada de validación se proporcionan con un valor y deben devolver true si el valor es válido para la propiedad; de lo contrario false. Se producirá una excepción si una devolución de llamada de validación devuelve false, que debes solucionar. Un uso típico de un método de devolución de llamada de validación restringe los valores de enteros o dobles cuando se establece la propiedad enlazable. Por ejemplo, el método IsValidValue comprueba que el valor de propiedad es double comprendido entre 0 y 360.

Devoluciones de llamada del valor de coerción

Un método de devoluciones de llamada del valor de coerción static se puede registrar con una propiedad enlazable especificando el parámetro coerceValue para el método BindableProperty.Create. El método de devolución de llamada especificado se invocará cuando el valor de propiedad enlazable esté a punto de cambiar, de modo que puedas ajustar el nuevo valor antes de que se aplique.

Importante

Además de ser desencadenadas por el sistema de propiedades, puedes invocar devoluciones de llamada de coerción de valor desde el código. El tipo BindableObject tiene un método CoerceValue al que se puede llamar para forzar una reevaluación del valor de su argumento BindableProperty invocando su devolución de llamada del valor de coerción.

Las devoluciones de llamada del valor de coerción se usan para forzar una reevaluación de una propiedad enlazable cuando el valor de propiedad está a punto de cambiar. Por ejemplo, se puede usar una devolución de llamada del valor de coerción para asegurarse de que el valor de una propiedad enlazable no es mayor que el valor de otra propiedad enlazable.

En el ejemplo de código siguiente se muestra cómo la propiedad enlazable Angle registra el método CoerceAngle como un método de devolución de llamada de valor de coerción:

public static readonly BindableProperty AngleProperty =
    BindableProperty.Create("Angle", typeof(double), typeof(MainPage), 0.0, coerceValue: CoerceAngle);
public static readonly BindableProperty MaximumAngleProperty =
    BindableProperty.Create("MaximumAngle", typeof(double), typeof(MainPage), 360.0, propertyChanged: ForceCoerceValue);
...

static object CoerceAngle(BindableObject bindable, object value)
{
    MainPage page = bindable as MainPage;
    double input = (double)value;

    if (input > page.MaximumAngle)
    {
        input = page.MaximumAngle;
    }

    return input;
}

static void ForceCoerceValue(BindableObject bindable, object oldValue, object newValue)
{
    bindable.CoerceValue(AngleProperty);
}

El método CoerceAngle comprueba el valor de la propiedad MaximumAngle y, si el valor de la propiedad Angle es mayor que él, convierte el valor en el valor de propiedad MaximumAngle. Además, cuando la propiedad MaximumAngle cambia la devolución de llamada del valor de coerción se invoca en la propiedad Angle llamando al método CoerceValue.

Crear un valor predeterminado con Func

Se puede usar un objeto Func para inicializar el valor predeterminado de una propiedad enlazable, como se muestra en el ejemplo siguiente:

public static readonly BindableProperty DateProperty =
    BindableProperty.Create ("Date", typeof(DateTime), typeof(MyPage), default(DateTime), BindingMode.TwoWay, defaultValueCreator: bindable => DateTime.Today);

El parámetro defaultValueCreator se establece en un objeto Func que devuelve un objeto DateTime que representa la fecha de hoy.