SilverLight 4 - Usando o DataGrid II - CRUD


Na primeira parte deste artigo eu apresentei o controle DataGrid e algumas de suas características para exibição de informações.

Neste artigo eu vou continuar a usar o exemplo do artigo anterior para mostrar como permitir as operações CRUD no DataGrid.

Através da utilização de um DataGrid, nós conseguimos gerenciar uma coleção de livros representada por List(Of Livro) exibindo a coleção em uma aplicação SilverLight.
Vamos agora tornar possível adicionar, atualizar e excluir os itens desta coleção através do DataGrid.

O Silverlight possui a classe ObservableCollection<T> que fica no namespace System.Collections.ObjectModel, que fornece notificações, quando a coleção é modificada, incluindo, alterando ou mesmo excluindo algum item. Através desse recurso quando definimos uma lista ou coleção como fonte de dados de um DataGrid, quando adicionamos qualquer item na coleção o DataGrid é atualizado de forma automática.
(Para que isso ocorra a interface INotifyCollectionChanged deverá ser implementada)

Obs: Essa mesma característica esta presente no controle DataGrid da WPF.

Um ObservableCollection gera um evento quando os itens são adicionados, removidos e alterados e a aplicação SilverLight reage a isso atualizando o DataGrid.

No nosso exemplo vamos permitir ao usuário editar os itens clicando em um botão e incluiremos também um painel que irá exibir os detalhes do item selecionado no controle DataGrid.

Objetivo: Permitir a inclusão , edição e exclusão dos itens da coleção em controle DataGrid customizado;

premissas:

- Os usuários poderão alterar os dados através de um botão;
- Será exibido um Painel com os detalhes do item selecionado no DataGrid;

No Visual Web Developer 2010 Express Edition abra projeto com o nome SilverLight_DataGrid criando no artigo anterior;

Vamos iniciar alterando o leiaute da página XAML no arquivo MainPage.xaml da seguinte forma:

1- Vamos incluir acima do DataGrid um cabeçalho com o título - Coleção de livros - e logo abaixo uma linha com dois botões: um para incluir e outro para excluir itens conforme mostra a imagem a seguir:


<Grid.RowDefinitions>
            <RowDefinition Height="60"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="250"></RowDefinition>
            <RowDefinition Height="200"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock x:Name="TitleTextBlock" Grid.Row="0" Grid.ColumnSpan="2" Text="Relação de Livros" FontSize="28" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
        <StackPanel x:Name="ActionsStackPanel" Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" Background="#888888">
            <TextBlock x:Name="ActionsTextBlock" Text="Ações=" Margin="3" VerticalAlignment="Center" Foreground="White"></TextBlock>
            <Button x:Name="AddButton" Content="Incluir Livro" Click="AddButton_Click" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
            <Button x:Name="DeleteButton" Content="Excluir Livro" Click="DeleteButton_Click" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
        </StackPanel>

Observe que definimos um StackPanel e incluímos dois controles Buttons onde declaramos os eventos AddButton_Click e DeleteButton_Click;

2- Vamos incluir também, logo abaixo do DataGrid, um painel onde iremos exibir os detalhes do item selecionado no DataGrid conforme a figura abaixo:

 <Grid Grid.Row="3" DataContext="{Binding ElementName=DataGrid1, Path=SelectedItem}" Background="LightGray" Margin="2 10 0 0">
            <Grid.RowDefinitions>
                <RowDefinition Height="40"></RowDefinition>
                <RowDefinition Height="40"></RowDefinition>
                <RowDefinition Height="40"></RowDefinition>
                <RowDefinition Height="40"></RowDefinition>
                <RowDefinition Height="40"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock Text="Detalhes" FontSize="25" Grid.ColumnSpan="2" FontWeight="Bold" Grid.Row="0"></TextBlock>
            <TextBlock Text="Titulo:" FontWeight="Bold" Grid.Row="1" Grid.Column="0"></TextBlock>
            <TextBlock Text="{Binding Titulo}" Grid.Row="1" Grid.Column="1"></TextBlock>
            <TextBlock Text="Autor:" FontWeight="Bold" Grid.Row="2" Grid.Column="0"></TextBlock>
            <TextBlock Text="{Binding Autor}" Grid.Row="2" Grid.Column="1"></TextBlock>
            <TextBlock Text="Páginas:" FontWeight="Bold" Grid.Row="3" Grid.Column="0"></TextBlock>
            <TextBlock Text="{Binding Paginas}" Grid.Row="3" Grid.Column="1"></TextBlock>
            <TextBlock Text="Editor:" FontWeight="Bold" Grid.Row="4" Grid.Column="0"></TextBlock>
            <TextBlock Text="{Binding Editor}" Grid.Row="4" Grid.Column="1"></TextBlock>

Dessa forma o nosso novo leiaute para a aplicação deverá ficar conforme é mostrado na figura abaixo:

Vamos agora ajustar o código da aplicação...

No arquivo MainPage.xaml.vb nós vinculamos uma lista genérica de livros (List(Of Livro)) ao DataGrid. Para permitir que o DataGrid reaja as alterações feitas na coleção vinculada ela terá que implementar a interface INotifyCollectionChanged e assim ao invés de usar uma lista - List(Of Livro) - vamos usar a classe ObservableCollection - ObservableCollection(Of Livro) - substituindo o código anterior conforme abaixo:

Private livroColecao As List(Of Livro)     Substituir para =>   Dim livroColecao As New ObservableCollection(Of Livro)()

