Compartilhar via


Associação de dados do Windows detalhadamente

Este artigo descreve os recursos de associação de dados do WinUI usando as APIs no namespace Microsoft.UI.Xaml.Data.

Observação

Este tópico descreve os recursos de associação de dados em detalhes. Para obter uma breve e prática introdução, confira a visão geral da associação de dados.

APIs importantes

Introdução

A associação de dados é uma técnica que permite que a interface do usuário do aplicativo exiba e sincronize dados com eficiência. Ao separar as preocupações de dados das preocupações com a interface do usuário, ela simplifica o design do aplicativo, aprimora a legibilidade e melhora a manutenção.

Você pode usar a associação de dados para simplesmente exibir valores de uma fonte de dados quando a interface do usuário for mostrada pela primeira vez, mas não responder a alterações nesses valores. Esse modo de associação é chamado única vez e funciona bem para um valor que não é alterado durante o tempo de execução. Como alternativa, você pode optar por "observar" os valores e atualizar a interface do usuário quando eles forem alterados. Esse modo é chamado de unidirecional e funciona bem para dados somente leitura. Por fim, você pode optar por observar e atualizar, para que as alterações feitas pelo usuário em valores na interface do usuário sejam automaticamente enviadas de volta para a fonte de dados. Esse modo é chamado de bidirecional e funciona bem para dados de leitura e gravação. Aqui estão alguns exemplos.

  • Você pode usar o modo único para associar uma imagem à foto do usuário atual.
  • Você pode usar o modo unidirecional para associar um ListView a uma coleção de artigos de notícias em tempo real agrupados por seção de jornal.
  • Você pode usar o modo bidirecional para associar um TextBox ao nome de um cliente em um formulário.

Independentemente do modo, há dois tipos de associação e você normalmente declara ambos na marcação da interface do usuário. Você pode optar por usar a extensão de marcação {x:Bind} ou a extensão de marcação {Binding}. Você pode até mesmo usar uma mistura dos dois no mesmo aplicativo, mesmo no mesmo elemento de interface do usuário. {x:Bind} era novo na UWP para Windows 10 e tem melhor desempenho. Todos os detalhes descritos neste tópico se aplicam a ambos os tipos de associação, a menos que digamos explicitamente o contrário.

Aplicativos de exemplo UWP que demonstram {x:Bind}

Aplicativos de exemplo UWP que demonstram {Binding}

Cada associação envolve essas partes

  • Uma origem de associação. Essa fonte fornece os dados para a associação. Pode ser uma instância de qualquer classe que tenha membros cujos valores você deseja exibir na interface do usuário.
  • Um destino de associação. Esse destino é uma DependencyProperty do FrameworkElement em sua interface do usuário que exibe os dados.
  • Um objeto de associação. Esse objeto transfere valores de dados da origem para o destino e, opcionalmente, do destino de volta para a origem. O objeto de associação é criado no tempo de carregamento XAML da extensão de marcação {x:Bind} ou {Binding} .

Nas seções a seguir, você examinará mais de perto a origem da associação, o destino de associação e o objeto de associação. As seções vinculam junto com o exemplo de associar o conteúdo de um botão a uma propriedade de cadeia de caracteres chamada NextButtonText, que pertence a uma classe chamada HostViewModel.

Origem da associação

Aqui está uma implementação básica de uma classe que você pode usar como uma fonte de associação.

public class HostViewModel
{
    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText { get; set; }
}

Essa implementação de HostViewModel, e sua propriedade NextButtonText, funciona apenas para associação única. Mas associações unidirecionais e bidirecionais são extremamente comuns. Nesses tipos de associação, a interface do usuário é atualizada automaticamente em resposta a alterações nos valores de dados da fonte de associação. Para que esses tipos de associação funcionem corretamente, você precisa tornar a origem da associação observável ao objeto de associação. Portanto, em nosso exemplo, se você quiser associar unidirecional ou bidirecional à propriedade NextButtonText, as alterações que ocorrerem em tempo de execução para o valor dessa propriedade devem ser observáveis pelo objeto de associação.

Uma maneira de fazer isso é derivar a classe que representa a fonte de associação de DependencyObject e expor um valor de dados por meio de um DependencyProperty*. É assim que um FrameworkElement se torna observável. A FrameworkElement é uma boa origem de associação pronta para uso.

Uma maneira mais leve de tornar uma classe observável e necessária para classes que já têm uma classe base é implementar System.ComponentModel.INotifyPropertyChanged. Essa abordagem envolve a implementação de um único evento chamado PropertyChanged. Um exemplo de uso HostViewModel é mostrado no código a seguir.

...
using System.ComponentModel;
using System.Runtime.CompilerServices;
...
public class HostViewModel : INotifyPropertyChanged
{
    private string nextButtonText;

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return nextButtonText; }
        set
        {
            nextButtonText = value;
            OnPropertyChanged();
        }
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Agora a NextButtonText propriedade é observável. Quando você cria uma associação unidirecional ou bidirecional para essa propriedade (mostraremos como mais tarde), o objeto de associação resultante assina o PropertyChanged evento. Quando esse evento é acionado, o manipulador do objeto de associação recebe um argumento que contém o nome da propriedade que foi alterada. É assim que o objeto de associação sabe qual valor da propriedade deve ser lido novamente.

Para que você não precise implementar o padrão mostrado anteriormente várias vezes, se estiver usando C#, poderá derivar da BindableBase classe base que encontrará no exemplo QuizGame (na pasta "Comum"). Aqui está um exemplo de como isso parece.

public class HostViewModel : BindableBase
{
    private string nextButtonText;

    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return nextButtonText; }
        set { SetProperty(ref nextButtonText, value); }
    }
}

