SilverLight 3.0 - Apresentando o DataBinding


O DataBinding pode ser visto como um mecanismo para mover os dados a partir de objetos para controles de interface. Neste artigo veremos como funciona o DataBinding para o SilverLight e para isso iremos abordar os seguintes tópicos: binding expressions, data templates, converters, binding modes, e validation, além disso veremos qual o mecanismo usado neste processo e em como usar estes recursos para criar a camada de interface.

O DataBinding efetua a vinculação entre os objetos - o modelo - e a interface, também conhecida como: o view. A tarefa do modelo e tratar os objetos e a tarefa da view e exibir os objetos em controles como listas, grades, gráficos , etc.

DataBinding Simples

Vamos iniciar com o DataBinding Simples ou básico, neste caso há  dois conceitos que você precisa conhecer para realizar o databinding básico. O primeiro é o conceito de binding expression.

Uma binding expression é utilizada no interior do XAML de um componente SilverLight para descrever o nome da propriedade que você deseja vincular a partir do seu modelo. Uma binding expression é realizada no interior de colchetes ({ }) e abaixo temos um exemplo de sua utilização em um arquivo XAML:

<UserControl x:Class="DataBindingDemo.SimplesBinding"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <TextBlock Text="{Binding Nome}" />
        <TextBlock Text="{Binding Path=ID}" />
        <TextBlock Text="{Binding Curso.Nome}"/>
    </StackPanel>
</UserControl>

Apenas para situarmos, o código acima é uma visão XAML da uma interface de uma aplicação SilverLight onde <StackPanel> e <TextBlock> são componentes visuais.

Na primeira linha referente ao componente <TextBlock> temos: <TextBlock Text="{Binding Nome}" />

Nesta linha temos uma binding expression na propriedade Text da view que diz ao SilverLight para obter o valor para esta propriedade a partir da propriedade Nome do model.

Na segunda linha: <TextBlock Text="{Binding Path=ID}" /> estamos realizando a mesma coisa com a propriedade ID do modelo usando uma binding expression equivalente (A palavra Path é opcional)

Na terceira linha <TextBlock Text="{Binding Curso.Nome}"/>, temos uma demonstração de navegação na hierarquia de objetos e neste caso o SilverLight encontra a propriedade Curso no modelo e então localiza a propriedade Nome a partir do objeto e a usa para a propriedade Text.

Mas neste momento você pode estar se perguntando: " Como o SilverLight conhece a origem do modelo ? "

Boa pergunta , garoto !

Aqui entra o segundo conceito do data binding : O data context.

A maioria dos controles SilverLight expõe a propriedade DataConext e pela configuração desta propriedade você pode efetivamente dizer ao SilverLight onde esta o modelo que ele deve usar. Desta forma no código abaixo temos a definição do model que vai ser vinculado com os componentes SilverLight <TextBlock> do arquivo XAML e exibir os valores correspondentes na interface.

Aluno aluno = new Aluno()
{
    Nome = "Macoratti",
    ID = 1,
    Curso = new Curso() { Nome = "Matemática" }
};
this.DataContext = aluno

Você pode definir a propriedade DataContext a qualquer momento tão logo o componente SilverLight correspondente seja inicializado. No código acima , this representa o user Control, de forma que nos estamos definindo o data context para todo o controle e todos os controles TextBlock usados irão obter os valores a partir do mesmo model. Isto ocorre porque o SilverLight percorre a árvore de controles para encontrar o DataContext onde o model existe.

Dessa forma, a binding expression {Binding Nome} no primeiro TextBlock irá primeiro procurar para a propriedade DataContext do próprio controle, e, se ela não encontrar, irá procurar pela propriedade DataContext para o componente StackPanel que é o pai do TextBlock e se isto falhar , o SilverLight irá procurar a propriedade DataContext no nível do UserControl. Esta "herança de contexto" significa que somente precisamos definir o DataContext uma única vez para a página inteira e a definição irá fluir pela página, mas se precisarmos podemos definir múltiplas propriedades DataContext no interior de uma árvore de controles e também sobrescrever contextos herdados.

Abra o Visual Studio 2008 e crie um novo projeto SilverLight usando o template SIlverLight  Application e a linguagem Visual Basic com o nome SilverLightAplicacao;

A seguir aceite hospedar a aplicação em uma página web conforme as configurações exibidas na janela abaixo e clique em OK;

Será criada um projeto com a estrutura abaixo onde a página que será exibida será  SilverLightAplicacaoTeste.aspx

Na pasta ClientBin será colocado o projeto SilverLight após a sua compilação. Vamos dar um Build na aplicação e espiar a pasta ClientBin que agora esta vazia...

Observe que a após a compilação temos na pasta ClientBin o arquivo SilverLightAplicacao.xap conforme a figura ao lado;

O arquivo SilverLightAplicacao.xap contém todos os recursos necessários para executar o controle SilverLight. Na verdade ele é um arquivo zipado renomeado para XAP.(É este arquivo que o plug-in SilverLight baixa e executa.)

