Introdução à vinculação de dados
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!
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.
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 Text
TextBlock
do .
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 Text
TextBlock
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.
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 OneWay
TwoWay
.
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.
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.
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 Text
CurrentTime
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 TextBlock
Clock
objeto. Além disso, o código vincula a Text
propriedade do à TextBlock
CurrentTime
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.
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 using
s 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.