Gerar o PropertyChanged evento com um argumento String.Empty ou null indica que todas as propriedades não indexadoras no objeto devem ser relidas. Você pode gerar o evento para indicar que as propriedades do indexador no objeto foram alteradas usando um argumento de "Item[indexador]" para indexadores específicos (em que o indexador é o valor do índice) ou um valor de "Item[]" para todos os indexadores.

Você pode tratar uma fonte de associação como um único objeto cujas propriedades contêm dados ou como uma coleção de objetos. No código C#, você pode associar uma vez a um objeto que implementa a Lista<T> para exibir uma coleção que não é alterada em tempo de execução. Para uma coleção observável (observando quando os itens são adicionados e removidos da coleção), associe unidirecionalmente a ObservableCollection<T> em vez disso. Para associar às suas próprias classes de coleção, use as diretrizes na tabela a seguir.

Scenario C# (CLR) C++/WinRT
Associar a um objeto. Pode ser qualquer objeto. Pode ser qualquer objeto.
Obtenha notificações de alteração de propriedade de um objeto associado. O objeto deve implementar INotifyPropertyChanged. O objeto deve implementar INotifyPropertyChanged.
Associar a uma coleção. Lista<T> IVector de IInspectable ou IBindableObservableVector. Consulte controles de itens XAML; associe a uma coleção C++/WinRT e coleções com C++/WinRT.
Obtenha notificações de alteração de coleção de uma coleção associada. ObservableCollection<T> IObservableVector de IInspectable. Por exemplo, winrt::single_threaded_observable_vector<T>.
Implemente uma coleção que dê suporte à associação. Estenda List<T> ou implemente IList, IList<Object>, IEnumerable, ou IEnumerable<Object>. Associação a genérico IList<T> e IEnumerable<T> não é suportada. Implemente IVector do IInspectable. Consulte controles de itens XAML; associe a uma coleção C++/WinRT e coleções com C++/WinRT.
Implemente uma coleção que dê suporte a notificações de alteração de coleção. Estenda ObservableCollection<T> ou implemente IList (não genérico) e INotifyCollectionChanged. Implemente IObservableVector de IInspectable ou IBindableObservableVector.
Implemente uma coleção que dê suporte ao carregamento incremental. Estenda ObservableCollection<T> ou implemente IList (não genérico) e INotifyCollectionChanged. Além disso, implemente ISupportIncrementalLoading. Implemente IObservableVector de IInspectable ou IBindableObservableVector. Além disso, implemente ISupportIncrementalLoading

Você pode associar controles de lista a fontes de dados arbitrariamente grandes e ainda obter alto desempenho usando o carregamento incremental. Por exemplo, você pode associar controles de lista aos resultados da consulta de imagem do Bing sem precisar carregar todos os resultados de uma só vez. Em vez disso, você carrega apenas alguns resultados imediatamente e carrega resultados adicionais conforme necessário. Para dar suporte ao carregamento incremental, você deve implementar ISupportIncrementalLoading em uma fonte de dados que dê suporte a notificações de alteração de coleção. Quando o mecanismo de associação de dados solicita mais dados, sua fonte de dados deve fazer as solicitações apropriadas, integrar os resultados e, em seguida, enviar as notificações apropriadas para atualizar a interface do usuário.

Destino de associação

Nos dois exemplos a seguir, a propriedade Button.Content é o destino de associação. Seu valor é definido como uma extensão de marcação que declara o objeto de associação. O primeiro exemplo mostra {x:Bind}, e o segundo exemplo mostra {Binding}. Declarar associações na marcação é uma prática comum porque é conveniente, legível e suportada por ferramentas. No entanto, se precisar, você poderá evitar a marcação e, de forma imperativa (programática), criar uma instância da classe Binding .

<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />

Se você estiver usando C++/WinRT, precisará adicionar o atributo BindableAttribute a qualquer classe de runtime com a qual deseja usar a extensão de marcação {Binding} .

Importante

Se você estiver usando C++/WinRT, o atributo BindableAttribute estará disponível com o SDK do Aplicativo do Windows. Sem esse atributo, você precisa implementar as interfaces ICustomPropertyProvider e ICustomProperty para poder usar a extensão de marcação {Binding} .

Objeto binding declarado usando {x:Bind}

Antes de criar sua marcação {x:Bind}, você precisa expor sua classe de fonte de ligação a partir da classe que representa a página de marcação. Adicione uma propriedade (do tipo HostViewModel nesse caso) à janela da classe MainWindow.

namespace DataBindingInDepth
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
            ViewModel = new HostViewModel();
        }
    
        public HostViewModel ViewModel { get; set; }
    }
}

Depois de adicionar a propriedade, você pode examinar mais de perto a marcação que declara o objeto de associação. O exemplo a seguir usa o mesmo Button.Content destino de associação que você viu na seção "Destino de associação" anteriormente. Ele mostra o destino de associação vinculado à propriedade HostViewModel.NextButtonText.

<!-- MainWindow.xaml -->
<Window x:Class="DataBindingInDepth.MainWindow" ... >
    <Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Window>

Observe o valor que você especifica para Path. A janela interpreta esse valor em seu próprio contexto. Nesse caso, o caminho começa referenciando a ViewModel propriedade que você acabou de adicionar à MainWindow página. Essa propriedade retorna uma HostViewModel instância, para que você possa fazer ponto nesse objeto para acessar a HostViewModel.NextButtonText propriedade. Especifica Mode para substituir o padrão {x:Bind} de execução única.

A propriedade Path dá suporte a uma variedade de opções de sintaxe para vincular a propriedades aninhadas, propriedades anexadas e indexadores inteiros e de cadeia de texto. Para obter mais informações, consulte Sintaxe de caminho de propriedade. A associação a indexadores de cadeia de caracteres fornece o efeito da associação a propriedades dinâmicas sem a necessidade de implementar ICustomPropertyProvider. Para outras configurações, consulte a extensão de marcação {x:Bind}.