A seguir defina o seguinte leiaute na janela XAML:

<Canvas Margin="30,26,31,34">

<Button Height="23" Width="193" Canvas.Left="43" Canvas.Top="8" Content="Vincular Aluno" x:Name="Bind" Click="btnBind_Click"/>

<TextBlock Height="20" Width="107" Canvas.Left="43" Canvas.Top="51" Text="ID:" TextWrapping="Wrap"/>

<TextBox Canvas.Left="170" Canvas.Top="52" Text="{Binding ID}" TextWrapping="Wrap" x:Name="txtID" Width="66"/>

<TextBlock Height="20" Width="107" Text="Nome:" TextWrapping="Wrap" Canvas.Left="43" Canvas.Top="91.269"/>

<TextBox x:Name="txtNome" Text="{Binding Nome}" TextWrapping="Wrap" Canvas.Left="170" Canvas.Top="91" Width="238"/>

<TextBlock Height="15" Width="83" Canvas.Left="43" Canvas.Top="144" Text="Conceito" TextWrapping="Wrap"/>

<TextBox x:Name="txtConceito" Text="{Binding Conceito}" Canvas.Left="170" Canvas.Top="135" TextWrapping="Wrap" Width="66"/>

</Canvas>

Vamos abrir esta aplicação no Expression Blend clicando com o botão direito sobre a página MainPage.xaml e selecionando a opção Open with Expression Blend;

Iremos obter a seguinte visão do nosso projeto no Expression Blend;

Vamos agora definir o código abaixo no arquivo code-behind MainPage.xaml.vb;

Partial Public Class MainPage

                 Inherits UserControl

 

Public Sub New()

      InitializeComponent()

End Sub

 

Private Sub btnBind_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

     Dim oAluno As New Aluno With {.ID = "1001", .Nome = "Jos‚ Carlos Macoratti", .Conceito = "A"}

 

      Me.txtID.DataContext = oAluno

        Me.txtNome.DataContext = oAluno

      Me.txtConceito.DataContext = oAluno

 

End Sub

End Class

Observe que estou definindo a classe Aluno com três propriedades e atribuindo um valor a elas.

Em seguida estou usando a propriedade DataContext para vincular o objeto oAluno que é um  instância da classe Aluno que representa o nosso aluno.

O DataContext se refere a fonte de dados que pode ser vinculada. O DataContext é com frequência definida para uma instância de uma entidade, e uma vez definida, ele pode ser vinculado a qualquer controle. Ele pode ser usado para vincular todos os controles no interior de um container a uma única fonte de dados. Isto pode ser muito útil quando existem muitos controles e todos vão usar a mesma fonte. (Veremos como fazer isso para vincular coleções.)

Executando o projeto no Visual Studio 2008 iremos obter a página SilverLightAplicacaoTeste.aspx exibindo os controles e após clicar no botão - Vincular Aluno - os dados serão vinculados e exibidos nos controles da página:

Vinculando Coleções

Muitas vezes precisamos vincular listas de dados como uma lista de alunos ou produtos. Neste cenário é como usar o controle ListBox do SilverLight.

O controle ListBox sabe como exibir uma coleção de itens pela replicação de um data template para cada item. Um data template descreve os controles que você quer usar quando estiver exibindo cada item individual em uma coleção.

Podemos pensar em um data template como sendo uma mini-controle pois ele contém um monte de controles filhos. O controle ListBox simplesmente cria uma instância deste mini-controle para cada objeto na coleção model. Vejamos um exemplo a seguir:

Crie um novo projeto no Visual Studio 2008 do tipo  SIlverLight  Application e a linguagem Visual Basic com o nome SL_DataBinding2;

A seguir aceite hospedar a aplicação em uma página web conforme as configurações exibidas na janela abaixo e clique em OK;

Inclua um novo item no projeto do tipo Class com o nome Aluno.vb e defina a nossa classe Aluno conforme abaixo:

Public Class Aluno

Private _id As Integer

Private _nome As String

Private _conceito As String

 

Property ID() As Integer

Get

    Return _id

End Get

    Set(ByVal value As Integer)

_id = value

End Set

End Property
 

Property Nome() As String

Get

    Return _nome

End Get

Set(ByVal value As String)

    _nome = value

End Set

End Property


Property
Conceito() As
String

Get

    Return _conceito

End Get

Set(ByVal value As String)

     _conceito = value

End Set

End Property


End
Class

 

 No arquivo MaingPage.xaml inclua o código conforme exibido abaixo:

<UserControl x:Class="SL_DataBinding2.MainPage"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

<StackPanel>

    <ListBox ItemsSource="{Binding}" Height="261" Margin="0,0,221,0">

             <ListBox.ItemTemplate>

                   <DataTemplate>

                   <TextBlock Text="{Binding Nome}"></TextBlock>

                    </DataTemplate>

             </ListBox.ItemTemplate>

       </ListBox>

