Introdução à vinculação de dados

Concluído

Tech logo of U W P and W P F.

Nesta lição, você aprenderá a criar um aplicativo que mostra a hora atual. A lição apresenta os fundamentos da vinculação de dados, obtendo dados do código para a interface do usuário do seu aplicativo e atualizando-os para atualizar a exibição do relógio na interface do usuário. Esta lição forma a base para tarefas de vinculação de dados mais complexas em lições posteriores. Por isso, vamos começar!

Tech logo of U W P and W P F. W P F appears dimmed.

1. Crie o projeto

Se ainda não estiver em execução, abra o Visual Studio. Crie um novo projeto C# Windows Universal usando o modelo Aplicativo em Branco (Universal Windows). Chame-lhe DatabindingSample. Este projeto é aquele com o qual você trabalhará durante todo o módulo de interface do usuário e dados.

Screenshot of the Visual Studio Create a new project dialog box.

Quando você clica em OK, o Visual Studio solicita que você insira as versões de destino e mínima do Windows. Este projeto é apenas um projeto de exercício e você não está planejando implantá-lo em computadores que executam uma versão mais antiga do Windows. Portanto, você pode selecionar a versão mais recente do Windows para a versão mínima e a versão de destino e, em seguida, clique em OK.

2. Adicione o TextBlock para a exibição do relógio

Quando o projeto tiver sido totalmente inicializado e carregado, abra MainPage.xaml clicando duas vezes nele no Gerenciador de Soluções.

Gorjeta

Se você estiver com pouco espaço na tela, use a lista suspensa no canto superior esquerdo para alternar o editor para simular uma tela de resolução mais baixa. Recomendamos o uso de 13,3" Desktop (1280x720) escala 100% para este módulo, mas escolha o que se sente mais confortável.

Adicione a seguinte linha entre as tags de abertura e fechamento do Grid elemento.

<TextBlock HorizontalAlignment="Right" 
           Margin="10" 
           Text="{x:Bind CurrentTime}" />

Isso cria um novo TextBlock no lado superior direito da janela, com uma margem de 10 unidades da borda. Em seguida, vamos abordar o TextTextBlockdo .

A Text={x:Bind CurrentTime} parte é o seu primeiro encontro com a vinculação de dados. x:Bind é uma extensão de marcação XAML que é compilada em código C# junto com o resto do seu aplicativo. Aqui, ele conecta a TextTextBlock propriedade do ao CurrentTime imóvel. Se você tentar compilar o projeto agora, você receber a seguinte mensagem de erro:

Erro XamlCompiler WMC1110: Caminho de vinculação inválido 'CurrentTime' : Propriedade 'CurrentTime' não pode ser encontrada no tipo 'MainPage'

Isso indica que o compilador está faltando uma CurrentTime propriedade do MainPage. Depois de criarmos essa propriedade, seu conteúdo é exibido no TextBlock canto superior direito.

Nota

A UWP também oferece suporte a um método de vinculação de dados mais antigo, que se parece com isto: Text={Bind CurrentTime}. Este método mais antigo funciona de forma um pouco diferente do {x:Bind}. Mais notavelmente, ele não oferece erros de tempo de compilação se você tiver um erro de digitação. Neste módulo, concentramo-nos exclusivamente na nova {x:Bind} forma de vinculação, que fornece verificação de erros em tempo de compilação. No entanto, é menos maduro do que o , e recebe novos recursos, {x:Bind} e é por isso que escolhemos ir com a versão mais recente do {Bind}Windows para criar o projeto.

3. Crie a CurrentTime propriedade

Abra MainPage.xaml.cs e adicione a seguinte definição de propriedade à MainPage classe.

public string CurrentTime => DateTime.Now.ToLongTimeString();

Se você não estiver familiarizado com a sintaxe acima, ela é chamada de membro com corpo de expressão. Ele foi introduzido no C# 6.0 e é uma abreviação para o seguinte:

public string CurrentTime 
{
    get { return DateTime.Now.ToLongTimeString(); }
}

4. Execute o aplicativo

Se você iniciar o aplicativo agora (usando a tecla F5 ou o comando Depurar / Iniciar Depuração no menu), o aplicativo será compilado e executado. O que é ainda melhor é que parece funcionar! A hora atual é exibida no canto superior direito.