Para ilustrar que a HostViewModel.NextButtonText propriedade é observável, adicione um Click manipulador de eventos ao botão e atualize o valor de HostViewModel.NextButtonText. Crie, execute e clique no botão para ver o valor da atualização do Content botão.

// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    ViewModel.NextButtonText = "Updated Next button text";
}

Observação

As alterações em TextBox.Text são enviadas para uma fonte associada bidirecional quando o TextBox perde o foco, e não após cada pressionamento de tecla do usuário.

DataTemplate e x:DataType

Dentro de um DataTemplate (se você usá-lo como modelo de item, conteúdo ou cabeçalho), o valor de Path não é interpretado no contexto da janela. Em vez disso, ele funciona no contexto do objeto de dados que você está modelando. Ao usar {x:Bind} em um modelo de dados, você pode validar suas associações em tempo de compilação e gerar um código eficiente para elas. Para fazer isso, é DataTemplate necessário declarar o tipo de seu objeto de dados usando x:DataType. O exemplo a seguir pode ser usado como um ItemTemplate controle de itens associado a uma coleção de SampleDataGroup objetos.

<DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{x:Bind Title}"/>
      <TextBlock Text="{x:Bind Description}"/>
    </StackPanel>
  </DataTemplate>

Objetos com tipo fraco em seu Caminho

Suponha que você tenha um tipo nomeado SampleDataGroup que implemente uma propriedade de cadeia de caracteres chamada Title. Você também tem uma propriedade MainWindow.SampleDataGroupAsObject do tipo object, mas na verdade retorna uma instância de SampleDataGroup. A associação <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> resulta em um erro de compilação porque a Title propriedade não foi encontrada no tipo object. Para corrigir esse erro, adicione uma conversão à sintaxe Path assim: <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Aqui está outro exemplo em que Element é declarado como object , mas na verdade é um TextBlock: <TextBlock Text="{x:Bind Element.Text}"/>. Um casting corrige o problema: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>.

Se seus dados forem carregados de forma assíncrona

As classes parciais para suas janelas geram o código para dar suporte a {x:Bind} em tempo de compilação. Você pode encontrar esses arquivos em sua obj pasta, com nomes como (para C#) <view name>.g.cs. O código gerado inclui um manipulador para o evento de carregamento da janela. Esse handler chama o método Initialize em uma classe gerada que representa as vinculações da janela. Initialize chama Update para iniciar a movimentação de dados entre a fonte de associação e o destino. Loading é gerado pouco antes da primeira passagem de medida da janela ou do controle do usuário. Se os dados forem carregados de forma assíncrona, talvez não estejam prontos quando Initialize for chamado. Depois de carregar os dados, você pode forçar a inicialização das associações únicas chamando this.Bindings.Update();. Se você precisar apenas de associações únicas para dados carregados de forma assíncrona, é muito mais barato inicializá-los dessa maneira do que ter associações unidirecionais e escutar alterações. Se os dados não passarem por alterações refinadas e provavelmente forem atualizados como parte de uma ação específica, você poderá fazer suas associações uma vez e forçar uma atualização manual a qualquer momento com uma chamada para Update.

Observação

{x:Bind} não é adequado para cenários de ligação tardia, como navegar na estrutura de dicionário de um objeto JSON, nem para duck typing. "Digitação de pato" é uma forma fraca de digitação baseada em correspondências léxicas em nomes de propriedades (como em, "se ele anda, nada e charlatões como um pato, então é um pato"). Com a digitação de pato, uma associação à Age propriedade seria igualmente satisfeita com um Person ou um Wine objeto (supondo que esses tipos cada um tinha uma Age propriedade). Para esses cenários, use a {Binding} extensão de marcação.

Objeto de vínculo declarado usando {Binding}

Se você usar C++/WinRT, adicione o atributo BindableAttribute a qualquer classe de runtime à qual você deseja associar ao usar a extensão de marcação {Binding} . Para usar {x:Bind}, você não precisa desse atributo.

// HostViewModel.idl
// Add this attribute:
[Microsoft.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
    HostViewModel();
    String NextButtonText;
}

Importante

Se você estiver usando C++/WinRT, o atributo BindableAttribute estará disponível com o SDK do Aplicativo do Windows. Sem esse atributo, você precisa implementar as interfaces ICustomPropertyProvider e ICustomProperty para poder usar a extensão de marcação {Binding} .

Por padrão, {Binding} pressupõe que você esteja vinculando ao DataContext da janela de marcação. Portanto, defina o DataContext da sua janela para ser uma instância da sua classe de origem de associação (do tipo HostViewModel nesse caso). O exemplo a seguir mostra a marcação que declara o objeto de associação. Ele usa o mesmo Button.Content destino de associação usado na seção "Destino de associação" anteriormente e se associa à propriedade HostViewModel.NextButtonText.

<Window xmlns:viewmodel="using:DataBindingInDepth" ... >
    <Window.DataContext>
        <viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
    </Window.DataContext>
    ...
    <Button Content="{Binding Path=NextButtonText}" ... />
</Window>
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    viewModelInDataContext.NextButtonText = "Updated Next button text";
}

Observe o valor especificado para Path. O DataContext da janela interpreta esse valor, que neste exemplo é definido como uma instância de HostViewModel. O caminho faz referência à HostViewModel.NextButtonText propriedade. Você pode omitir Mode, porque o padrão {Binding} de unidirecional funciona aqui.