</StackPanel>

</UserControl>

Este código define um StackPanel e um controle ListBox que utiliza um DataTemplate usando um controle TextBlock para vincular uma coleção de Nomes e exibir no ListBox.

A propriedade ItemSource do ListBox é a propriedade que irá referenciar a coleção que desejamos vincular. Neste caso nós usamos a binding expression {Binding}, e isto significa que nos queremos todo o DataContext. Neste cenário o modelo é ele próprio uma coleção de objetos. Poderíamos ter navegado no modelo definindo uma expressão como : {Binding Aluno.Conceito}

Note que a  propriedade ItemTemplate da lista é definida para o DataTemplate e que no interior do DataTemplate temos um único TextBlock usado para exibir a propriedade Nome de cada objeto no modelo. Neste caso nos estamos usando um único TextBlock mas o DataTemplate suporta múltiplos controles como images, videos, TextBlock e elementos gráficos.

No arquivo code-behind MainPaing.xaml.vb defina a rotina carregaLista()  que vai criar uma coleção de alunos e em seguida usar a propriedade DataContext do ListBox para atribuir a coleção criada;

Executando o projeto iremos obter:

Podemos alterar as definições do Binding no arquivo MainPage.xaml conforme a figura abaixo para poder exibir o ID, o nome e o conceito:

<UserControl x:Class="SL_DataBinding2.MainPage"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

<StackPanel>

       <ListBox ItemsSource="{Binding}" Height="261" Margin="0,0,221,0">

              <ListBox.ItemTemplate>

                          <DataTemplate>

                                 <StackPanel Orientation="Horizontal">

                                        <TextBlock Text="{Binding ID}"></TextBlock>

                                        <TextBlock Text=" " />

                                        <TextBlock Text="{Binding Nome}"></TextBlock>

                                        <TextBlock Text=" " />

                                        <TextBlock Text="{Binding Conceito}"></TextBlock>

                         </StackPanel>

                           </DataTemplate>

                     </ListBox.ItemTemplate>

         </ListBox>

</StackPanel>

</UserControl>

Observe que incluímos um StackPanel no interior do DataTemplate e definimos o binding nos controles TextBlock para as propriedades ID, Nome e Conceito. O resultado após a execução é exibido a seguir:

O SilverLight também possui a capacidade de atualizar a interface do usuário quando houver uma alteração no modelo. Vejamos como usar este recurso

No nosso exemplo estamos exibindo o conceito do aluno e se houver uma alteração na propriedade Conceito do modelo desejamos que a interface seja  atualizada para refletir esta alteração.

Para obter este resultado temos que implementar a interface INotifyCollectionChanged, e felizmente já existe uma classe que podemos usar que faz esta implementação.

Quando você inclui ou exclui objetos em uma coleção , a coleção irá automaticamente disparar o evento CollectionChanged. Quando o SilverLight estabelece um data binding ele irá olhar para ver se a coleção implementa a interface  INotifyCollectionChanged e se isto for verdade ele irá sobrescrever este evento.

Isto significa que você não tem que fazer nenhum trabalho adicional quando estiver efetuando uma binding em uma coleção observável. Se fazermos a vinculação na coleção com a propriedade ItemsSource de um ListBox, por exemplo, então o ListBox irá automaticamente exibir  os novos objetos incluídos e/ou incluídos da coleção.

Para outros tipos de vinculações que não sejam coleções a interface usada é a INotifyPropertyChanged que obriga que um objeto implemente o evento PropertyChanged. No caso da nossa classe Aluno a implementação ficaria da seguinte forma:

Imports System.ComponentModel

Public Class Aluno
         Implements INotifyPropertyChanged

Private _id As Integer
Private _nome As String
Private _conceito As String

Property ID() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property

Property Nome() As String
Get
Return _nome
End Get
Set(ByVal value As String)
_nome = value
End Set
End Property

Property Conceito() As String
Get
Return _conceito
End Get
Set(ByVal value As String)
   If _conceito <> value Then
      _conceito = value
       RaisePropertyChanged("Conceito")
   End If
End Set
End Property

Public Event PropertyChanged(ByVal sender As Object, ByVal e As  _ 
               PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

Private Sub RaisePropertyChanged(ByVal propertyName As String)
Dim handler As var = PropertyChanged
If (Not (handler) Is Nothing) Then
      handler(Me, New PropertyChangedEventArgs(propertyName))
End If
End Sub

End Class

Tudo que precisamos fazer foi lançar o evento PropertyChanged passando o nome da propriedade que foi alterada como um argumento do evento para que as alterações feitas se reflitam na interface.

Existem muito a fazer e a falar sobre o SIlverLight, e este artigo apresentou alguns conceitos básicos para que você possa compreender aos poucos o poder dessa incrível ferramenta.

Aguarde em breve mais artigos sobre o SilverLight.

Eu sei é apenas SIlverLight , mas eu gosto...

referências:


José Carlos Macoratti