Screenshot of the running app with the clock.

No entanto, algo não está certo porque o relógio não atualiza. Ele está preso no momento em que o aplicativo foi lançado pela primeira vez. Como o aplicativo saberia quando atualizar o valor no TextBlock? Temos que dizer ao tempo de execução da UWP para atualizá-lo uma vez por segundo.

5. Especificar modos de vinculação

{x:Bind} As ligações são altamente otimizadas para desempenho. O que significa que eles não fazem nada que o desenvolvedor não tenha pedido explicitamente. Portanto, por padrão, uma vinculação só avalia a fonte da vinculação (no nosso caso, a CurrentTime propriedade) uma {x:Bind} vez. Esse tipo de vinculação é chamado OneTime de vinculação. Se quisermos que a estrutura UWP continue atualizando a interface do usuário, temos que especificar explicitamente outro modo de vinculação: ou OneWayTwoWay.

TwoWay O modo de vinculação indica uma ligação bidirecional entre nosso código C# (a lógica) e a interface do usuário. Esse tipo de associação será útil mais tarde, quando formos vinculados a controles que o usuário pode manipular. Mas para um TextBlock, uma OneWay associação é preferível porque as alterações de dados só terão origem no código, nunca na interface do usuário.

Para especificar um modo de OneWay vinculação para o nosso TextBlock, altere {x:Bind CurrentTime} para {x:Bind CurrentTime, Mode=OneWay}. A tag inteira TextBlock dentro do Grid deve agora se parecer com esta marcação.

<TextBlock HorizontalAlignment="Right" 
           Margin="10" 
           Text="{x:Bind CurrentTime, Mode=OneWay}" />

A associação instrui o tempo de execução da UWP a criar a infraestrutura necessária para controlar as CurrentTime alterações na propriedade e refleti-la no Text .TextBlock Essa infraestrutura adicional ocupa uma pequena quantidade de memória e ciclos de CPU, e é por isso que não é o padrão.

Se você executar o aplicativo agora, o relógio ainda não será atualizado. Precisamos notificar o sistema de que a CurrentTime propriedade mudou.

6. Implementar a INotifyPropertyChanged interface

Esta notificação acontece através da INotifyPropertyChanged interface. É uma interface simples com um único evento.

public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}

Qualquer classe que tenha uma propriedade C# simples como fonte de vinculação de dados deve implementar a INotifyPropertyChanged interface. A classe deve disparar o PropertyChanged evento quando a interface do usuário deve ser atualizada. Vamos em frente e adicionar a interface à MainPage declaração de classe.

public sealed partial class MainPage : Page, INotifyPropertyChanged

Também temos que implementar a interface adicionando o PropertyChanged evento à classe.

public event PropertyChangedEventHandler PropertyChanged;

7. Invoque o evento a PropertyChanged cada segundo

Tudo o que resta é invocar o evento toda vez que quisermos atualizar o PropertyChanged relógio (ou seja, a cada segundo). Para começar, vamos declarar um DispatcherTimer objeto na MainPage classe.

private DispatcherTimer _timer;

Agora vamos configurá-lo no construtor (após a chamada) para que ele seja acionado a InitializeComponent cada segundo.

_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };

_timer.Tick += (sender, o) =>
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentTime)));

_timer.Start();

A primeira linha acima cria o temporizador com um intervalo de um segundo e a última linha inicia-o. Vamos examinar o que acontece quando o temporizador dispara (na segunda linha).

PropertyChanged?.Invoke é uma abreviatura para verificar se um evento é nulo e, se não, invocá-lo. Como a maioria dos eventos, o primeiro argumento é o remetente (this). O segundo argumento para o evento é um objeto recém-criadoPropertyChangedEventArgs, que tem um construtor esperando uma cadeia de caracteres como o PropertyChanged nome da propriedade. Assim, os assinantes do PropertyChanged evento (neste caso, o sistema UWP) receberão o nome da propriedade atualizada e poderão agir de acordo.

Gorjeta