O valor padrão de DataContext para um elemento de interface do usuário é o valor herdado de seu pai. Você pode substituir esse padrão definindo DataContext explicitamente, e ele será herdado pelos filhos por padrão. Definir DataContext explicitamente em um elemento é útil quando você deseja ter várias associações que usam a mesma origem.

Um objeto de associação tem uma Source propriedade, que usa como padrão o DataContext do elemento de interface do usuário no qual a associação é declarada. Você pode substituir esse padrão definindo Source, RelativeSourceou ElementName explicitamente na associação (consulte {Binding} para obter detalhes).

Dentro de um DataTemplate, o DataContext é automaticamente definido como o objeto de dados que está sendo modelo. O exemplo a seguir pode ser usado como um ItemTemplate controle de itens associado a uma coleção de qualquer tipo que tenha propriedades de cadeia de caracteres nomeadas Title e Description.

<DataTemplate x:Key="SimpleItemTemplate">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{Binding Title}"/>
      <TextBlock Text="{Binding Description"/>
    </StackPanel>
  </DataTemplate>

Observação

Por padrão, as alterações em TextBox.Text são enviadas para uma fonte associada bidirecional quando o TextBox perde o foco. Para fazer com que as alterações sejam enviadas após cada pressionamento de tecla do usuário, definido UpdateSourceTrigger como PropertyChanged na associação na marcação. Você também pode assumir completamente o controle de quando as alterações são enviadas para a origem definindo UpdateSourceTrigger como Explicit. Em seguida, você manipula eventos na caixa de texto (normalmente TextBox.TextChanged), chama GetBindingExpression no destino para obter um objeto BindingExpression e, por fim, chama BindingExpression.UpdateSource para atualizar programaticamente a fonte de dados.

A propriedade Path dá suporte a uma variedade de opções de sintaxe para associar a propriedades aninhadas, propriedades anexadas e indexadores inteiros e de cadeia de caracteres. Para obter mais informações, consulte Sintaxe de caminho de propriedade. A associação a indexadores de cadeia de caracteres fornece o efeito da associação a propriedades dinâmicas sem a necessidade de implementar ICustomPropertyProvider. A propriedade ElementName é útil para associação elemento a elemento. A propriedade RelativeSource tem vários usos, um dos quais é uma alternativa mais poderosa à associação de modelo dentro de um ControlTemplate. Para outras configurações, consulte a extensão de marcação {Binding} e a classe Binding .

E se a origem e o destino não forem do mesmo tipo?

Se você quiser controlar a visibilidade de um elemento de interface do usuário com base no valor de uma propriedade booliana ou se quiser renderizar um elemento de interface do usuário com uma cor que seja uma função do intervalo ou tendência de um valor numérico, ou se você quiser exibir um valor de data e/ou hora em uma propriedade de elemento de interface do usuário que espera uma cadeia de caracteres, em seguida, você precisa converter valores de um tipo para outro. Há casos em que a solução certa é expor outra propriedade do tipo certo da classe de origem de associação e manter a lógica de conversão encapsulada e testável lá. Mas essa solução não é flexível ou escalonável quando você tem grandes números ou grandes combinações de propriedades de origem e destino. Nesse caso, você tem algumas opções:

  • Se estiver usando {x:Bind} , você poderá associar diretamente a uma função para fazer essa conversão
  • Ou você pode especificar um conversor de valor que é um objeto projetado para executar a conversão

Conversores de valor

Aqui está um conversor de valor, adequado para uma associação unidirecional ou unidirecional, que converte um valor DateTime em um string valor que contém o mês. A classe implementa IValueConverter.

public class DateToStringConverter : IValueConverter
{
    // Define the Convert method to convert a DateTime value to 
    // a month string.
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        // value is the data from the source object.
        DateTime thisDate = (DateTime)value;
        int monthNum = thisDate.Month;
        string month;
        switch (monthNum)
        {
            case 1:
                month = "January";
                break;
            case 2:
                month = "February";
                break;
            default:
                month = "Month not found";
                break;
        }
        // Return the value to pass to the target.
        return month;
    }

    // ConvertBack is not implemented for a OneWay binding.
    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

E aqui está como você consome esse conversor de valor em sua marcação de objeto de associação.

<UserControl.Resources>
  <local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>
...
<TextBlock Grid.Column="0" 
  Text="{x:Bind ViewModel.Month, Converter={StaticResource Converter1}}"/>
<TextBlock Grid.Column="0" 
  Text="{Binding Month, Converter={StaticResource Converter1}}"/>

O mecanismo de associação chamará os métodos Convert e ConvertBack se o parâmetro Converter for definido para a associação. Quando os dados são passados da origem, o mecanismo de associação chama Convert e passa os dados retornados para o destino. Quando os dados são passados do destino (para uma associação bidirecional), o mecanismo de associação chama ConvertBack e passa os dados retornados para a origem.

O conversor também tem parâmetros opcionais: ConverterLanguage, que permite especificar o idioma a ser usado na conversão, e ConverterParameter, que permite passar um parâmetro para a lógica de conversão. Para obter um exemplo que usa um parâmetro de conversor, consulte IValueConverter.

Observação

Se houver um erro na conversão, não gere uma exceção. Em vez disso, retorne DependencyProperty.UnsetValue, que interromperá a transferência de dados.

Para exibir um valor padrão a ser usado sempre que a origem da associação não puder ser resolvida, defina a FallbackValue propriedade no objeto de associação na marcação. Isso é útil para lidar com erros de conversão e formatação. Também é útil associar a propriedades de origem que podem não existir em todos os objetos em uma coleção associada de tipos heterogêneos.