Por conta desta alteração deveremos alterar também na rotina carregaLivros substituindo a List(of Livro) por ObservableCollection(Of Livro) na seguinte linha de código:

livroColecao = New ObservableCollection(Of Livro)()

Vamos agora tratar dos eventos que deverão ser tratados no DataGrid. São eles:

Quando o usuário pressionar a Tecla Delete vamos remover o item selecionada da coleção e para isso temos que definir o evento KeyDown no DataGrid conforme o código a seguir:

<sdk: DataGrid x: Name = "BookDataGrid" KeyDown="DataGrid1_KeyDown" ...>

Para tratar a edição desde o início até o seu término devemos definir os eventos BeginningEdit e CellEditEnded de forma que a declaração do nosso DataGrid no arquivo MainPage.xaml deverá ficar assim:

 <sdk:DataGrid Name="DataGrid1"
                      Grid.Row="2"
                      AutoGenerateColumns = "True"
                      RowBackground="#999999"
                      AlternatingRowBackground="#CCCCCC"
                      ColumnWidth="170"
                      RowHeight="30"
                      HeadersVisibility="All"
                      KeyDown="DataGrid1_KeyDown"
                      BeginningEdit="DataGrid1_BeginningEdit"
                      CellEditEnded="DataGrid1_CellEditEnded
"
                      >
</sdk:DataGrid>

Agora temos que definir o código relacionado aos eventos declarados de forma que a ação desejada seja executada. Para isso vamos definir no arquivo MainPage.xaml.vb o código para cada um dos eventos definidos acima e também para os eventos AddButton_Click do botão para incluir itens e DeleteButton_Click do botão para excluir itens criados na página XAML. O código incluído deverá ficar assim:

Private Sub AddButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        IncluirLivro()
    End Sub

    Private Sub DeleteButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        RemoverLivro()
    End Sub

    Private modoEdicao As Boolean = False

    Private Sub DataGrid1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs) Handles DataGrid1.KeyDown
        If e.Key = Key.Delete AndAlso Not modoEdicao Then
            RemoverLivro()
        ElseIf e.Key = Key.Insert AndAlso Not modoEdicao Then
            IncluirLivro()
        End If
    End Sub

    Private Sub IncluirLivro()
        Dim b As New Livro()
        livroColecao.Add(b)
    End Sub

    Private Sub RemoverLivro()
        If DataGrid1.SelectedItem IsNot Nothing Then
            Dim deleteBook As Livro = TryCast(DataGrid1.SelectedItem, Livro)
            livroColecao.Remove(deleteBook)
        End If
    End Sub

- Nos eventos DeleteButton_Click e DataGrid1_KeyDown, se a tecla pressionada for a tecla Delete, chamamos a rotina RemoverLivro();

- Nos eventos AddButton_Click e DataGrid1_KeyDown, se a tecla pressionada for a tecla Insert , chamamos a rotina IncluirLivro();

As rotinas RemoverLivro e IncluirLivro estão definidas a seguir e removem e incluem um item na coleção de livros.

Observe que definimos a variável modoEdicao como False e estamos usando essa variável para verificar se estamos editando um valor que esta na célula ou simplesmente temos uma linha selecionada.

Para realizar esta verificação foram incluídos os eventos BeginningEdit e CellEditEnded no DataGrid e eles serão acionados quando uma célula entra ou sai do modo de edição.

Dessa forma temos que definir o código nesses dois eventos de forma a saber se estamos no modo de edição ou não alterando o valor da variável modoEdicao conforme abaixo:

   Private Sub DataGrid1_BeginningEdit(ByVal sender As System.Object, ByVal e As System.Windows.Controls.DataGridBeginningEditEventArgs)
        modoEdicao = True
   End Sub

   Private Sub DataGrid1_CellEditEnded(ByVal sender As System.Object, ByVal e As System.Windows.Controls.DataGridCellEditEndedEventArgs)
        modoEdicao = False
   End Sub

E pronto !!! Com essas alterações temos o nosso DataGrid pronto para edição, inclusão e exclusão de itens da coleção como podemos ver na figura a seguir:

Simples , simples assim...

Então resumindo temos:

- Um DataGrid vinculado a um ObservableCollection(Of Livro) e desta forma as alterações feitas na coleção são refletidas no controle de forma imediata graças a sincronização automática que o databinding nos oferece em coleções que implementam a interface INotifyCollectionChanged. Dessa forma basta a classe implementar a interface INotifyCollectionChanged, e, as alterações nos itens individuais serão refletidas no DataGrid.

- Implicitamente um DataGrid implementa uma vinculação TwoWay onde a alteração é feita na origem e no destino, ou seja, a alteração da propriedade altera a fonte de dados;

- Para remover um item pressionando a tecla Delete, precisamos primeiro verificar se não estamos editando o valor da célula. Se estivermos editando a linha não deve ser excluída. Isso é feito usando os eventos BeginningEdit e CellEditEnded. O primeiro é chamado antes que o usuário possa editar o valor. Os eventos também podem ser usados para executar alguma ação sobre o valor da célula, tais como a formatação.

No fim das contas, a gestão (inserção, exclusão e edição) dos dados no DataGrid desce para a gestão dos itens na coleção pois na verdade não estamos incluindo itens no DataGrid mas estamos incluindo, removendo e alterando itens em uma coleção vinculada ao controle DataGrid.

Pegue o projeto completo aqui: SilverLight_DataGrid.zip

Eu sei é apenas SilverLight 4 , mas eu gosto...

Referências:

José Carlos Macoratti