Vou começar este texto fazendo uma referência à minha introdução já feita no artigo
.
Tenho escrito pouco sobre a tecnologia SilverLight, primeiro devido à
falta de tempo e depois pelas constantes mudanças e evoluções que o
SilverLight tem passado. Você vai dormir usando a versão 3 e quando
acorda já tem a versão 4.
De qualquer forma, em 2011 pretendo dar um pouco mais de atenção ao
SilverLight e um bom começo é ter o ambiente corretamente ajustado para
poder usar a tecnologia.
Lembrando que o SilverLight foi lançado em meados de 2007 e desde
então tem evoluído muito. Enquanto o ASP .NET é uma plataforma para
desenvolvimento do lado do servidor, com a chegada do
SilverLight o foco muda para o lado do cliente, visto que uma aplicação
SilverLight roda no navegador do cliente em uma versão específica da
CLR (Common Language Runtime).
Se o SilverLight é algo totalmente novo mas você conhece o WPF, fique
sabendo que o SilverLight pode ser considerado como uma versão reduzida
do WPF, sendo possível inclusive reutilizar código escrito no
SilverLight 4 no WPF 4 e vice-versa.
Preparando o terreno
Para iniciar o desenvolvimento de aplicações SilverLight precisamos ter instalados as ferramentas e os SDKs necessários.
- Instalar o Visual Studio 2010 ou o Visual Web Developer Express 2010;
- Instalar o SilverLight 4 Tools for Visual Studio 2010;
- Instalar o Expression Blend 4;
Após baixar e instalar as ferramentas acima, não ocorrendo nenhum
erro, tudo estará pronto para você dar início a saga de desenvolver
aplicações para o SilverLight.
Invocando um serviço que expõe dados
Ao trabalhar em um projeto Silverlight que envolve serviços, o WCF
(Windows Comunication Foundation) é a escolha preferida para a
construção de um serviço se temos que criar este e o aplicativo cliente
do Silverlight que irá utilizá-lo. Dessa forma, usando o WCF temos um
controle completo sobre quais tipos serão enviados para o cliente.
Quando queremos construir uma aplicação Silverlight que trabalha com
os dados disponíveis sobre o serviço (talvez proveniente de um banco de
dados ou outro serviço externo), precisamos ter em mente as seguintes
questões:
- Como devemos projetar o serviço que expõe os dados de modo que possa ser acessível a partir do Silverlight?
- Como devemos proceder para projetar o aplicativo do Silverlight, para que ele se comunica com o serviço?
Para mostrar como podemos nos conectar a partir do Silverlight com um
serviço WCF que expõe os dados, vamos começar com a concepção do
próprio serviço.
Observação: O artigo foi baseado em alguns exemplos prontos que foram adaptados e ajustados.
Vamos supor que estamos construindo uma aplicação que contém uma
janela de visualização onde o usuário poderá obter informações sobre os
funcionários de uma empresa.
Os dados do funcionário serão expostos pelo serviço e o aplicativo
Silverlight irá se conectar ao serviço e trabalhar com os dados no lado
do cliente. A seguir estão os passos que precisa executar para começar
este trabalho.
Dica importante: para tornar mais simples o exemplo não vamos trabalhar com um banco de dados mas iremos preencher os dados via código.
Dando a partida: criando a aplicação SilverLight 4
Abra o Visual Web Developer 2010 Express Edition no menu File
selecione New Project. A seguir selecione Visual C# e o template
SilverLight > SilverLight Application, informe o nome
SilverLightFuncionarios e clique em OK.

Será apresentada a janela abaixo, onde vemos o projeto do tipo ASP
.NET Web Application Project selecionado como o tipo de projeto web que
será usado para hospedar a aplicação SilverLight. Note que a versão do
SilverLight escolhida é a versão 4.

Após fazer estas verificações clique em OK. Será criada uma solução com dois projetos:
- O projeto SilverLight: SilverLightFuncionarios;
- O projeto Web: SilverLightFuncionarios.web - responsável por hospedar o conteúdo SilverLight;