Se você associar um controle de texto a um valor que não seja uma cadeia de caracteres, o mecanismo de associação de dados converterá o valor em uma cadeia de caracteres. Se o valor for um tipo de referência, o mecanismo de associação de dados recuperará o valor da cadeia de caracteres chamando ICustomPropertyProvider.GetStringRepresentation ou IStringable.ToString , se disponível, e chamará Object.ToString. No entanto, observe que o mecanismo de associação ignorará qualquer ToString implementação que oculte a implementação da classe base. Em vez disso, as implementações de subclasse devem substituir o método de classe ToString base. Da mesma forma, em idiomas nativos, todos os objetos gerenciados parecem implementar ICustomPropertyProvider e IStringable. No entanto, todas as chamadas GetStringRepresentationIStringable.ToString são roteadas para Object.ToString ou uma substituição desse método e nunca para uma nova ToString implementação que oculta a implementação da classe base.

Observação

O Kit de Ferramentas da Comunidade do Windows fornece um BoolToVisibilityConverter. O conversor mapeia true para o Visible valor de enumeração e false para Collapsed que você possa associar uma Visibility propriedade a um booliano sem criar um conversor. Para usar o conversor, seu projeto deve adicionar o pacote NuGet CommunityToolkit.WinUI.Converters .

Associação de função em {x:Bind}

{x:Bind} permite que a etapa final em um caminho de associação seja uma função. Use esse recurso para executar conversões ou criar associações que dependem de mais de uma propriedade. Para obter mais informações, consulte Funções em x:Bind.

Associação elemento a elemento

Você pode associar a propriedade de um elemento XAML à propriedade de outro elemento XAML. Aqui está um exemplo de como essa vinculação aparece na marcação.

<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />

Dicionários de recursos com {x:Bind}

A extensão de marcação {x:Bind} depende da geração de código, portanto, ela precisa de um arquivo code-behind contendo um construtor que chama InitializeComponent (para inicializar o código gerado). Para reutilizar o dicionário de recursos, instancie seu tipo (de modo que InitializeComponent seja chamado) em vez de referenciar seu nome de arquivo. Aqui está um exemplo do que fazer se você tiver um dicionário de recursos existente e quiser usá-lo {x:Bind} .

<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>
// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI.Xaml.Data;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
    }
}
<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Window.Resources>
        <ResourceDictionary>
            .... 
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
</Window>

Misturando {x:Bind} e {Binding} em um estilo reutilizável

O exemplo anterior mostrou como usar {x:Bind} em DataTemplates. Você também pode criar estilos reutilizáveis que combinam extensões de marcação {x:Bind} e {Binding}. Essa combinação é útil quando você deseja associar algumas propriedades a valores conhecidos em tempo de compilação usando {x:Bind} e outras propriedades para valores DataContext de runtime usando {Binding}.

O exemplo a seguir mostra como criar um estilo de botão reutilizável que usa as duas abordagens de associação:

TemplatesResourceDictionary.xaml

<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <!-- DataTemplate using x:Bind -->
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
    
    <!-- Style that mixes x:Bind and Binding -->
    <Style x:Key="CustomButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
        <Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="Margin" Value="4"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="RootBorder"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="4">
                        <StackPanel Orientation="Horizontal" 
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                            <!-- x:Bind to a static property or page-level property -->
                            <Ellipse Width="8" Height="8" 
                                     Fill="{x:Bind DefaultIndicatorBrush}" 
                                     Margin="0,0,8,0"/>
                            <!-- Binding to DataContext -->
                            <ContentPresenter x:Name="ContentPresenter"
                                              Content="{TemplateBinding Content}"
                                              Foreground="{TemplateBinding Foreground}"
                                              FontSize="{TemplateBinding FontSize}"/>
                        </StackPanel>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="PointerOver">
                                    <VisualState.Setters>
                                        <!-- Binding to DataContext for hover color -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{Binding ButtonHoverBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <VisualState.Setters>
                                        <!-- x:Bind to a compile-time known resource -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{x:Bind DefaultPressedBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

TemplatesResourceDictionary.xaml.cs

// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
        
        // Properties for x:Bind - these are compile-time bound
        public SolidColorBrush DefaultIndicatorBrush { get; } = 
            new SolidColorBrush(Colors.Green);
            
        public SolidColorBrush DefaultPressedBrush { get; } = 
            new SolidColorBrush(Colors.DarkGray);
    }
}

Uso em MainWindow.xaml com um ViewModel que fornece valores de runtime:

<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <Grid.DataContext>
            <examplenamespace:ButtonThemeViewModel/>
        </Grid.DataContext>
        
        <StackPanel Margin="20">
            <!-- These buttons use the mixed binding style -->
            <Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
            <Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
        </StackPanel>
    </Grid>
</Window>

ButtonThemeViewModel.cs (o DataContext que fornece valores de associação de runtime):

using System.ComponentModel;
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;

namespace ExampleNamespace
{
    public class ButtonThemeViewModel : INotifyPropertyChanged
    {
        private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
        private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
        private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);

        public SolidColorBrush ButtonBackgroundBrush
        {
            get => _buttonBackgroundBrush;
            set
            {
                _buttonBackgroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
            }
        }

        public SolidColorBrush ButtonForegroundBrush
        {
            get => _buttonForegroundBrush;
            set
            {
                _buttonForegroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
            }
        }

