segunda-feira, 31 de julho de 2017

Trabalhando com data binding no Windows Forms

Por André Alves Lima em 26/07/2017

Eu sei que WPF é a plataforma de desenvolvimento de aplicações desktop mais nova da Microsoft e que o Windows Forms já está aposentado. Entretanto, algumas pessoas podem discordar disso, mas, eu acho que em diversas situações faz mais sentido utilizar o Windows Forms se você já tiver experiência com ele. Porém, o objetivo desse artigo não é fazer uma comparação entre WPF e Windows Forms (eu já escrevi sobre isso uns tempos atrás). O que eu quero realmente mostrar no artigo de hoje é o sistema de data binding no Windows Forms.
Uma vez que é um fato que muitos desenvolvedores ainda trabalham com Windows Forms, é muito importante aprender a trabalhar com essa plataforma da melhor maneira possível. Eu já vi inúmeros desenvolvedores que ficam copiando manualmente dados de controles para classes de dados, ou desenvolvem lógica para ativar ou desativar controles utilizando eventos. Saiba que existe uma maneira muito mais fácil e limpa de implementar esse tipo de funcionalidade. É justamente com a ajuda do data binding que a sua vida vai ficar muito mais tranquila ao desenvolver qualquer tipo de aplicação, seja ela Windows Forms, WPF, Xamarin, UWP, etc.
Quer aprender como funciona o esquema de data binding no Windows Forms? Então vamos lá!

Data binding entre controles

Uma das coisas que podemos implementar com data binding no Windows Forms é a troca de informações entre controles. Nós podemos ligar qualquer propriedade de um controle com qualquer propriedade de outro controle. Por exemplo, imagine que você tenha que habilitar ou desabilitar um botão dependendo do estado de um CheckBox:
Como é que muita gente resolve esse problema? Implementando essa lógica no evento “CheckStateChanged” do CheckBox! Se você implementaria dessa forma, para tudo! Com uma linha de código nós conseguimos fazer uma ligação entre a propriedade “Enabled” do TextBox e a propriedade “Checked” do CheckBox:
1
2
// C#
btExemplo.DataBindings.Add("Enabled", checkBoxHabilitado, "Checked");
1
2
' VB.NET
BtExemplo.DataBindings.Add("Enabled", CheckBoxHabilitado, "Checked")
Veja só o efeito produzido por essa simples linha de código:
Como você pode perceber, data binding entre propriedades de controles é algo muito tranquilo de ser implementado no Windows Forms. Basta acessarmos a propriedade “DataBindings” do controle destino (no nosso caso, o botão) e então chamamos o método “Add” para adicionarmos uma nova ligação (nós podemos ter várias ligações no mesmo controle, utilizando propriedades diferentes).
Os parâmetros para o método “Add” são: a propriedade que receberá o valor no controle destino (no nosso caso, a propriedade “Enabled” do botão), o controle de origem (no nosso caso, o CheckBox) e a propriedade no controle de origem (no nosso caso, a propriedade “Checked” do CheckBox).
Viu só que fácil? Imagine se nós tivéssemos também alguns TextBoxes na tela. Nós poderíamos fazer outros data bindings com a propriedade “Text“, por exemplo:
1
2
3
4
// C#
btExemplo.DataBindings.Add("Text", tbExemplo, "Text");
tbExemplo.DataBindings.Add("Text", tbExemplo2, "Text");
tbExemplo2.DataBindings.Add("Text", tbExemplo, "Text");
1
2
3
4
' VB.NET
BtExemplo.DataBindings.Add("Text", TbExemplo, "Text")
TbExemplo.DataBindings.Add("Text", TbExemplo2, "Text")
TbExemplo2.DataBindings.Add("Text", TbExemplo, "Text")
E com essas poucas linhas de código, nós temos esse efeito:

Data binding no DataGridView

Outro exemplo clássico de data binding no Windows Forms é com o controle DataGridView. Nós podemos alimentar o controle de grid com uma coleção de objetos ou com uma DataTable. Para demonstrar essa funcionalidade, vamos adicionar uma nova classe no nosso projeto, dando o nome de “Produto“:
1
2
3
4
5
6
7
// C#
public class Produto
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public decimal ValorUnitario { get; set; }
}
1
2
3
4
5
6
' VB.NET
Public Class Produto
    Public Property Id As Integer
    Public Property Nome As String
    Public Property ValorUnitario As Decimal
End Class
Em seguida, vamos adicionar as colunas correspondentes no DataGridView:
Atenção! Não esqueça de configurar a propriedade “DataPropertyName” de cada coluna do grid, de modo que elas apontem para a propriedade correspondente da nossa classe:
Feito isso, vamos adicionar uma lista de Produtos no nível do formulário:
1
2
// C#
private List<Produto> _produtos = new List<Produto>();
1
2
' VB.NET
Private Produtos As New List(Of Produto)
Com a lista instanciada, vamos adicionar alguns produtos dentro dela e, em seguida, alimentamos o grid com essa lista através da propriedade “DataSource“:
1
2
3
4
5
6
// C#
_produtos.Add(new Produto() { Id = 1, Nome = "Produto 1", ValorUnitario = 1.23m });
_produtos.Add(new Produto() { Id = 2, Nome = "Produto 2", ValorUnitario = 4.56m });
_produtos.Add(new Produto() { Id = 3, Nome = "Produto 3", ValorUnitario = 7.89m });
 
dgvProdutos.DataSource = _produtos;
1
2
3
4
5
6
' VB.NET
Produtos.Add(New Produto() With {.Id = 1, .Nome = "Produto 1", .ValorUnitario = 1.23})
Produtos.Add(New Produto() With {.Id = 2, .Nome = "Produto 2", .ValorUnitario = 4.56})
Produtos.Add(New Produto() With {.Id = 3, .Nome = "Produto 3", .ValorUnitario = 7.89})
 
DgvProdutos.DataSource = Produtos
Ao executarmos a aplicação, aparentemente tudo funcionou corretamente:
Mas, será que tudo está funcionando mesmo? O que será que aconteceria se nós adicionássemos um novo produto na lista em tempo de execução? Vamos testar?
Para checarmos esse cenário, vamos implementar uma lógica para o evento “Click” do nosso botão. Quando o botão for clicado, nós vamos alterar o texto do primeiro produto da lista utilizando o conteúdo digitado no TextBox e, além disso, nós adicionaremos um novo produto utilizando um ID sequencial:
1
2
3
4
5
6
7
// C#
private int _ultimoId = 3;
private void btExemplo_Click(object sender, EventArgs e)
{
    _produtos[0].Nome = tbExemplo.Text;
    _produtos.Add(new Produto() { Id = ++_ultimoId, Nome = _ultimoId.ToString(), ValorUnitario = _ultimoId });
}
1
2
3
4
5
6
7
' VB.NET
Private UltimoId = 3
Private Sub BtExemplo_Click(sender As Object, e As EventArgs) Handles BtExemplo.Click
    Produtos(0).Nome = TbExemplo.Text
    UltimoId += 1
    Produtos.Add(New Produto() With {.Id = UltimoId, .Nome = UltimoId.ToString(), .ValorUnitario = UltimoId})
End Sub
Se testarmos essa implementação, veremos que o novo produto não será exibido no grid e, além disso, temos um comportamento bem estranho quanto à alteração do texto no primeiro produto. O grid só entende que ele foi modificado depois de navegarmos para outra linha:
Por que tivemos esse efeito? E como é que podemos resolve-lo?


Continua na parte 2

Nenhum comentário:

Postar um comentário