Vamos nos concentrar primeiro na aplicação web. Os dados que
desejamos expor consistem em informações sobre os funcionários. Vamos
então definir as classes que representam o domínio do nosso problema.
A seguir vemos o diagrama de classes que mostra as classes do nosso domínio:

O diagrama de classes acima mostra o relacionamento entre as classes e
a enumeração CarroTipo. Note que a classe Funcionario é uma classe
abstrata e que as demais classes herdam da classe Funcionario.
Dica Importante: Utilizando classes
abstratas você pode declarar classes que definam apenas parte de uma
implementação, deixando que as classes estendidas forneçam a
implementação específica de alguns ou de todos os métodos. Uma classe
abstrata em geral será destinada apenas a servir como base para a
criação de outras classes.
O próximo passo é criar as classes no projeto
SilverLightFuncionarios.web. Vamos começar criando a classe Funcionario.
Selecione o projeto SilverLightFuncionarios.web e no menu Project
clique em Add Class. A seguir informe o nome Funcionario.cs e clique no
botão Add.

Repita o procedimento acima e crie as seguintes classes:
- Gerente.cs
- Consultor.cs
- Administrativo.cs
- CarroTipo.cs
Após criar os arquivos para as classes vamos definir o código da classe Funcionario.cs conforme abaixo:
using System;
using System.Runtime.Serialization;
namespace SilverlightFuncionarios.Web
{
[DataContract]
[KnownType(typeof(Gerente))]
[KnownType(typeof(Consultor))]
[KnownType(typeof(Administrativo))]
public abstract class Funcionario
{
[DataMember]
public int funcionarioid { get; set; }
[DataMember]
public string nome { get; set; }
[DataMember]
public string email { get; set; }
[DataMember]
public DateTime nascimento { get; set; }
}
}
Vamos entender a classe Funcionario:
- A classe é uma classe abstrata e isso indica que a classe não pode ser instanciada e deve ser herdada por outra classe.
- O atributo DataContract usado na classe indica que o tipo pode ser enviado via rede.
- DataContract especifica que o tipo define ou implementa um contrato
de dados e é serializável por um serializador, como o
DataContractSerializer. Para fazer o seu tipo serializável, os autores
do tipo devem definir um contrato de dados para o seu tipo.
- O atributo DataMember usado nos campos da classe será incluído no tipo e poderá ser enviado via rede para o lado do cliente.
- O DataMember quando aplicado ao membro de um tipo, especifica que o
membro faz parte de um contrato de dados e é serializável pelo
DataContractSerializer.
- O atributo KnowType marca os tipos a serem incluídos no processo de serialização.
- O atributo de classe KnownType permite que você especifique,
antecipadamente, os tipos que devem ser incluídos para apreciação
durante a desserialização.
Agora vamos definir o código da classe Gerente conforme o código a seguir:
using System.Runtime.Serialization;
namespace SilverlightFuncionarios.Web
{
public class Gerente : Funcionario
{
[DataMember]
public double Gratificacao { get; set; }
[DataMember]
public CarroTipo Carro { get; set; }
}
}
A classe Gerente herda da classe Funcionario e define os campos:
Observação: Para poder usar os atributos
DataContrat e DataMember, talvez você terá que incluir uma referência a
System.RunTime.Serialization no projeto web.
Abaixo temos a definição da classe Consultor:
using System.Runtime.Serialization;
namespace SilverlightFuncionarios.Web
{
public class Consultor : Funcionario
{
[DataMember]
public CarroTipo Carro { get; set; }
}
}
A classe Consultor herda da classe Funcionario e define o campo:
Observação: Para poder usar os atributos
DataContrat e DataMember talvez você terá que incluir uma referência a
System.RunTime.Serialization no projeto web.
A seguir temos o código da classe Administrativo:
namespace SilverlightFuncionarios.Web
{
public class Administrativo : Funcionario
{
}
}
A classe Administrativo herda da classe Funcionario. Finalmente o código da enumeração CarroTipo:
namespace SilverlightFuncionarios.Web
{
public enum CarroTipo
{
Esportivo,
Passeio,
Utilitario
}
}
Nosso próximo objetivo será criar uma classe chamada FuncionarioRepositorio
que será usada para carregar os dados de exemplo. Em uma aplicação real
geralmente carregaríamos os dados de um banco de dados. Para criar a
classe repita o procedimento usado para criar a classe Funcionario.
O código desta classe é definido como:
using System;
using System.Collections.Generic;
namespace SilverlightFuncionarios.Web
{
public class FuncionarioRepositorio
{
private static List<Funcionario> todosFuncionarios;
public FuncionarioRepositorio()
{
carregaFuncionarios();
}
private void carregaFuncionarios()
{
if (todosFuncionarios == null)
{
todosFuncionarios = new List<Funcionario>()
{
new Gerente()
{
funcionarioid=1,
nome="Macoratti",
email="macoratti@yahoo.com",
carro=CarroTipo.Esportivo,
gratificacao=10000.00,
nascimento=new DateTime(1960, 1, 1)
},
new Consultor()
{
funcionarioid=2,
nome="Mario",
email="mario@bol.com.br",
carro=CarroTipo.Passeio,
nascimento=new DateTime(1976, 11, 9)
},
new Consultor()
{
funcionarioid=3,
nome="Janice",
email="janice@uol.com.br",
carro=CarroTipo.Utilitario,
nascimento=new DateTime(1983, 3, 12)
},
new Consultor()
{
funcionarioid=4,
nome="Jefferson",
email="jeff@net.com",
carro=CarroTipo.Passeio,
nascimento=new DateTime(1984, 6, 7)
},
new Administrativo()
{
funcionarioid=5,
nome="Miriam",
email="miriam@uol.com.br",
nascimento=new DateTime(1970, 9, 22)
},
new Administrativo()
{
funcionarioid=6,
nome="Jose",
email="jose@bol.com.br",
nascimento=new DateTime(1973, 2, 19)
},
};
}
public List<Funcionario> TodosFuncionarios
{
get
{
return todosFuncionarios;
}
}
}
}
A classe FuncionarioRepositorio usa uma lista estática de funcionários: private static List<Funcionario> todosFuncionarios.
Agora que definimos as classes do nosso domínio e a classe que irá
popular os objetos da nossa classe vamos incluir um serviço WCF no
projeto web. Selecione o projeto SilverLightFuncionarios.web e no menu
Project clique em Add New Item.
Na caixa de diálogo Add New Item veremos duas opções para adicionar um serviço WCF:
- SilverLight-enabled WCF Service;

Vamos selecionar o item SilverLight-enabled WCF Service e informe o
nome FuncionarioService e clique no botão Add. Será criado um arquivo
FuncionarioService.csv conforme a figura abaixo:

Vamos fazer alguns ajustes no arquivo FuncionarioService gerado para
habilitar os serviços WCF. O serviço deverá apresentar dois métodos:
- O primeiro deverá recuperar todos os funcionários;
- O outro deverá recuperar um funcionário pela identificação do funcionário;
Cada método deverá estar disponível no lado do cliente e deverá ter o
atributo OperacionContract que indica que o método define uma operação
que é parte de um contrato de serviço em uma aplicação.
Dessa forma o código implementado no serviço deverá chamar o método
TodosFuncionarios da classe FuncionarioRepositorio conforme abaixo:
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
namespace SilverlightFuncionarios.Web
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class FuncionarioService
{
[OperationContract]
public List<Funcionario> GetTodosFuncionarios()
{
return new FuncionarioRepositorio().TodosFuncionarios;
}
[OperationContract]
public Funcionario GetFuncionarioPorId(int funciid)
{
return new FuncionarioRepositorio().TodosFuncionarios.Where
(e => e.funcionarioid == funciid).FirstOrDefault();
}
}
}
Com isso encerramos os ajustes do lado do cliente e podemos partir
para o lado do servidor. Antes de continuar compile a aplicação (Build).
Selecione o projeto SilverLight SilverLightFuncionarios e no menu
Project clique em Add Service Reference.
A seguir clique no botão Discover e selecione: Services in Solution.
Se o serviço estiver disponível ele deverá aparecer na caixa Services.