        public SolidColorBrush ButtonHoverBrush
        {
            get => _buttonHoverBrush;
            set
            {
                _buttonHoverBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Neste exemplo:

  • {Binding} é usado para propriedades que dependem do DataContext (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush)
  • {x:Bind} é usado para propriedades que são conhecidas em tempo de compilação e pertencem ao próprio ResourceDictionary (DefaultIndicatorBrush, DefaultPressedBrush)
  • O estilo é reutilizável e você pode aplicá-lo a qualquer Botão
  • O tema de runtime é possível por meio do DataContext enquanto ainda se beneficia do desempenho de {x:Bind} elementos estáticos

Associação de eventos e ICommand

{x:Bind} dá suporte a um recurso chamado associação de eventos. Com esse recurso, você pode especificar o manipulador para um evento usando uma associação. Esse recurso é uma opção adicional para manipulação de eventos, além de lidar com eventos usando um método no arquivo code-behind. Suponha que você tenha um ListViewDoubleTapped manipulador de eventos em sua MainWindow classe.

public sealed partial class MainWindow : Window
{
    ...
    public void ListViewDoubleTapped()
    {
        // Handle double-tapped logic
    }
}

Você pode associar um evento DoubleTapped de ListView a um método no MainWindow como este.

<ListView DoubleTapped="{x:Bind ListViewDoubleTapped}" />

Você não pode utilizar métodos sobrecarregados para manipular um evento com essa técnica. Além disso, se o método que manipula o evento tiver parâmetros, todos eles deverão ser atribuíveis dos tipos de todos os parâmetros do evento, respectivamente. Nesse caso, ListViewDoubleTapped não está sobrecarregado e não tem parâmetros (mas ainda seria válido mesmo se fosse necessário dois object parâmetros).

A técnica de associação de eventos é semelhante à implementação e ao consumo de comandos. Um comando é uma propriedade que retorna um objeto que implementa a interface ICommand . { x:Bind} e {Binding} funcionam com comandos. Para que você não precise implementar o padrão de comando várias vezes, use a DelegateCommand classe auxiliar encontrada no exemplo de UWP do QuizGame (na pasta "Comum").

Associação a uma coleção de pastas ou arquivos

Você pode usar as APIs no namespace Windows.Storage para recuperar dados de pasta e arquivo em seus aplicativos do SDK do Aplicativo Windows empacotados. No entanto, os métodos GetFilesAsync, GetFoldersAsync e GetItemsAsync não retornam valores adequados para vinculação a controles de lista. Em vez disso, você deve associar aos valores retornados dos métodos GetVirtualizedFilesVector, GetVirtualizedFoldersVector e GetVirtualizedItemsVector da classe FileInformationFactory . O exemplo de código a seguir da amostra UWP StorageDataSource e GetVirtualizedFilesVector mostra o padrão de uso típico. Lembre-se de declarar a funcionalidade picturesLibrary no manifesto do pacote do aplicativo e confirmar se há imagens na pasta biblioteca Imagens.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var library = Windows.Storage.KnownFolders.PicturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions();
    queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
    queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;

    var fileQuery = library.CreateFileQueryWithOptions(queryOptions);

    var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
        fileQuery,
        Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
        190,
        Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
        false
        );

    var dataSource = fif.GetVirtualizedFilesVector();
    this.PicturesListView.ItemsSource = dataSource;
}

Normalmente, você usa essa abordagem para criar uma visualização somente leitura de informações de arquivo e pasta. Você pode criar associações bidirecionais para as propriedades de arquivo e pasta, por exemplo, para permitir que os usuários classifiquem uma música em um modo de exibição de música. No entanto, as alterações não são mantidas até que você chame o método apropriado SavePropertiesAsync (por exemplo, MusicProperties.SavePropertiesAsync). Você deve confirmar alterações quando o item perde o foco porque essa ação aciona uma redefinição de seleção.

Observe que a associação bidirecional usando essa técnica funciona apenas com locais indexados, como Música. Você pode determinar se um local é indexado chamando o método FolderInformation.GetIndexedStateAsync .

Observe também que um vetor virtualizado pode retornar null para alguns itens antes de preencher seu valor. Por exemplo, você deve verificar null antes de usar o valor SelectedItem de um controle de lista associado a um vetor virtualizado ou usar SelectedIndex .

Associação a dados agrupados por uma chave

Se você pegar uma coleção simples de itens (livros, por exemplo, representados por uma BookSku classe) e agrupar os itens usando uma propriedade comum como chave (a BookSku.AuthorName propriedade, por exemplo), o resultado será chamado de dados agrupados. Quando você agrupa dados, ele não é mais uma coleção simples. Os dados agrupados são uma coleção de objetos de grupo, em que cada objeto de grupo tem:

  • uma chave e
  • uma coleção de itens cuja propriedade corresponde a essa chave.

Para usar o exemplo de livros novamente, o resultado do agrupamento dos livros por nome de autor resulta em uma coleção de grupos de nomes de autor em que cada grupo tem:

  • uma chave, que é um nome de autor e
  • uma coleção dos BookSku objetos cuja AuthorName propriedade corresponde à chave do grupo.

Em geral, para exibir uma coleção, você associará o ItemsSource de um controle de itens (como ListView ou GridView) diretamente a uma propriedade que retorna uma coleção. Se essa for uma coleção simples de itens, você não precisará fazer nada especial. Mas se for uma coleção de objetos de grupo (como é ao associar dados agrupados), você precisará dos serviços de um objeto intermediário chamado CollectionViewSource , que fica entre o controle de itens e a fonte de associação. Você associa a CollectionViewSource propriedade que retorna dados agrupados e associa o controle de itens ao CollectionViewSource. Um valor adicional de adição de um CollectionViewSource é que ele mantém o controle do item atual, para que você possa manter mais de um controle de itens em sincronia associando-os todos ao mesmo CollectionViewSource. Você também pode acessar o item atual programaticamente por meio da propriedade ICollectionView.CurrentItem do objeto retornado pela propriedade CollectionViewSource.View .

Para ativar a instalação de agrupamento de um CollectionViewSource, defina IsSourceGrouped como true. Se você também precisa definir a propriedade ItemsPath depende exatamente de como você cria seus objetos de grupo. Há duas maneiras de criar um objeto de grupo: o padrão "is-a-group" e o padrão "has-a-group". No padrão "is-a-group", o objeto de grupo deriva de um tipo de coleção (por exemplo, ), portanto, List<T>o objeto de grupo é, na verdade, o próprio grupo de itens. Com esse padrão, você não precisa definir ItemsPath. No padrão "has-a-group", o objeto de grupo tem uma ou mais propriedades de um tipo de coleção (como List<T>), portanto, o grupo "tem um" grupo de itens na forma de uma propriedade (ou vários grupos de itens na forma de várias propriedades). Com esse padrão, você precisa definir ItemsPath como o nome da propriedade que contém o grupo de itens.

O exemplo a seguir ilustra o padrão "possui-um-grupo". A classe de janela tem uma propriedade chamada DataContext, que retorna uma instância do nosso modelo de exibição. O CollectionViewSource associa-se à Authors propriedade do modelo de exibição (Authors é a coleção de objetos de grupo) e também especifica que é a Author.BookSkus propriedade que contém os itens agrupados. Por fim, o GridView está associado ao CollectionViewSourceestilo de grupo definido para que ele possa renderizar os itens em grupos.

<Window.Resources>
    <CollectionViewSource
    x:Name="AuthorHasACollectionOfBookSku"
    Source="{x:Bind ViewModel.Authors}"
    IsSourceGrouped="true"
    ItemsPath="BookSkus"/>
</Window.Resources>
...
<GridView
ItemsSource="{x:Bind AuthorHasACollectionOfBookSku}" ...>
    <GridView.GroupStyle>
        <GroupStyle
            HeaderTemplate="{StaticResource AuthorGroupHeaderTemplateWide}" ... />
    </GridView.GroupStyle>
</GridView>

Você pode implementar o padrão "is-a-group" de duas maneiras. Uma maneira é criar sua própria classe de grupo. Derivar a classe de (de List<T> onde T é o tipo dos itens). Por exemplo, public class Author : List<BookSku>. A segunda maneira é usar uma expressão LINQ para criar dinamicamente objetos de grupo (e uma classe de grupo) de valores de propriedade semelhantes aos itens bookSku . Essa abordagem — manter apenas uma lista simples de itens e agrupá-los em tempo real — é típica de um aplicativo que acessa dados de um serviço de nuvem. Você obtém a flexibilidade de agrupar livros por autor ou por gênero (por exemplo) sem precisar de classes de grupo especiais, como Autor e Gênero.

O exemplo a seguir ilustra o padrão "is-a-group" usando LINQ. Desta vez, agrupamos livros por gênero, exibidos com o nome do gênero nos cabeçalhos do grupo. Esse agrupamento é indicado pelo caminho da propriedade "Key" em referência ao valor Key do grupo.

using System.Linq;
...
private IOrderedEnumerable<IGrouping<string, BookSku>> genres;

public IOrderedEnumerable<IGrouping<string, BookSku>> Genres
{
    get
    {
        if (genres == null)
        {
            genres = from book in bookSkus
                     group book by book.genre into grp
                     orderby grp.Key
                     select grp;
        }
        return genres;
    }
}

Lembre-se de que, ao usar {x:Bind} com modelos de dados, você precisa indicar o tipo que está sendo associado definindo um x:DataType valor. Se o tipo for genérico, você não poderá expressá-lo na marcação, portanto, precisará usar {Binding} no modelo de cabeçalho de estilo de grupo.

    <Grid.Resources>
        <CollectionViewSource x:Name="GenreIsACollectionOfBookSku"
        Source="{x:Bind Genres}"
        IsSourceGrouped="true"/>
    </Grid.Resources>
    <GridView ItemsSource="{x:Bind GenreIsACollectionOfBookSku}">
        <GridView.ItemTemplate x:DataType="local:BookTemplate">
            <DataTemplate>
                <TextBlock Text="{x:Bind Title}"/>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Key}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </GridView.GroupStyle>
    </GridView>

Um controle SemanticZoom é uma ótima maneira de seus usuários exibirem e navegarem dados agrupados. O aplicativo de exemplo da Bookstore2 UWP ilustra como usar o SemanticZoom. Nesse aplicativo, você pode exibir uma lista de livros agrupados por autor (a exibição ampliada) ou pode ampliar para ver uma lista de autores de salto (a exibição ampliada). A lista de saltos oferece uma navegação muito mais rápida do que rolar pela lista de livros. As exibições ampliadas e ampliadas são, na verdade ListView , ou GridView controles associados ao mesmo CollectionViewSource.

Uma ilustração de um SemanticZoom

Quando você associa a dados hierárquicos, como subcategorias dentro de categorias, pode optar por exibir os níveis hierárquicos em sua interface do usuário com uma série de controles de itens. Uma seleção em um controle de itens determina o conteúdo dos controles de itens subsequentes. Você pode manter as listas sincronizadas associando cada lista a sua própria CollectionViewSource e associando as CollectionViewSource instâncias em uma cadeia. Essa configuração é chamada de exibição mestre/detalhes (ou lista/detalhes). Para obter mais informações, consulte Como associar a dados hierárquicos e criar uma exibição mestre/detalhes.

Diagnosticar e depurar problemas de associação de dados