Não use literais de cadeia de caracteres (como "CurrentTime") para o nome da propriedade. O uso da cadeia de caracteres em si é propenso a erros de digitação, o que pode resultar em problemas difíceis de depurar quando a interface do usuário não está sendo atualizada. Além disso, uma renomeação inocente da propriedade também pode introduzir erros se as constantes de cadeia de caracteres não forem atualizadas. É uma boa prática usar sempre a expressão, que é imune a nameof erros de digitação e pode seguir renomeações.

Todo o MainPage.xaml.cs deve ter a seguinte aparência:

namespace DatabindingSample
{
    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        private DispatcherTimer _timer;

        public MainPage()
        {
            this.InitializeComponent();
            _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };

            _timer.Tick += (sender, o) =>
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentTime)));

            _timer.Start();
        }

        public string CurrentTime => DateTime.Now.ToLongTimeString();
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

8. Execute o aplicativo

Se você executar o aplicativo agora, o relógio será atualizado. Parabéns, você criou sua primeira vinculação de dados!

9. Resumo

Agora você sabe como usar {x:Bind} para criar uma maneira rápida e automática de obter dados do código para a interface do usuário do seu aplicativo UWP. Esta técnica é verificada no momento da compilação. Você também se familiarizou com a INotifyPropertyChanged interface. Essa interface permite que seu aplicativo notifique a estrutura UWP quando uma propriedade vinculada a dados for alterada e a interface do usuário for atualizada.

Tech logo of U W P and W P F. U W P appears dimmed.

1. Crie o projeto

Se ainda não estiver em execução, abra o Visual Studio. Crie um novo projeto WPF em C# usando o modelo Aplicativo WPF. Chame-o DatabindingSampleWPF e selecione OK. Este projeto é aquele com o qual você trabalhará durante todo o módulo de interface do usuário e dados.

Screenshot of the Visual Studio Create a new WPF project dialog box.

2. Crie a classe Clock

Como nossa tarefa é exibir a hora atual, faz sentido criar uma Clock classe primeiro. Clique com o botão direito do mouse no projeto no Gerenciador de Soluções, selecione Adicionar / Classe e digite Clock como o DatabindingSampleWPF nome da classe.

Copie o seguinte código para o arquivo recém-criado:

using System;

namespace DatabindingSampleWPF
{
    public class Clock
    {
        public string CurrentTime => DateTime.Now.ToLongTimeString();
    }
}

Se você não estiver familiarizado com a sintaxe acima para a CurrentTime propriedade, ela é chamada de membro com corpo de expressão. Ele foi introduzido no C# 6.0 e é uma abreviação para o seguinte:

public string CurrentTime 
{
    get { return DateTime.Now.ToLongTimeString(); }
}

Como você pode ver, tudo o que a classe tem até agora é uma propriedade simples string que retorna a Clock hora atual em um formato de tempo longo. O próximo passo é exibir o tempo dentro do próprio aplicativo.

3. Adicione o TextBlock para a exibição do relógio

Se você tiver MainWindow.xaml aberto no Visual Studio, selecione sua guia. Caso contrário, você pode abri-lo clicando duas vezes nele no Gerenciador de Soluções.

Adicione a seguinte linha entre as tags de abertura e fechamento do Grid elemento.

<TextBlock HorizontalAlignment="Right" 
           VerticalAlignment="Top"
           Margin="10" 
           Text="{Binding CurrentTime}">
    <TextBlock.DataContext>
        <local:Clock/>
    </TextBlock.DataContext>
</TextBlock>

Essa marcação criará uma nova TextBlock no canto superior direito da janela, com uma margem de 10 unidades a partir da borda.

A Text="{Binding CurrentTime}" parte é o seu primeiro encontro com a vinculação de dados. {Binding} é uma extensão de marcação XAML. Aqui, ele conecta TextBlock a propriedade do à CurrentTime propriedade - mas a TextCurrentTime propriedade de qual objeto?

O objeto ao qual a associação de dados se refere é instanciado no DataContext do TextBlock. Assim, o código XAML acima não apenas cria um controle, mas também instancia um TextBlockClock objeto. Além disso, o código vincula a Text propriedade do à TextBlockCurrentTime propriedade do Clock objeto que ele criou. A CurrentTime propriedade é chamada de origem da ligação, enquanto a Text propriedade é chamada de destino da ligação.

4. Execute o aplicativo

