Vinculação de dados com tipos incompatíveis

Concluído

Às vezes, os dados que você está usando não correspondem ao tipo de dados da propriedade de controle que exibe os dados. Por exemplo, você pode ter um valor monetário armazenado em um decimal tipo que deseja exibir em um Label controle, formatado como uma moeda. Um exemplo mais complicado seria com o aplicativo de clima apresentado no módulo. Uma imagem deve ser exibida com base no valor da Sunny previsão do tempo ou Cloudy da enumeração, mas não é possível vincular o valor de enumeração da origem à propriedade image de um destino. Esta unidade analisa formas de converter dados.

Formatação de cadeia de caracteres

Uma incompatibilidade de tipo comum é um tipo intrínseco que você deseja exibir como uma cadeia de caracteres formatada. Como quando você deseja exibir partes de um DateTime valor ou formatar um decimal tipo como moeda.

Suponha que você queira exibir o valor devido em uma fatura e tenha essa propriedade em seu objeto de dados:

public decimal BillAmount { get; set; }

O valor devido acaba sendo de 22.0304. Você pode usar dois controles de rótulo para exibir algum texto e o valor em dólar, conforme demonstrado no trecho a seguir:

<HorizontalStackLayout>
    <Label Text="You owe" Margin="0,0,5,0" />
    <Label Text="{Binding BillAmount}" />
    <Label Text="to the bank" Margin="5,0,0,0" />
</HorizontalStackLayout>

Isso gera uma cadeia de caracteres para a interface do usuário que se parece com You owe 22.0304 to the bank, mas está faltando o símbolo de moeda e pode haver muitas ou poucas casas decimais com base na moeda local. Normalmente, você processaria o valor como uma cadeia de caracteres com o especificador de formato "C" (ou moeda) no código, assim:

string formattedBillAmount = string.Format("{0:C}", BillAmount);

Mas para usar a formatação na vinculação de dados, você precisa fazer com que o objeto de dados forneça essa cadeia de caracteres formatada como uma propriedade diferente ou intercete-a de alguma forma e formate-a você mesmo. Felizmente, as associações MAUI do .NET fornecem uma maneira de formatar cadeias de caracteres com a StringFormat propriedade de vinculação. A cadeia de caracteres de formato segue as mesmas regras que o String.Format método. Coloque a cadeia de caracteres de formato entre aspas simples para que o analisador XAML não seja confundido pelas chaves encaracoladas. O parâmetro 0 String format é o valor da propriedade processado pela ligação.

<Label Text="{Binding BillAmount, StringFormat='You owe {0:C} to the bank'}" />

Considere o seguinte XAML, que demonstra a exibição do uso das BillAmount duas maneiras:

<VerticalStackLayout Padding="10">
    <HorizontalStackLayout>
        <Label Text="You owe" Margin="0,0,5,0" />
        <Label Text="{Binding BillAmount}" />
        <Label Text="to the bank" Margin="5,0,0,0" />
    </HorizontalStackLayout>
    <HorizontalStackLayout>
        <Label Text="{Binding BillAmount, StringFormat='You owe {0:C} to the bank'}" />
    </HorizontalStackLayout>
</VerticalStackLayout>

A imagem a seguir ilustra o que a saída XAML produz na tela:

Captura de tela de um aplicativo .NET MAUI Android exibindo dois controles de rótulo diferentes com texto relacionado a uma fatura. O texto de um rótulo é formatado com a moeda USD.

O XAML usando a StringFormat propriedade binding é mais simples do que o outro XAML, e você tem acesso ao . O poderoso sistema de formatação de cadeias de caracteres da NET.

Conversão de tipo personalizada

A StringFormat propriedade binding é conveniente ao exibir um valor como uma cadeia de caracteres, mas não quando você deseja converter algo como um Color ou Image de outro tipo. Nesses casos, você precisa escrever um código de conversão personalizado.

Suponha que você esteja solicitando que o usuário escolha uma senha e queira usar uma cor na interface do usuário para indicar a força da senha. Existem três níveis de força: fraco, bom, forte. A força é baseada em quantos caracteres estão na senha. Para dar feedback imediato ao usuário sobre a força da senha, você deseja que o Entry plano de fundo do controle que contém a senha seja alterado com base na força. A imagem a seguir demonstra esses três níveis de força: fraco, bom e forte.

Captura de tela de um aplicativo .NET MAUI Android com três controles de entrada, cada um com um fundo colorido diferente.

Dos três controles de entrada na captura de tela, o primeiro tem quatro caracteres inseridos e apresenta um fundo vermelho. O segundo tem nove caracteres inseridos e apresenta um fundo amarelo. O último controle de entrada tem 15 caracteres e apresenta um fundo azul.

Estes níveis são atribuídos à Strength enumeração:

private enum Strength
{
    Weak,
    Good,
    Strong
}

