Compartilhar via


Visão geral da associação de dados do Windows

Este tópico mostra como associar um controle (ou outro elemento de interface do usuário) a um único item ou associar um controle de itens a uma coleção de itens em um aplicativo SDK de aplicativo do Windows. Além disso, mostramos como controlar a renderização de itens, implementar uma exibição de detalhes com base em uma seleção e converter dados para exibição. Para saber mais detalhes, consulte Vinculação de dados em detalhes.

Pré-requisitos

Este tópico pressupõe que você saiba como criar um aplicativo básico do SDK de Aplicativo do Windows. Para obter instruções sobre como criar seu primeiro aplicativo do SDK de Aplicativo do Windows, consulte Criar seu primeiro projeto do WinUI 3 (SDK de Aplicativo do Windows).

Criar o projeto

Crie um projeto C# de Aplicativo em branco empacotado (WinUI 3 na Área de Trabalho). Nomeie-o como "Início Rápido".

Associação a um único item

Cada associação consiste em um destino de associação e uma origem de associação. Normalmente, o destino é uma propriedade de um controle ou outro elemento de interface do usuário e a origem é uma propriedade de uma instância de classe (um modelo de dados ou um modelo de exibição). Este exemplo mostra como associar um controle a um único item. O destino é a propriedade Text de um TextBlock. A origem é uma instância de uma classe simples chamada Recording que representa uma gravação de áudio. Primeiro, vamos examinar a classe.

Adicione uma nova classe ao projeto e nomeie a classe Recording.

namespace Quickstart
{
    public class Recording
    {
        public string ArtistName { get; set; }
        public string CompositionName { get; set; }
        public DateTime ReleaseDateTime { get; set; }
        public Recording()
        {
            ArtistName = "Wolfgang Amadeus Mozart";
            CompositionName = "Andante in C for Piano";
            ReleaseDateTime = new DateTime(1761, 1, 1);
        }
        public string OneLineSummary
        {
            get
            {
                return $"{CompositionName} by {ArtistName}, released: "
                    + ReleaseDateTime.ToString("d");
            }
        }
    }
    public class RecordingViewModel
    {
        private Recording defaultRecording = new Recording();
        public Recording DefaultRecording { get { return defaultRecording; } }
    }
}

Em seguida, exponha a classe da fonte de associação da classe que representa a janela de marcação. Fazemos isso adicionando uma propriedade do tipo RecordingViewModel a MainWindow.xaml.cs.

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

A última parte é associar um TextBlock à propriedade ViewModel.DefaultRecording.OneLineSummary.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
    HorizontalAlignment="Center"
    VerticalAlignment="Center"/>
    </Grid>
</Window>

Este é o resultado.

Vincular um bloco de texto

Vinculação a uma coleção de itens

Um cenário comum é vincular-se a uma coleção de objetos de negócios. No C#, a classe ObservableCollection<T> é uma boa opção de coleção para associação de dados, pois implementa as interfaces INotifyPropertyChanged e INotifyCollectionChanged. Essas interfaces fornecem notificação de alteração para associações quando os itens são adicionados ou removidos ou uma propriedade da própria lista é alterada. Se você quiser que seus controles vinculados sejam atualizados com alterações nas propriedades dos objetos na coleção, o objeto de negócios também deverá implementar INotifyPropertyChanged. Para obter mais informações, consulte Vinculação de dados em detalhes.

Este próximo exemplo associa um ListView a uma coleção de objetos . Vamos começar adicionando a coleção ao nosso modelo de exibição. Basta adicionar esses novos membros à classe RecordingViewModel.

public class RecordingViewModel
{
    ...
    private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
    public ObservableCollection<Recording> Recordings{ get{ return recordings; } }
    public RecordingViewModel()
    {
        recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
            CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
        recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
            CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
        recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
            CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
    }
}

Em seguida, associe um ListView à propriedade ViewModel.Recordings.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <ListView ItemsSource="{x:Bind ViewModel.Recordings}"
        HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

Ainda não fornecemos um modelo de dados para a classe Recording, portanto, o melhor que o framework de interface do usuário pode fazer é chamar ToString para cada item no ListView. A implementação padrão de ToString é retornar o nome do tipo.

Associação de uma exibição de lista 1

Para corrigir isso, podemos substituir ToString para retornar o valor de OneLineSummaryou podemos fornecer um modelo de dados. A opção de modelo de dados é uma solução mais comum e mais flexível. Especifique um modelo de dados usando a propriedade ContentTemplate de um controle de conteúdo ou a propriedade ItemTemplate de um controle de itens. Aqui estão duas maneiras de criar um modelo de dados para Recording junto com uma ilustração do resultado.

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <TextBlock Text="{x:Bind OneLineSummary}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Associação de uma exibição de lista 2

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <StackPanel Orientation="Horizontal" Margin="6">
                <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                <StackPanel>
                    <TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
                    <TextBlock Text="{x:Bind CompositionName}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Associação de uma exibição de lista 3