Se o serviço puder ser conectado sem erros, ele irá aparecer na lista
de serviços e em Operations serão exibidos os nomes dos métodos
criados. A seguir selecione o serviço e informe o nome
FuncionarioService e clique no botão OK.

Depois de clicar no botão OK, Visual Web Developer 2010 Express
tentará construir um proxy que é mais ou menos uma cópia do lado do
cliente da classe de serviço. Na janela Solution Explorer o serviço
poderá ser visto conforme mostra a figura a seguir:

Vamos agora cuidar da interface onde iremos usar o serviço criado.
Selecione o projeto SilverLightFuncionarios e no menu Project clique em
Add Reference e inclua referência a System.Windows.Controls.Data. Em
seguida clique com o botão direito do mouse sobre o projeto e selecione
Add > New Folder e informe o nome Converters para a pasta criada.
Depois vamos incluir dois arquivos que serão usados como conversores
de data para o campo Nascimento e moeda para o campo Gratificação:
Observação: Não vou entrar em detalhes sobre os conversores, irei apenas usá-los no projeto. Se você quiser saber mais sobre eles consulte este link.
Selecione o arquivo MainPage.xaml e a partir da ToolBox inclua os seguintes controles conforme o leiaute da figura abaixo;
- TextBlock
- TextBox
- Button
- DataGrid
A seguir temos a exibição do código XAML correspondente:

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="SilverlightFuncionarios.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"
xmlns:local="clr-namespace:SilverlightFuncionarios.Converters" Loaded="UserControl_Loaded"
d:DesignHeight="450" d:DesignWidth="550" DataContext="{Binding}">
<UserControl.Resources>
<local:ShortDateConverter x:Key="localShortDateConverter"></local:ShortDateConverter>
<local:CurrencyConverter x:Key="localCurrencyConverter"></local:CurrencyConverter>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" Height="450" Width="550">
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock x:Name="TitleTextBlock" Grid.Row="0" Grid.ColumnSpan="2" Text="Macoratti.net - SilverLight" FontSize="24" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
<StackPanel Grid.Row="1" Background="Bisque" >
<Grid Margin="3" HorizontalAlignment="Center" >
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="300"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Grid.ColumnSpan="2">
<TextBlock x:Name="FunciIDTextBlock" VerticalAlignment="Center" Margin="2">Cod. Funci.::</TextBlock>
<TextBox x:Name="FunciIDTextBox" HorizontalAlignment="Left" Width="200" VerticalAlignment="Center" Margin="2"></TextBox>
<Button x:Name="ProcuraFunciButton" Click="ProcuraFunciButton_Click" Margin="2" Content="Procurar Funci" Width="120" Height="30" HorizontalAlignment="Center"></Button>
<TextBlock x:Name="ErrorTextBlock" Foreground="Red"></TextBlock>
</StackPanel>
<data:DataGrid x:Name="FunciDataGrid" Grid.Row="1" SelectionChanged="FunciDataGrid_SelectionChanged" CanUserReorderColumns="False"
IsReadOnly="True" AutoGenerateColumns="False" Width="316" Margin="0,0,3,0">
<data:DataGrid.Columns>
<data:DataGridTextColumn Binding="{Binding funcionarioid}" Header="Cod.Funci"></data:DataGridTextColumn>
<data:DataGridTextColumn Binding="{Binding nome}" Header="Nome"></data:DataGridTextColumn>
<data:DataGridTextColumn Binding="{Binding email}" Header="Email"></data:DataGridTextColumn>
</data:DataGrid.Columns>
</data:DataGrid>
<Grid x:Name="DetailGrid" Grid.Row="1" Grid.Column="1" Width="219" Margin="3,3,-10,3">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock x:Name="FunciIdTextBlock" Grid.Row="0" Grid.Column="0" Text="Cod. Funci:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="FunciIdValueTextBlock" Grid.Row="0" Grid.Column="1" Text="{Binding funcionarioid}"></TextBlock>
<TextBlock x:Name="NomeTextBlock" Grid.Row="1" Grid.Column="0" Text="Nome:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="NomeTextBlockValue" Grid.Row="1" Grid.Column="1" Text="{Binding nome}" ></TextBlock>
<TextBlock x:Name="EmailTextBlock" Grid.Row="2" Grid.Column="0" Text="Email:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="EmailTextBlockValue" Grid.Row="2" Grid.Column="1" Text="{Binding email}" ></TextBlock>
<TextBlock x:Name="NascimentoTextBlock" Grid.Row="3" Grid.Column="0" Text="Nascimento:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="NascimentoTextBlockValue" Grid.Row="3" Grid.Column="1" Text="{Binding nascimento, Converter={StaticResource localShortDateConverter}}" ></TextBlock>
<TextBlock x:Name="GratificacaoTextBlock" Grid.Row="4" Grid.Column="0" Text="Gratificação:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="GratificacaoTextBlockValue" Grid.Row="4" Grid.Column="1" Text="{Binding gratificacao, Converter={StaticResource localCurrencyConverter}}" ></TextBlock>
<TextBlock x:Name="CarroTextBlock" Grid.Row="5" Grid.Column="0" Text="Carro:" FontWeight="Bold"></TextBlock>
<TextBlock x:Name="CarroTextBlockValue" Grid.Row="5" Grid.Column="1" Text="{Binding carro}" ></TextBlock>
</Grid>
</Grid>
</StackPanel>
</Grid>
</UserControl>
Na interface teremos as informações dos funcionários exibidas no
controle DataGrid e os seus detalhes nos controles TextBlock conforme o
funcionário selecionado. Observe o uso dos conversores localShortDateConverter e localCurencyConverter para os campos nascimento e gratificação.
Observe que estamos utilizando os recursos do DataBinding, vinculando
cada controle ao nome do membro e definido na classe de domínio. A
classe Binding está no namespace System.Windows.Data e é
responsável por manter a comunicação entre a origem e o destino, expondo
uma série de propriedades que nos permite customizar o comportamento
dessa comunicação.
Entre as principais propriedades, temos:
- ElementName: define o nome do elemento que
servirá como fonte. Utilize esta propriedade quando desejar preencher
uma outra propriedade com o valor de um controle do WPF.
- Mode: determina a direção das informações.
- NotifyOnSourceUpdated: valor boleano indicando se o evento SourceUpdated é disparado quando alguma atualização na fonte das informações ocorrer.
- NotifyOnTargetUpdated: valor boleano indicando se o evento SourceUpdated é disparado quando alguma atualização no destino das informações ocorrer.
- Path: espefica o nome da propriedade que será exibida.
- RelativeSource: especifica uma fonte de forma relativa à posição do objeto atual.
- Source: define o nome do objeto que servirá como
fonte. Utilize esta propriedade quando desejar preencher com uma
instância de um objeto.
- XPath: a mesma finalidade da propriedade Path, mas define uma expressão XPath quando a fonte de informações for um arquivo Xml.
Dessa forma temos a interface pronto para ser usada, receber e exibir as informações de funcionários.
Acompanhe a segunda parte do artigo onde vamos implementar o código no arquivo MainPage.xaml.cs referente ao evento Click do botão Procurar Funci, que irá chamar a rotina carrega TodosFuncionarios - responsável por usar o serviço criado para obter as informações dos funcionários.
Eu sei é apenas SilverLight 4,
mas eu gosto...
artigo publicado originalmente no iMasters, por José Carlos Macoratti