Um objeto de dados é atribuído como a página , BindingContextque contém a força da senha com a PasswordStrength propriedade. À medida que o usuário digita uma senha, a PasswordStrength propriedade é alterada de acordo com o comprimento da senha. Como o objeto de dados contém a PasswordStrength propriedade, você vincula essa propriedade ao BackgroundColor do Entry controle:

<Entry BackgroundColor="{Binding PasswordStrength} ... />

No entanto, há um problema aqui. O PasswordStrength é do tipo Strength enquanto BackgroundColor é um Color. Estes tipos não são compatíveis entre si. O .NET MAUI fornece uma maneira de corrigir esses problemas de incompatibilidade de tipo, a propriedade da Converter ligação.

Um conversor de vinculação faz exatamente o que seu nome diz, converte entre a origem e o destino da vinculação. Os conversores são implementados através da IValueConverter interface.

Implementar IValueConverter

Você cria sua lógica de conversão em uma classe que implementa a IValueConverter interface. Normalmente, os nomes dessas classes terminam com o nome Converter para deixar claro seu propósito.

A IValueConverter interface define dois métodos:

  • Convert—Converte da propriedade da origem da vinculação para a propriedade da interface do usuário do destino da vinculação.

  • ConvertBack—Converte da propriedade UI do destino da vinculação de volta para a propriedade da origem da vinculação.

    Esse método raramente é usado e não é usado neste cenário. A maioria dos conversores lança um NotSupportedException para indicar que essa conversão não é suportada.

Aqui está o contrato da interface:

public interface IValueConverter
{
    object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture);
    object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture);
}

Lembre-se de que o cenário com o qual estamos trabalhando está vinculando a Entry.BackgroundColor propriedade à propriedade do objeto de PasswordStrength dados, que é uma Strength enumeração.

<Entry BackgroundColor="{Binding PasswordStrength} ... />

A Strength enumeração precisa ser convertida em um Colorarquivo . Assim, o conversor precisa avaliar qual Strength valor é fornecido, e retornar um diferente Color. O código a seguir demonstra essa conversão:

namespace MyProject.Converters;

class StrengthToColorConverter : IValueConverter
{
    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        return (Strength)value! switch
        {
            Strength.Weak => Colors.OrangeRed,
            Strength.Good => Colors.Yellow,
            Strength.Strong => Colors.LightBlue,
            _ => Colors.LightBlue
        };
    }

    public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) =>
        throw new NotImplementedException();
}

Vamos detalhar este código:

  • O Convert método tem quatro parâmetros. Geralmente, você pode descartar os dois últimos parâmetros, a menos que tenha um motivo específico para usá-los.
  • O value parâmetro contém o valor de entrada. Neste exemplo, é um Strength valor de enumeração.
  • O targetType parâmetro é ignorado. Mas você pode usar esse parâmetro para validar que o tipo de propriedade com a qual o conversor está sendo usado é um Colorarquivo . Isso é omitido neste exemplo para simplificar.
  • Uma expressão de switch é usada para retornar uma cor diferente com base no Strength valor.

Usar o conversor em XAML

Com a classe de conversor criada, você precisa criar uma instância dela e fazer referência a ela na ligação. A maneira padrão de instanciar o conversor é no dicionário de recursos do elemento raiz.

Primeiro, mapeie um namespace XML para o namespace .NET que contém o conversor. No exemplo de código a seguir, o cvt namespace XML mapeia para o MyProject.Converters namespace .NET:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:cvt="clr-namespace:MyProject.Converters"
             ...

Em seguida, crie uma instância no ContentPage.Resources:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:cvt="clr-namespace:MyProject.Converters"
             x:Class="MyProject.PasswordExample">
    <ContentPage.Resources>
        <cvt:StrengthToColorConverter x:Key="StrengthToColorConverter" />
    </ContentPage.Resources>

Agora, uma instância do conversor está no dicionário de recursos com a chave StrengthToColorConverter, que passa a ser o mesmo nome do tipo. Essa é uma maneira típica de nomear conversores, pois geralmente você tem apenas um único conversor que reutiliza em todo o XAML. Se você, por algum motivo, necessitasse de várias instâncias de conversor, as chaves teriam que ser diferentes entre elas.

Por último, consulte o conversor na ligação. Como o conversor está em um dicionário de recursos, você usa a extensão de {StaticResource} marcação para fazer referência a ele. O conversor é atribuído à Converter propriedade de ligação:

<Entry BackgroundColor="{Binding PasswordStrength, Converter={StaticResource StrengthToColorConverter}}" ... />

Verifique o seu conhecimento

1.

Para exibir e formatar um valor como uma cadeia de caracteres na vinculação de dados, qual é a melhor abordagem?

2.

Que tipo é usado na conversão de vinculação de dados?