Para obter mais informações sobre a sintaxe XAML, consulte Criar uma interface do usuário com XAML. Para obter mais informações sobre o layout de controle, consulte Definir layouts com XAML.

Adicionando uma exibição de detalhes

Você pode optar por exibir todos os detalhes dos objetos Recording nos itens de ListView . Mas isso ocupa muito espaço. Em vez disso, você pode mostrar apenas dados suficientes no item para identificá-lo e, quando o usuário fizer uma seleção, você pode exibir todos os detalhes do item selecionado em uma parte separada da interface do usuário conhecida como exibição de detalhes. Além disso, esse esquema também é conhecido como um modo de exibição mestre/detalhado, ou um modo de exibição de lista/detalhes.

Há duas maneiras de fazer isso. Você pode vincular a exibição de detalhes à propriedade SelectedItem do ListView. Ou você pode usar uma CollectionViewSource e, nesse caso, associar ListView e o modo de exibição de detalhes a CollectionViewSource (o que cuida do item atualmente selecionado por você). Ambas as técnicas são mostradas abaixo e ambas dão os mesmos resultados (mostrados na ilustração).

Nota

Até agora neste tópico, usamos apenas a extensão de marcação {x:Bind}, mas ambas as técnicas que mostraremos abaixo exigem a extensão de marcação mais flexível (mas menos performante) {Binding}.

Primeiro, está a técnica SelectedItem. Para um aplicativo C#, a única alteração necessária é na marcação.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:Recording">
                        <StackPanel Orientation="Horizontal" Margin="6">
                            <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                            <StackPanel>
                                <TextBlock Text="{x:Bind CompositionName}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
            Margin="0,24,0,0">
                <TextBlock Text="{Binding ArtistName}"/>
                <TextBlock Text="{Binding CompositionName}"/>
                <TextBlock Text="{Binding ReleaseDateTime}"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

Para a técnica CollectionViewSource, primeiro adicione um CollectionViewSource como recurso de nível superior do Grid.

<Grid.Resources>
    <CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>

Nota

A classe Window no WinUI não tem uma propriedade Resources. Você pode adicionar o CollectionViewSource ao elemento de nível superior Grid (ou outro elemento da interface do usuário pai, como StackPanel). Se estiver trabalhando em um Page, poderá adicionar o CollectionViewSource ao Page.Resources.

Em seguida, ajuste as associações no ListView , que não precisa mais ser nomeado, e na exibição de detalhes para usar o CollectionViewSource . Observe que, associando o modo de exibição de detalhes diretamente a CollectionViewSource, você está indicando que deseja associar ao item atual em associações em que o caminho não pode ser encontrado na coleção em si. Não é necessário especificar a propriedade CurrentItem como o caminho para a associação, embora você possa fazer isso se houver alguma ambiguidade.

...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...

E aqui está o resultado idêntico em cada caso.

Associação de uma exibição de lista 4

Formatação ou conversão de valores de dados para exibição

Há um problema com a renderização acima. A propriedade ReleaseDateTime não é somente uma data, mas um DateTime. Então, ele está sendo exibido com mais precisão do que precisamos. Uma solução é adicionar uma propriedade de cadeia de caracteres à classe Recording que retorna o equivalente a ReleaseDateTime.ToString("d"). Nomear essa propriedade ReleaseDate indicaria que ela retorna uma data e não uma data e hora. Nomeá-lo ReleaseDateAsString indicaria ainda mais que ele retorna uma cadeia de caracteres.

Uma solução mais flexível é usar algo conhecido como conversor de valor. Aqui está um exemplo de como criar seu próprio conversor de valor. Adicione o código abaixo ao arquivo de código-fonte Recording.cs.

public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
    // This converts the value object to the string to display.
    // This will work with most simple types.
    public object Convert(object value, Type targetType,
        object parameter, string language)
    {
        // Retrieve the format string and use it to format the value.
        string formatString = parameter as string;
        if (!string.IsNullOrEmpty(formatString))
        {
            return string.Format(formatString, value);
        }

        // If the format string is null or empty, simply
        // call ToString() on the value.
        return value.ToString();
    }

    // No need to implement converting back on a one-way binding
    public object ConvertBack(object value, Type targetType,
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Agora podemos adicionar uma instância de StringFormatter como um recurso e usá-la na associação do TextBlock que exibe a propriedade ReleaseDateTime.

<Grid.Resources>
    ...
    <local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
    Converter={StaticResource StringFormatterValueConverter},
    ConverterParameter=Released: \{0:d\}}"/>
...

Como você pode ver acima, para a flexibilidade de formatação, usamos a marcação para passar uma cadeia de caracteres de formato para o conversor por meio do parâmetro conversor. No exemplo de código mostrado neste tópico, o conversor de valor C# usa esse parâmetro.

Este é o resultado.

exibindo uma data com formatação personalizada