Se você iniciar o aplicativo agora (usando a tecla F5 ou o comando Depurar / Iniciar Depuração no menu), o aplicativo será compilado e executado. O que é ainda melhor é que parece funcionar! A hora atual é exibida no canto superior direito.

Screenshot of the running app with the clock.

No entanto, algo não está certo porque o relógio não atualiza. Ele está preso no momento em que o aplicativo foi lançado pela primeira vez. Como o aplicativo saberia quando atualizar o valor no TextBlock? Temos que dizer ao tempo de execução do WPF para atualizá-lo uma vez por segundo.

Em outras palavras, precisamos notificar o sistema de que a CurrentTime propriedade mudou.

5. Implementar a INotifyPropertyChanged interface

Esta notificação acontece através da INotifyPropertyChanged interface. É uma interface simples com um único evento.

public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}

Qualquer classe que tenha uma propriedade C# simples como fonte de vinculação de dados deve implementar a INotifyPropertyChanged interface. A classe deve disparar o PropertyChanged evento quando a interface do usuário deve ser atualizada. Vamos em frente e adicionar a interface à Clock declaração de classe.

using System.ComponentModel;

public class Clock : INotifyPropertyChanged
{

Também temos que implementar a interface adicionando o PropertyChanged evento à classe.

public event PropertyChangedEventHandler? PropertyChanged;

6. Invoque o evento a PropertyChanged cada segundo

Tudo o que resta é invocar o evento toda vez que quisermos atualizar o PropertyChanged relógio (ou seja, a cada segundo). Para começar, vamos adicionar o System.Windows.Threading namespace ao usings e declarar um DispatcherTimer objeto na Clock classe.

private DispatcherTimer _timer;

Agora configure-o no construtor, para que ele dispare a cada segundo.

public Clock()
{
    _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };

    _timer.Tick += (sender, o) => PropertyChanged?.Invoke(this,
            new PropertyChangedEventArgs(nameof(CurrentTime)));

    _timer.Start();
}

A primeira linha no construtor cria o temporizador com um intervalo de um segundo, e a última linha o inicia. Vamos examinar o que acontece quando o temporizador dispara (na segunda linha).

PropertyChanged?.Invoke é uma abreviatura para verificar se um evento é nulo e, se não, invocá-lo. Como a maioria dos eventos, o primeiro argumento é o remetente (this). O segundo argumento para o evento é um objeto recém-criadoPropertyChangedEventArgs, que tem um construtor esperando uma cadeia de caracteres como o PropertyChanged nome da propriedade. Assim, os assinantes do PropertyChanged evento (neste caso, o sistema WPF) receberão o nome da propriedade atualizada e poderão agir de acordo.

Gorjeta

Não use literais de cadeia de caracteres (como "CurrentTime") para o nome da propriedade. O uso da cadeia de caracteres em si é propenso a erros de digitação, o que pode resultar em problemas difíceis de depurar quando a interface do usuário não está sendo atualizada. Além disso, uma renomeação inocente da propriedade também pode introduzir erros se as constantes de cadeia de caracteres não forem atualizadas. É uma boa prática usar sempre a expressão, que é imune a nameof erros de digitação e pode seguir operações de renomeação.

O todo Clock.cs deve ter a seguinte aparência:

namespace DatabindingSampleWPF
{
    using System;
    using System.ComponentModel;
    using System.Windows.Threading;

    public class Clock : INotifyPropertyChanged
    {
        private DispatcherTimer _timer;

        public string CurrentTime => DateTime.Now.ToLongTimeString();

        public event PropertyChangedEventHandler PropertyChanged;

        public Clock()
        {
            // setup _timer to refresh CurrentTime
            _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
            _timer.Tick += (sender, o) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentTime)));
            _timer.Start();
        }
    }
}

7. Execute o aplicativo

Se você executar o aplicativo agora, o relógio será atualizado. Você criou sua primeira vinculação de dados!

8. Resumo

Agora você sabe como usar {Binding} para criar uma maneira rápida e automática de obter dados do código para a interface do usuário do seu aplicativo WPF. Você também se familiarizou com a INotifyPropertyChanged interface. Essa interface permite que seu aplicativo notifique a estrutura do WPF quando uma propriedade ligada a dados for alterada e a interface do usuário for atualizada.