Sua marcação de associação contém os nomes das propriedades (e, para C#, às vezes campos e métodos). Portanto, ao renomear uma propriedade, você também precisa alterar qualquer associação que faça referência a ela. Se você esquecer de fazer isso, criará um bug de associação de dados e seu aplicativo não compila ou não é executado corretamente.

Os objetos de associação que {x:Bind} e {Binding} criam são em grande parte funcionalmente equivalentes. Mas {x:Bind} tem informações de tipo para a origem da associação e gera o código-fonte em tempo de compilação. Com {x:Bind}, você obtém o mesmo tipo de detecção de problemas que obtém com o restante do código. Essa detecção inclui a validação em tempo de compilação de suas expressões de associação e depuração definindo pontos de interrupção no código-fonte gerado como a classe parcial para sua página. Você pode encontrar essas classes nos arquivos em sua obj pasta, com nomes como (para C#) <view name>.g.cs). Se você tiver um problema com uma associação, ative Interromper em Exceções Não Tratadas no depurador do Microsoft Visual Studio. O depurador interrompe a execução nesse ponto e você pode depurar o que deu errado. O código gerado segue {x:Bind} o mesmo padrão para cada parte do grafo de nós de origem de associação e você pode usar as informações na janela Pilha de Chamadas para ajudar a determinar a sequência de chamadas que levaram ao problema.

{Binding} não tem informações de tipo para a origem da associação. Mas quando você executa seu aplicativo com o depurador anexado, todos os erros de associação aparecem nas janelas Saída e Falhas de Associação XAML no Visual Studio. Para obter mais informações sobre como depurar erros de associação no Visual Studio, consulte o diagnóstico de associação de dados XAML.

Criando associações no código

Observação

Esta seção só se aplica a {Binding}, porque você não pode criar associações {x:Bind} no código. No entanto, você pode obter alguns dos mesmos benefícios com {x:Bind}DependencyObject.RegisterPropertyChangedCallback, que permite que você se registre para notificações de alteração em qualquer propriedade de dependência.

Você também pode conectar elementos de interface do usuário aos dados usando código de procedimento em vez de XAML. Para fazer isso, crie um novo objeto Binding , defina as propriedades apropriadas e chame FrameworkElement.SetBinding ou BindingOperations.SetBinding. Criar associações programaticamente é útil quando você deseja escolher os valores de propriedade de associação em tempo de execução ou compartilhar uma única associação entre vários controles. No entanto, você não pode alterar os valores de propriedade de ligação depois de chamar SetBinding.

O exemplo a seguir mostra como implementar uma associação no código.

<TextBox x:Name="MyTextBox" Text="Text"/>
// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
var textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;

// Create the binding and associate it with the text box.
var binding = new Binding { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);

Comparação de recursos {x:Bind} e {Binding}

Característica {x:Bind} vs. {Binding} Anotações
O caminho é a propriedade padrão {x:Bind a.b.c}
-
{Binding a.b.c}
Propriedade Path {x:Bind Path=a.b.c}
-
{Binding Path=a.b.c}
In x:Bind, Path está com raiz na Janela por padrão, não no DataContext.
Indexer {x:Bind Groups[2].Title}
-
{Binding Groups[2].Title}
Associa-se ao item especificado na coleção. Há suporte apenas para índices baseados em inteiros.
Propriedades anexadas {x:Bind Button22.(Grid.Row)}
-
{Binding Button22.(Grid.Row)}
As propriedades anexadas são especificadas usando parênteses. Se a propriedade não for declarada em um namespace XAML, prefixe-a com um namespace XML, que deve ser mapeado para um namespace de código à frente do documento.
Fundição {x:Bind groups[0].(data:SampleDataGroup.Title)}
-
Não é necessário para {Binding}.
As conversões são especificadas usando parênteses. Se a propriedade não for declarada em um namespace XAML, prefixe-a com um namespace XML, que deve ser mapeado para um namespace de código à frente do documento.
Conversor {x:Bind IsShown, Converter={StaticResource BoolToVisibility}}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}}
Declare conversores na raiz da janela, controle, ResourceDictionary ou em App.xaml.
ConverterParameter, ConverterLanguage {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
Declare conversores na raiz da Janela, Controle, ou do ResourceDictionary, ou em App.xaml.
TargetNullValue {x:Bind Name, TargetNullValue=0}
-
{Binding Name, TargetNullValue=0}
Usado quando a folha da expressão de associação é nula. Use aspas simples para um valor de cadeia de caracteres.
FallbackValue {x:Bind Name, FallbackValue='empty'}
-
{Binding Name, FallbackValue='empty'}
Usado quando qualquer parte do caminho da associação (exceto a folha) é nula.
ElementName {x:Bind slider1.Value}
-
{Binding Value, ElementName=slider1}
Com {x:Bind} você está associando a um campo; Path é enraizado na Janela por padrão, então você pode acessar qualquer elemento nomeado através de seu campo.
RelativeSource: Self <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... />
-
<Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... />
Com {x:Bind}, nomeie o elemento e use seu nome em Path.
RelativeSource: TemplatedParent (Origem Relativa: Parente Modelado) Não é necessário para {x:Bind}
-
{Binding <path>, RelativeSource={RelativeSource TemplatedParent}}
Com {x:Bind}, TargetType em ControlTemplate indica associação ao modelo pai. Para {Binding}, a associação de modelo regular pode ser usada em modelos de controle para a maioria dos usos. Mas use TemplatedParent onde você precisa usar um conversor ou uma associação bidirecional.
Source Não é necessário para {x:Bind}
-
<ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/>
Para {x:Bind} você pode usar diretamente o elemento nomeado, usar uma propriedade ou um caminho estático.
Mode {x:Bind Name, Mode=OneWay}
-
{Binding Name, Mode=TwoWay}
Mode pode ser OneTime, OneWayou TwoWay. {x:Bind} o padrão é OneTime; {Binding} o padrão é OneWay.
UpdateSourceTrigger {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
-
{Binding UpdateSourceTrigger=PropertyChanged}
UpdateSourceTrigger pode ser Default, LostFocusou PropertyChanged. {x:Bind} não suporta UpdateSourceTrigger=Explicit. {x:Bind} PropertyChanged usa o comportamento para todos os casos, exceto TextBox.Textem que usa LostFocus o comportamento.

Consulte também