Professional Documents
Culture Documents
1
Índice
2
C- Integração de Navegador do Silverlight ...........................................................................51
Introdução ............................................................................................................................51
Seção 1 – Expondo Funções .NET ao Navegador. ...............................................................52
Entendendo o XAML e o Código .NET do Silverlight .............................................................52
Expondo um método .NET ao JavaScript ..............................................................................54
Chamando o Método .NET a partir do JavaScript. .................................................................55
Seção 2 – Manipulando a Árvore de Renderização XAML a partir do Navegador ..............57
Atualizando elementos XAML existentes ...............................................................................57
Criando novos Elementos XAML ...........................................................................................58
Mais Estudo...........................................................................................................................60
Seção 3 – Chamando o Script do Navegador a partir de .NET ............................................61
Mais Estudo...........................................................................................................................63
D- Personalizando a Aparência ..............................................................................................64
Introdução ............................................................................................................................64
Objetivos do Laboratório: .....................................................................................................64
Exercício 1: Criando o controle deslizante do Voyager ........................................................65
Tarefa 1: Montando seu controle deslizante .....................................................................66
Tarefa 2: Personalizando o controle deslizante ..................................................................69
Tarefa 3: Personalizando o Elevador .................................................................................71
Tarefa 4: Testando nosso controle deslizante. ...................................................................74
Tarefa 5: Exercícios para o usuário....................................................................................74
Apêndices .................................................................................................................................75
Exercício 1: Respostas das Tarefas ......................................................................................75
Tarefa 2: Personalizando o controle deslizante. .................................................................75
Tarefa 3: Personalizando o Elevador .................................................................................77
E- Layout Personalizado no Silverlight .................................................................................82
Introdução ............................................................................................................................82
Objetivos do Laboratório: .....................................................................................................83
Seção 1: Criando um WrapPanel Personalizado ..................................................................84
Tarefa 1: Crie uma classe WrapPanel ..............................................................................85
Tarefa 2: Meça seus Filhos para encontrar seu Tamanho Desejado. ...............................86
Tarefa 3: Organize nossos filhos .........................................................................................87
Tarefa 4: Exercitando nosso Painel .....................................................................................88
3
Seção 2 – Implementando um TimelineStackPanel para a aplicação do Voyager .............89
Tarefa 1: Crie uma classe TimelineStackPanel ..................................................................91
Tarefa 2: Implementando Measure (Medida) em nosso TimelineStackPanel .....................91
Tarefa 3 Adicionando Propriedades de Dependência Anexadas ao TimelineStackPanel..92
Tarefa 4: Notificando o Panel quando um Begin ou End for alterado .................................93
Tarefa 5: Adicionando Propriedades de Dependência Low e High ao nosso Painel. ..........95
Tarefa 6: Notificando o Panel que as propriedades Low/High mudaram ............................97
Tarefa 7: Implementando o Arrange (Organizar) ................................................................98
Tarefa 8: Resolvendo um problema de Conversor ...........................................................100
Tarefa 9: Testando nosso TimelineStackPanel a partir do código ....................................101
Tarefa 10: Testando nosso TimelineStackPanel a partir do XAML ...................................102
Tarefa 11: Exercícios para o usuário................................................................................102
Apêndices ...............................................................................................................................103
Seção 1: Respostas das Tarefas .........................................................................................103
Tarefa 1: Crie uma classe WrapPanel..............................................................................103
Tarefa 2: Medindo nossos filhos ......................................................................................103
Tarefa 3: Passo 1 – Substituindo o Arrange .....................................................................103
Tarefa 3: Passo 2 -- Implementando o Arrange ...............................................................104
Tarefa 4: Exercitando nosso WrapPanel. .........................................................................104
Exercício 2: Respostas das Tarefas ....................................................................................105
Tarefa 1: Criando um TimelineStackPanel .......................................................................105
Tarefa 3: Adicionando propriedades de dependência anexadas para Begin e End ..........105
Tarefa 4: Notificando o Panel quando um Begin ou End for alterado ...............................106
Tarefa 5: Adicionando Propriedades de Dependência Low e High ao nosso Painel. ........107
Tarefa 6: Notificando o Panel que as propriedades Low/High mudaram ..........................107
Tarefa 7: Implementando o Arrange.................................................................................108
Tarefa 8: Resolvendo um problema de Conversor ...........................................................109
Tarefa 9: Testando nosso TimelineStackPanel a partir do código ....................................110
Tarefa 10: Testando nosso TimelineStackPanel a partir do XAML ...................................110
Tarefa 11: Exercícios para o usuário................................................................................110
F- Usando Dados nas Aplicações do Silverlight ................................................................111
Introdução ...............................................................................................................................111
Objetivos do Laboratório: ........................................................................................................111
4
Tarefa 1: Criando uma Ligação Simples usando XAML e DataContext............................113
Tarefa 2: Ligando a uma Coleção (usando um DataTemplate) ........................................114
Tarefa 3: Substituindo a Listbox por um DataGrid ............................................................116
Tarefa 4: Personalizando as colunas no DataGrid ...........................................................117
Tarefa 5 – Exibição Mestre/Detalhes usando Ligações a partir do código........................118
Tarefa 6: Exercício para o usuário ...................................................................................120
Apêndice .................................................................................................................................121
Seção 1: Respostas das Tarefas .........................................................................................121
Tarefa 1: Criando uma Ligação Simples usando XAML e DataContext ............................121
Tarefa 2: Ligando a uma Coleção (usando um DataTemplate) ........................................121
Tarefa 3: Substituindo a Listbox por um DataGrid ............................................................124
Tarefa 4: Personalizando as colunas no DataGrid ...........................................................125
Tarefa 5: Implementando InotifyPropertyChanged (Passo 17) .........................................126
Tarefa 6 - Implementando INotifyPropertyChanged (Passo 9). .......................................127
G- Construindo um Media Player Simples ..........................................................................128
Seção 1: Criando uma Página de Mídia no Silverlight .......................................................129
Seção 2: Adicionando controles de Reprodução à sua Mídia ...........................................131
Seção 3: Usando o Progresso de Download e o Progresso de Buffer ..............................133
Seção 4: Gerenciando Marcadores de Mídia.......................................................................134
H- Silverlight e Aplicações Conectadas ..............................................................................136
Introdução ...............................................................................................................................136
Seção 1: Usando o WebClient para Ler Dados Remotos de Ligação para o Silverlight ..137
Tarefa 1: Crie uma aplicação do Silverlight e adicione a Classe CityData ...........................137
Tarefa 2: Crie o Serviço XML ..............................................................................................138
Tarefa 3: Crie o XAML ao qual fará ligações .......................................................................140
Tarefa 4: Crie a solicitação e o retorno de chamada do WebClient .....................................141
Tarefa 5: Ligando os Dados no Retorno de Chamada .........................................................143
Mais Estudo.........................................................................................................................144
Seção 2: Usando WebRequest / WebResponse para obter Dados ...................................145
Tarefa 1: Crie o Projeto e instale a aplicação de servidor ....................................................146
Tarefa 2: Crie a interface de usuário do Silverlight ..............................................................148
Tarefa 3: Escreva a lógica da interface de usuário e da Ligação de Dados .........................149
Seção 3: Construindo e Ligando a um Serviço WCF .........................................................152
5
Tarefa 1: Crie o Projeto do Silverlight e adicione o Serviço WCF ........................................153
Tarefa 2: Crie o Cliente do Silverlight e Ligue-o ao Serviço .................................................154
Apêndices ...............................................................................................................................156
Seção 1: Respostas das Tarefas .........................................................................................156
Tarefa 1: Classe CityData ................................................................................................156
Tarefa 2: Manipulador Genérico.......................................................................................156
Tarefa 3: XAML Ligado ....................................................................................................157
Tarefa 4: Criando a chamada para o Serviço POX ..........................................................157
Tarefa 5: Ligando os Dados no Retorno de Chamada .....................................................158
Seção 2: ..............................................................................................................................158
Tarefa 1: Função GetCities ..............................................................................................158
Tarefa 2: XAML da interface de usuário ...........................................................................159
Seção 3 ...............................................................................................................................161
Tarefa 1: Classe de Dados de Cidades ............................................................................161
6
A- Princípios Básicos do
Silverlight 2
Conceitos básicos do desenvolvimento do Silverlight 2
Este laboratório explora as ferramentas e os recursos fundamentais que servem de base para qualquer
aplicação do Silverlight.
O laboratório não foi projetado para ser feito do início ao fim. Ele foi estruturado como uma série de
exercícios práticos ‘passo a passo’, ilustrando determinadas técnicas. Você é estimulado a explorar e
experimentar. Pense em um exemplo do que gostaria de construir, e use as instruções deste laboratório
como degraus para alcançar esse objetivo.
O conteúdo deste laboratório é baseado na versão Beta 2 do Silverlight 2. Essa é uma versão preliminar
que não representa o conjunto final de recursos ou a funcionalidade final.
Conteúdo:
7
Seção 1: Criando uma Aplicação Simples
com Silverlight
Esta seção ilustra as técnicas básicas de programação necessárias em qualquer aplicação Silverlight:
construção e depuração, trabalho com objetos de interface de usuário e manipulação de entrada.
Com as ferramentas do Silverlight para Visual Studio instaladas, o Visual Studio 2008 permite que você
construa e depure projetos do Silverlight. Os passos a seguir demonstrarão esse processo e ilustrarão
alguns dos recursos dos projetos do Silverlight 2 que são diferentes de outros projetos no Visual Studio.
4. Para depurar e testar um projeto do Silverlight, você vai precisar de um projeto de site na
solução. Isso será separado do projeto do Silverlight propriamente dito – os projetos do
Silverlight apenas constroem um pacote binário do Silverlight conhecido como um arquivo XAP –
vamos falar brevemente sobre isso. Já que isso significa que você normalmente trabalhará com
pelo menos dois projetos, não se esqueça de marcar a caixa de verificação ‘Create directory for
solution’. Dê um nome adequado ao projeto (para este laboratório, vamos usar
FirstSilverlightProject) e clique no botão ‘OK’.
8
5. A seguinte caixa de diálogo aparecerá:
Um projeto do Silverlight não pode ser executado isoladamente – ele deve sempre ser
executado no contexto de uma página da Web pai, que é onde o controle do Silverlight
propriamente dito é incorporado. O assistente permite que você escolha como isso acontecerá.
(Observação: você também pode estabelecer uma associação entre um projeto do Silverlight e
um projeto da web no Solution Explorer do Visual Studio. Se você clicar com o botão direito em
qualquer projeto da web que faça parte de uma solução que contém um projeto do Silverlight,
verá uma opção ‘Add Silverlight Link...’ no menu de contexto. Portanto você sempre tem a
opção de reorganizar a estrutura de seu projeto se mudar de idéia com relação as escolhas que
fez nesse assistente).
A segunda opção, ‘Dynamically generate an HTML test page to host Silverlight within this
project’, é a mais simples – ela apenas cria um único arquivo HTML (oculto) para você que será
usado para incorporar o plug-in do Silverlight. Contudo, isso é insatisfatório por duas razões.
Primeiro, não há acesso ao ambiente de design completo que o Visual Studio pode oferecer para
um projeto da web (particularmente útil se o conteúdo do Silverlight não for a totalidade da
página mas meramente um elemento). E em segundo lugar, isso significa que quando você
executa a aplicação, ela será executada a partir de um arquivo HTML local no disco, em vez de
via HTTP. Um arquivo HTML local pode não fornecer um ambiente realista no qual você executa
seu código, devido ao contexto de segurança em que o navegador será executado.
O terceiro botão de opção do assistente fica desativado porque você acabou de criar uma nova
solução. Se você fosse adicionar um novo Projeto do Silverlight a uma solução existente que já
continha um site, isso permitiria que você usasse esse site para executar o conteúdo do
Silverlight.
Nesse caso, a primeira opção: ‘Add a new Web to the solution for hosting the control’ é a mais
apropriada. Você pode então escolher o tipo de projeto da web – um Projeto de Site ou um
9
Projeto de Aplicação da Web. Essa escolha não faz diferença para o Silverlight – ele está lá
porque o ASP.NET tem suporte para dois estilos diferentes de projeto da web. Para este
laboratório, escolhemos 'Web Site’.
Por fim, note que a caixa de verificação ‘Copy to configuration specific folders’ determina se o
diretório de saída é aninhado para dar suporte a múltiplas configurações de compilação (build).
Se você quiser construir tanto a versão de ‘lançamento’ quanto a de ‘depuração’ de seu arquivo
XAP, por exemplo, é melhor marcar essa caixa.
Clique em OK. O Visual Studio vai criar os dois projetos – seu projeto do Silverlight e um site
para hospedá-lo.
6. Dos dois arquivos que o Visual Studio abre após criar o projeto, um deles não é de uso imediato
para você neste laboratório. Ele abrirá a Default.aspx, a página principal de sua aplicação da
web. No entanto, essa página não tem seu conteúdo do Silverlight. Em vez disso, o assistente
adicionou uma segunda página, que será chamada de ProjectNameTestPage.aspx, e a tornou a
página padrão para depuração. (FirstSilverlightProjectTestPage.aspx, neste caso). Feche ou
exclua a Default.aspx e abra a FirstSilverlightProjectTestPage.aspx.
7. Note que perto do topo desse arquivo aspx, uma montagem (assembly) é trazida ao escopo
contendo as extensões do ASP.NET que têm suporte para o Silverlight:
Essas extensões incluem o controle <asp:Silverlight>, que é como esse projeto carrega seu
conteúdo do Silverlight, como você pode ver mais abaixo na página. (Se você estiver
familiarizado com a técnica do Silverlight 1.0 de usar o script Silverlight.js, e chamar uma função
JavaScript para carregar o controle do Silverlight, esse método ainda funciona, mas não é o
modo como o assistente do Silverlight escolhe fazer as coisas).
9. Construa o projeto a fim de criar esse arquivo .xap. No Windows Explorer, vá e encontre o
arquivo, que você encontrará na pasta FirstSilverlightProject_Web\ClientBin. Note que o
diretório ClientBin fica oculto por padrão; na janela de ferramentas do Solution Explorer
(Gerenciador de Soluções), você pode visualizá-lo clicando no botão Show All Files na barra de
ferramentas:
10
10. Esse arquivo .xap é na verdade apenas um arquivo ZIP. Faça uma cópia desse arquivo e depois
renomeie a extensão da cópia de .xap para .zip. Dê um clique duplo no arquivo ZIP para abri-lo,
e você verá que ele contém apenas dois arquivos: um DLL que contém todo o código C#
compilado de seu projeto do Silverlight e um arquivo AppManifest.xaml. Esse manifesto lista os
conteúdos do ZIP e indica qual DLL contém o ponto de entrada. O DLL também contém a
linguagem XAML (eXtensible Application Markup Language) que descreve a interface de usuário
de sua aplicação – todos os arquivos XAML são compilados dentro do DLL como recursos
incorporados.
11. Tente adicionar um bitmap ao seu projeto do Silverlight. Basta usar o item do menu de contexto
‘Add Existing Item’ no Solution Explorer. (Lembre-se de adicionar isso ao seu projeto do
Silverlight, e não o projeto da web associado). Uma vez que tiver adicionado isso, o Visual Studio
vai definir a Ação de Compilação (Build) como Conteúdo. Em um projeto do Silverlight, isso
significa que o item será adicionado ao arquivo .xap – tente reconstruir o projeto e depois repita
o processo de extrair os conteúdos do arquivo .xap, e você verá o bitmap que acabou de
adicionar al lado do DLL e manifesto.
12. Para testar seu projeto, você vai precisar de algum conteúdo no Page.xaml, caso contrário não
haverá nada para ver. Nós começaremos com algo trivial. Abra o Page.xaml e dentro de Grid,
adicione o seguinte:
Essa marcação cria um botão chamado BigButton que contém o texto “Click Me!” (Clique em
mim!) na fonte de sistema padrão, com um tamanho de 36pt.
11
Click="BigButton_Click" />
14. Em uma aplicação do Silverlight 2, as páginas XAML normalmente têm um arquivo code-behind
que define o comportamento da interface de usuário. Por convenção, o arquivo code-behind é
nomeado com um “.cs” (ou “.vb” para um projeto do Visual Basic) no final do nome do arquivo
XAML. Então abra o Page.xaml.cs para ver o code-behind de seu arquivo XAML. Note que o
Visual Studio criou automaticamente um manipulador de eventos para o evento de clique em
botão, desta forma:
15. No menu, escolha Build / Build Solution para garantir que a conclusão do código do Visual Studio
esteja em sincronia com o novo XAML que você adicionou.
16. Dentro do manipulador de eventos de clique, adicione as duas linhas de código a seguir:
17. Ponha um ponto de interrupção na primeira linha do código especificado no passo anterior (o
que você pode fazer colocando o cursor nessa linha e pressionando F9). Comece a depurar o
projeto pressionando F5. (Isso também vai construir o projeto para você). Na primeira vez em
que depurar um projeto do Silverlight no estilo ‘site’ do projeto da web, você verá a seguinte
mensagem:
18. Uma janela do navegador da web vai aparecer com o conteúdo do Silverlight. Clique no botão.
Logo depois, o Visual Studio deve mostrar que você acessou o ponto de interrupção, verificando
que você é capaz de depurar o código C# que está sendo executado no navegador da web.
12
19. Pressione F5 para permitir que a aplicação continue. O navegador da web deve estar mostrando
agora o texto atualizado dentro de um botão vermelho.
Controles Adicionais
Vale a pena destacar que na versão Beta 2, alguns controles mais complexos como DataGrid,
Calendar, TabControl e GridSplitter não estão incluídos no tempo de execução básico, mas estão
incluídos em montagens separadas (o DataGrid está em System.Windows.Controls.Data.dll e os
outros estão em System.Windows.Controls.Extended.dll). Isso significa que você não os verá por
padrão quando usar o IntelliSense. Veja como pode adicioná-los:
Primeiro, você precisará adicionar uma referência a uma dessas montagens ou a ambas. No
projeto do Silverlight, clique com o botão direito no nó de Referências e escolha “Add
Reference...”. Dentro da guia do .NET, role para baixo até encontrar
System.Windows.Controls.Data e .Extended (redimensione a primeira coluna para ver os nomes
completos):
13
Agora você pode fazer referência aos controles dentro desses namespaces a partir do código.
Para acessá-los a partir do XAML, você também precisará adicionar referências a namespaces no
topo de seu arquivo XAML, imediatamente após as declarações de namespace xmlns e xmlns:x
padrão. Use as duas linhas de código a seguir:
xmlns:ex="clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Extended"
xmlns:data="clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
Agora está pronto. Tudo o que você precisa lembrar de fazer é usar o escopo de namespace, por
exemplo, <data:DataGrid> para instanciar o DataGrid ou <ex:Calendar> para instanciar o
Calendar.
Crédito Extra
Se você quiser ser mais independente e explorar um pouco, experimente. Por exemplo,
verifique as outras propriedades disponíveis no elemento Button a partir do editor do XAML, ou
substitua o Button por um elemento TextBox, TextBlock ou Calendar. (Não se esqueça de
remover ou editar o manipulador de eventos na visualização do código também). Você pode
alterar as propriedades a partir do XAML ou da visualização do código; pode também adicionar
um código de inicialização extra após a chamada InitializeComponent() no construtor de
Páginas.
14
Seção 2: Layout, Controles e Conteúdo
de Vetor
Até agora aprendemos a criar um projeto do Silverlight, adicionar um elemento e interagir com
esse elemento através do uso de manipuladores de eventos definidos no código C#. Mas nossa
aplicação do Silverlight não vai ser muito flexível com apenas um controle.
Painéis são elementos que podem conter múltiplos elementos filhos, e que determinam os
tamanhos e as posições desses filhos. O mais simples é o Canvas – este só tem suporte para
layout fixo, e funciona do mesmo modo que no Silverlight 1.0. O Grid e o StackPanel são de
maior interesse. Eles são novos no Silverlight 2 (e funcionam do mesmo modo que seus
homônimos no WPF).
As seções a seguir ilustram o uso básico dos novos painéis, e apresentam alguns exemplos de
como múltiplos painéis podem ser combinados para produzir layouts mais complexos.
Canvas
Observação: Se você já estiver familiarizado com o Silverlight 1.0, pode pular esta seção e
proceder à do container StackPanel.
A opção mais simples é projetar seu conteúdo do Silverlight com um tamanho fixo, posicionar
elementos individuais com coordenadas (x,y) absolutas e organizar sua página da web para
acomodar esse tamanho fixo. Isso funciona bem quando você está incorporando conteúdo do
Silverlight dentro de um conteúdo HTML existente e o redimensionamento automático do
conteúdo do Silverlight não faz parte das considerações. Os passos a seguir mostram como fazer
isso.
Crie um novo projeto do Silverlight no Visual Studio chamado FixedSize. Deixe que o Visual
Studio crie uma Web associada para hospedar o conteúdo do Silverlight.
Abra o Page.xaml. Note que o elemento raiz já tem um tamanho fixo – as propriedades Width e
Height foram definidas em 400 e 300 pixels respectivamente. Por padrão, o conteúdo do
UserControl é um Grid; substitua os elementos de abertura e de fechamento pelo Canvas, que é
uma boa opção para layout fixo.
15
Dentro do elemento Canvas, adicione:
Rectangle e Ellipse são os dois primitivos simples para desenhar; mais tarde, você verá um
elemento Path muito mais sofisticado que tem suporte para curvas de Bézier, linhas e formatos
preenchidos. Note que as propriedades anexadas Canvas.Left e Canvas.Top fornecem controle
baseado em pixel sobre a localização coordenada dos elementos.
Ter que adicionar e posicionar cada elemento à mão com o XAML é algo bastante trabalhoso.
Em vez disso, vamos explorar brevemente o Expression Blend, uma ferramenta de design
interativo que funciona junto com o Visual Studio para fornecer uma experiência de design rica
par ao layout de conteúdos em um arquivo XAML. Clique com o botão direito em Page.xaml e
escolha “Open in Expression Blend”. Você verá o mesmo conteúdo abrir na ferramenta de
design:
Mude a visualização para o modo ‘Divisão’, usando as guias do lado direito do Canvas. Isso
permitirá que você veja como o XAML muda conforme você edita o formato, ou que edite o
XAML à mão e veja o efeito imediatamente.
16
Para começar, vamos ver as classes de formato. Elas podem ser encontradas em dois ícones na
barra de ferramentas à esquerda:
A ferramenta Pen (Caneta) permite desenhar curvas de Bézier clicando e arrastando. Se você
arrastar, ela desenhará segmentos de linha curvados. Se você clicar, ela desenhará ângulos, e se
arrastar dois ou mais ângulos em seguida eles serão unidos por segmentos de linha retos. No
XAML, o formato é definido pela propriedade Data do elemento Path, que usa uma sintaxe SVG
compacta para representar o contorno do path.
O Silverlight usa a mesma sintaxe que o Windows Presentation Foundation; se quiser aprender
mais sobre ela, está documentada em:
http://msdn2.microsoft.com/library/system.windows.media.pathgeometry.aspx.
Os outros dois tipos de formato para os quais o Blend tem suporte são o Rectangle e o Ellipse.
Eles estão disponíveis no item da barra de ferramentas abaixo da Pen. (Clique e mantenha
pressionado o mouse para fazer o submenu aparecer – ele só mostrará uma das ferramentas
por vez. Note que Line não é um formato separado – é apenas uma forma mais simples de criar
objetos Path). Você pode definir a largura e a altura desses formatos, e no caso de um Rectangle
(Retângulo), o Blend fornece alças de ajuste para arredondar os ângulos. Tente ajustá-los e veja
o efeito que isso tem no XAML.
Todos os formatos podem ter seu Fill (Preenchimento) e Stroke (Traço) ajustados da mesma
forma. No lado direito, certifique-se de que o painel Properties (Propriedades) está selecionado,
e você poderá editá-los nas seções Brushes e Appearance (Pincéis e Aparência). Faça um teste e
observe o efeito que têm visualmente e no Xaml.
Observação: O Silverlight tem suporte para uma gama um pouco maior de formatos que o
Blend. Ele também tem suporte para Line (Linha), Polygon (Polígono) e Polyline (Polilinha). O
17
Blend não os usa porque tudo o que fazem também pode ser feito com o Path. Mas se você
gostaria de testá-los no XAML, encontrará a documentação para eles no Visual Studio
Documentation, pesquisando pelo namespace System.Windows.Shapes,
Para certos tipos de gráficos, imagens de bitmap podem ser mais apropriadas que os gráficos
orientados a vetor escaláveis oferecidos pelos tipos de formato. Então a seguir você usará a
marca Image, que tem suporte para arquivos de bitmap JPEG e PNG. No Blend, selecione a guia
‘Project’ no canto superior direito. Aparecerá uma exibição de árvore de seu projeto. Clique com
o botão direito no item de projeto (FixedSize) (o que está abaixo da Solução) e selecione
Adicionar item existente. Encontre qualquer imagem de bitmap – pode ser uma das imagens
JPEG de exemplo que vêm com o Windows - e abra-a.
Arraste o arquivo de imagem que acabou de adicionar da exibição de árvore do Projeto para a
superfície de design. Redimensione-a se necessário para fazer com que caiba no espaço.
(Certifique-se de que tem a ferramenta Selection ativa para poder mover e redimensionar itens.
É a ferramenta no topo da barra de ferramentas à esquerda). Inspecione o XAML para ver o
elemento de Imagem que ele criou para mostrar sua imagem.
Observação: o MediaElement, que tem suporte para a reprodução de arquivos de vídeo, pode
ser usado da mesma forma que o elemento Image do Blend. Tente adicionar um arquivo WMV
ao seu projeto da mesma forma que adicionou uma imagem. (A documentação do Silverlight
descreve os formatos de arquivo de mídia para os quais o Silverlight tem suporte).
Finalmente, você vai testar o TextBlock. Ele pode ser encontrado no final da barra de
ferramentas. Note que o TextBox e o TextBlock compartilham o mesmo local na barra de
ferramentas; TextBox é para edição de texto, enquanto o TextBlock apenas exibe o texto.
Certifique-se de que selecionou o TextBlock – se não clicar e mantiver pressionado o botão da
barra de ferramentas para mostrar as duas opções.
No XAML, o elemento TextBlock tem suporte para duas maneiras de representar texto. Você
pode apenas definir a propriedade do texto diretamente como um atributo dentro da marca
TextBlock, por exemplo:
<TextBlock TextWrapping="Wrap">
<Run Text="This is some " />
<Run FontWeight="Bold" Text="formatted " />
<Run FontStyle="Italic" Text="text." />
<LineBreak />
<Run Text="It spans multiple lines." />
</TextBlock>
18
Embora o Blend defina elementos Width e Height (largura e altura) quando você arrasta um
TextBlock, o bloco vai se autodimensionar se você não especificar essas coisas de maneira
explícita. Tente remover o Width e o Height. Tente então especificar apenas um Width,
certificando-se de que a propriedade TextWrapping está definida como “Wrap”.
Sinta-se à vontade para testar o Blend um pouco mais - use a janela de Propriedades à direita
para testar os pincéis, os gradientes, as transformações e a aparência. Salve então as alterações
e feche o Blend para retornar ao editor do Visual Studio. Note que o Visual Studio recarrega o
arquivo XAML para garantir que as alterações que você fez sejam atualizadas.
O XAML pode ser usado para representar quase todos os conteúdos de gráficos baseados em
vetor. O Expression Design contém suporte embutido para exportar sua saída ao XAML, e há
filtros e conversores de terceiros disponíveis para outros formatos como o Adobe Illustrator.
Para demonstrar isso, exclua tudo o que está dentro do elemento Canvas do projeto XAML.
Exploração extra opcional: Abra o Expression Design e explore essa ferramenta como um modo
de criar arte de vetor. Tente abrir uma das outras imagens de exemplo e exportá-la para o
XAML. Lembre-se de usar a opção (Silverlight” ou “XAML Silverlight Canvas” (dependendo de
qual versão do Expression Design você está usando) para criar um XAML compatível com o
subconjunto para o qual o Silverlight tem suporte:
19
Antes de terminar esse projeto, vamos explorar rapidamente o modo como o conteúdo do
Silverlight é hospedado dentro de um container HTML pai. O elemento Canvas dentro do XAML
fornece valores de largura e altura que definem o tamanho do container e restringe seus
elementos filhos, mas isso não afeta o tamanho do controle do Silverlight propriamente dito -
isso é feito a partir do HTML. Abra o arquivo FixedSizeTestPage.aspx e encontre o controle do
Silverlight. Por padrão, o projeto define o controle em um tamanho de 640x480:
Execute a aplicação. O conteúdo deve aparecer com o tamanho especificado. Tente adicionar
outro conteúdo HTML (por exemplo, um texto) antes e depois do controle do Silverlight, para
que você possa ver a posição do plug-in do Silverlight em relação ao conteúdo HTML. O controle
do Silverlight acaba encapsulando o plug-in com um <span>, para que ele se comporte como um
elemento embutido para fins de layout do HTML.
<style type="text/css">
.slPlugin
{
width: 640px;
height: 480px;
}
</style>
StackPanel
O StackPanel organiza seus filhos em uma pilha vertical ou horizontal. Se você estiver familiarizado
com o StackPanel do WPF, o do Silverlight 2 funciona da mesma forma.
20
1. Crie um novo projeto de aplicação do Silverlight; abra o Page.xaml e remova as propriedades
Width e Height explícitas do UserControl.
2. Substitua o elemento Grid por um StackPanel. Dentro do StackPanel, adicione alguns botões de
opção, como:
3. Veja como os itens são organizados em uma pilha vertical. Edite a propriedade Content de um
dos botões para que seja uma seqüência de caracteres muito mais longa, e note como o
StackPanel se redimensiona para o conteúdo filho.
6. Os StackPanels podem conter uma ampla variedade de elementos filhos. Faça uma experiência:
tente adicionar elementos de formato como elipses ou retângulos (não se esqueça de
especificar uma cor de preenchimento), ou controles como TextBox, Scrollbar, Calendar e Slider.
Tente aninhar um StackPanel dentro de um StackPanel. (Para facilitar a visualização da extensão
do painel, defina sua propriedade Background com uma cor sólida como “PaleGreen”).
Note que, diferentemente dos controles, que derivam de uma classe pai chamada UIElement e
têm um tamanho intrínseco determinado pelo seu conteúdo, elementos de formato como o
Rectangle são objetos mais primitivos por razões de desempenho, e não têm um tamanho
intrínseco a menos que você especifique uma Width e Height explícita. Já que um StackPanel só
oferece o espaço exato necessário na direção do empilhamento, você terá que especificar uma
Width (largura) para os elementos gráficos que são filhos do painel horizontal, e uma Height
(altura) para os que são filhos do painel vertical – caso contrário os elementos terão zero Width
ou Height respectivamente. (Você pode especificar tanto a Width como a Height se preferir.
Mas pode omitir a Height no painel horizontal já que o elemento vai simplesmente assumir a
altura total do painel; da mesma forma, se não especificar a Width de um elemento gráfico em
uma painel vertical, ele será tão largo quanto o próprio painel).
21
7. Tente adicionar uma propriedade Margin a um ou mais controles e veja como isso afeta o
layout. As margens podem ser especificadas como um valor único, como um par de valores
separados por vírgula que representam as margens esquerda/direita e superior/inferior
respectivamente, ou como um conjunto de quatro valores separados por vírgula que
representam as margens esquerda, superior, direita e inferior individualmente.
Grid
Grid é o container de layout mais sofisticado e flexível, permitindo que o conteúdo seja escalado
conforme o redimensionamento do container pai. O painel Grid dimensiona e posiciona seus
filhos gravando o espaço em uma grade. Você pode especificar o número de linhas e colunas de
que precisa, usando o dimensionamento fixo, automático ou proporcional. (Por exemplo, você
pode dar a uma coluna um quarto da largura e a outra o espaço remanescente). Os filhos de
uma grade podem ocupar uma única célula, ou podem abranger múltiplas células. As células
também podem conter múltiplos filhos. Os passos a seguir mostram esses recursos do Grid,
conforme vamos construindo um seletor de cores simples.
1. Crie um novo projeto do Silverlight chamado SimpleColorPicker. Deixe que o Visual Studio
crie uma Web associada para hospedar o conteúdo do Silverlight. Nós vamos criar uma
interface simples para selecionar qualquer cor que o Silverlight possa exibir. Vai ficar assim:
No lado esquerdo do seletor de cores estão quadro controles deslizantes para selecionar os
valores alfa, vermelho, verde e azul. No lado direito há uma pré-visualização da cor, junto com
seu valor hex e uma caixa de grupo para selecionar o modelo de cor que queremos usar. Há
várias formas de fazer o layout do conteúdo, mas nós vamos usar uma grade como o container
pai, dividindo-a em duas colunas de três linhas, com a primeira coluna abrangendo as três
linhas, como mostram as linhas vermelhas abaixo:
22
Dentro do Grid, adicione um elemento <Grid.ColumnDefinitions>. Dentro dele, adicione duas
marcas <ColumnDefinition />. Isso indica que a grade terá duas colunas. Da mesma forma,
adicione um elemento <Grid. RowDefinitions> contendo três marcas <RowDefinition />. O
código deve ficar assim:
Nós podemos modificar a largura das colunas ou a altura das linhas usando as propriedades
Width e Height, respectivamente. Elas podem ser especificadas como pixels absolutos (por
exemplo, ColumnDefinition Width="250"), como uma razão relativa a outras colunas ou linhas,
ou dimensionar automaticamente conforme seu conteúdo (use Width="Auto"). Para este
exemplo, vamos definir as larguras das colunas em 60% e 40%. Vamos começar mostrando as
linhas de grade para fins de depuração. Adicione o seguinte atributo ao elemento Grid:
Note as linhas azul/amarela na exibição do designer. (Esse recurso serve como um auxílio ao
desenvolvimento e não para o desenho de linhas de propósito geral. Use o elemento border
para ter um controle refinado sobre as bordas das células). Agora edite as larguras de cada
coluna, assim:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60*" />
<ColumnDefinition Width="40*" />
</Grid.ColumnDefinitions>
(É a razão dos valores que importa aqui, e não os valores absolutos. Nós podíamos ter definido
3* e 2* em vez de 60* e 40* e obtido exatamente o mesmo resultado).
Quando usamos o Canvas como um painel de container em uma seção anterior, pudemos
definir o local exato de seus filhos através do uso de propriedades anexadas. Definindo o
Canvas.Left e o Canvas.Top em qualquer elemento, nós poderíamos definir uma coordenada
(x,y) para qualquer elemento filho. Com um container escalável como o Grid, em vez de
especificar propriedades Top e Left, especificamos a célula em que o elemento deve aparecer
usando as propriedades anexadas Grid.Row e Grid.Column. Se quisermos um controle mais
refinado sobre o local desse elemento dentro de uma célula de grade, podemos aplicar uma
margem.
Na célula superior direita, vamos adicionar um retângulo que será preenchido com uma cor de
pré-visualização. Imediatamente antes do elemento </Grid> de fechamento, adicione o
seguinte:
23
<Rectangle Grid.Row="0" Grid.Column="1"
x:Name="PreviewColor"
Fill="CadetBlue" Margin="10" Stroke="#FF666666" StrokeThickness="2" />
Note que as linhas e colunas são baseadas em zero, portanto isso representa a primeira linha e a
segunda coluna. O x:Name é o que nos permitirá fazer referência a esse retângulo a partir do
código. O aspecto mais interessante do elemento acima é que não precisamos especificar de
forma explícita um tamanho para o retângulo – ele preenche automaticamente a célula (exceto
para a margem). Tente mudar o tamanho da margem e definir as propriedades RadiusX e
RadiusY para arredondar os ângulos do retângulo, e também a Width e a Height para ajustar o
tamanho do retângulo.
Às vezes é mais fácil aninhar os painéis do container um dentro do outro. Vamos adicionar uma
caixa de texto e rotular imediatamente abaixo da pré-visualização do retângulo. Adicione o
seguinte XAML:
Por padrão, o StackPanel é alinhado com o topo da célula; nós podemos ajustar isso
adicionando VerticalAlignment="Center". Tente isso agora.
Se você estiver familiarizado com outros ambientes como o Windows Forms, pode ficar
surpreso em ver que não há um container GroupBox para os botões de opção. Como o
Silverlight sabe quais botões de opção ficam juntos?
Por padrão, os botões de opção são agrupados de acordo com seu container pai (neste caso, o
StackPanel). Você pode, no entanto, mudar isso usando a propriedade GroupName – isso lhe
permite ter múltiplos grupos de botões por pai.
Por último, vamos adicionar os controles deslizantes para o lado esquerdo do controle.
24
Aqui você pode ver que estamos definindo uma propriedade RowSpan para mesclar as três
linhas na coluna esquerda. Isso nos dá uma forma conveniente de usar uma única grade,
embora nem todas as colunas tenham o mesmo número de linhas. Note o uso de um controle
Slider para permitir que o usuário selecione uma cor – por padrão ele vai do 0 ao 1, então
definimos explicitamente o máximo como 255 e os valores como o equivalente decimal de
#FF5F9EA0.
Concluímos o layout da aplicação, vamos agora remover a propriedade ShowGridLines já que ela
não é mais necessária:
Tudo o que precisamos fazer agora é adicionar um código à aplicação para cuidar do movimento
do controle deslizante. Posicione o cursor de texto após o atributo de Valor mas antes do
elemento de fechamento do Slider chamado AlphaSlider, e digite ValueChanged=
Uma dica de ferramenta do IntelliSense vai aparecer, oferecendo a você a oportunidade de criar
um novo manipulador de eventos:
Agora abra o Page.xaml.cs no Solution Explorer (um filho do Page.xaml), e verá que um stub do
manipulador de eventos foi adicionado ao código.
Vamos preencher esse manipulador de eventos com alguma lógica para atualizar o retângulo e a
caixa de texto de modo a corresponder aos valores atuais dos controles deslizantes:
O que estamos fazendo aqui é criar um novo objeto de cor com base no valor dos controles
deslizantes, e depois usá-lo em um pincel para preencher o retângulo, bem como atualizar a
caixa de texto. O valor dos controles deslizantes é armazenado como um valor de ponto
25
flutuante, então temos que converter cada um deles para um byte antes de passá-los ao
método estático Color.FromArgb(), que usa quatro parâmetros representando os valores alfa,
vermelho, verde e azul e retorna um objeto que representa a cor propriamente dita.
Já que queremos que o mesmo código seja executado independentemente de qual controle
deslizante é manipulado, podemos simplificar as coisas definindo o mesmo manipulador para o
evento ValueChanged de cada controle deslizante. Renomeie o manipulador de eventos de
AlphaSlider_ValueChanged para Slider_ValueChanged (corrija-o tanto no código C# quanto no
XAML). Agora vá até o XAML para o controle deslizante vermelho, e digite novamente
ValueChanged=
Observação: Você também pode usar a ligação de dados para conectar um elemento a uma
fonte de dados subjacente; para mais informações sobre o uso da ligação de dados dessa forma,
verifique o laboratório relacionado disponível separadamente.
Tente construir o projeto selecionando a opção do menu Build / Build Solution. A aplicação deve
compilar sem erros. Vamos vê-la em ação. Para isso, pressione F5 ou escolha Debug / Start
Debugging no menu. Se esta for a primeira vez que tenta executar este projeto, você verá a
seguinte caixa de diálogo:
Problema na Beta 2 Você verá que embora a aplicação compile, ela não é executada com
sucesso (você recebe um NullReferenceException). A razão para isso é que o evento
ValueChanged dispara durante a inicialização dos componentes, porém como os componentes
não estão totalmente carregados, não é possível acessá-los a partir do código. Há duas formas
de resolver isso: você pode tentar uma das duas para este laboratório. Adicione os
manipuladores de eventos a partir do código depois que o método InitializeComponent() tiver
disparado, ou defina um campo de bool particular na classe como verdadeiro quando o
InitializeComponent tiver executado e teste o valor do bool no evento antes de executar o
código. Agora reconstrua e execute.
26
Teste a aplicação: você deve conseguir mover os controles deslizantes e ver o preenchimento do
retângulo e a caixa de texto mudarem de acordo.
Agora vamos testar um pouco a depuração do Visual Studio. Sem fechar o navegador, mude
para o Visual Studio. Vá para a primeira linha de código no evento Slider_ValueChanged, e
adicione um ponto de interrupção pressionando F9 ou clicando na margem esquerda. Você verá
um ponto vermelho aparecer para indicar que um ponto de interrupção foi definido:
Agora tente mover um dos controles deslizantes. A aplicação vai disparar instantaneamente o
ponto de interrupção e o Visual Studio vai mudar para o modo de depuração. No final da tela,
você verá uma série de janelas de ferramenta diferentes que fornecem várias exibições da
aplicação em execução.
No lado esquerdo, a janela Autos mostra variáveis que são usadas nas instruções atuais e ao
redor; A janela Locals mostra todos os objetos no contexto atual; a janela Watch permite definir
uma observação em qualquer objeto ou propriedade que desejar. (Use o menu Debug /
Windows para adicioná-las ao seu editor se não vir uma delas por padrão). Você não apenas
pode ver as variáveis aqui, mas pode também modificá-las. Se nunca usou o Visual Studio antes,
tente isso: edite o GreenSlider.Value para que seja 255.0 e o RedSlider.Value para que seja 0.
(Você também pode modificar o BlueSlider.Value inserindo isso no lado esquerdo da grade de
propriedades da janela Watch – por padrão, isso não aparece porque o serviço de linguagem só
exibe as primeiras entradas automaticamente). Agora pressione F5 para continuar a execução
da aplicação. Você verá que os valores alterados são refletidos na aplicação no tempo de
execução. Quando terminar, feche o navegador e o Visual Studio vai voltar automaticamente ao
modo de edição. (Você pode desativar o ponto de interrupção pressionando F9 na devida linha
novamente).
Para provar que o Grid é um objeto fácil de escalar, vamos voltar à exibição do XAML no Visual
Studio. No topo do arquivo, você verá que já há uma largura e uma altura padrão aplicadas ao
UserControl de 400x300. Remova os atributos Width e Height. Você verá que a exibição do
design vai parecer minúscula repentinamente. O que está acontecendo agora é que o objeto
inteiro está se dimensionando para o mínimo que tenha suporte para seu conteúdo filho. Na
verdade, isso é tão pequeno que os controles deslizantes na coluna esquerda têm tão pouco
espaço que se tornam inúteis, portanto vamos ajustar isso um pouco.
27
Na coleção ColumnDefinitions, nós vamos adicionar propriedades MinWidth a ambas as colunas
para que o controle não possa ter uma dimensão menor que um tamanho específico. Defina a
largura mínima da primeira para 100 pixels, e a segunda para 90 pixels, assim:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60*" MinWidth="100"/>
<ColumnDefinition Width="40*" MinWidth="90"/>
</Grid.ColumnDefinitions>
(Note que esses valores não podem ser obedecidos se a janela do navegador obrigar o controle
geral do Silverlight a ser menor que esse tamanho).
Agora vamos executar a aplicação novamente. Desta vez, você deve conseguir redimensionar a
janela e fazer com que o controle fique visível.
28
Seção 3: Elementos e Objetos XAML
Conforme vimos acima, as interfaces de usuário do Silverlight são normalmente construídas com o
uso do XAML. Cada elemento da interface de usuário criado com XAML tem um objeto .NET
correspondente no Silverlight 2. Uma coisa importante a notar é que você não é obrigado a usar o
XAML para criar os elementos – você pode escrever um código que crie objetos de elemento da
interface de usuário diretamente, sem usar o XAML. A seção a seguir usa essa técnica para desenhar
um gráfico de barras.
1. Crie um novo projeto do Silverlight no Visual Studio chamado BarGraph. Deixe que o Visual
Studio crie uma Web associada para hospedar o conteúdo do Silverlight.
Abra o Page.xaml. Remova os elementos Width e Height do UserControl, e defina uma Width
(largura) e uma Height (altura) no Grid (grade) de 600 e 400 pixels respectivamente.
Adicione uma nova classe chamada GraphBuilder para seu projeto do Silverlight. Clique com o
botão direito no projeto BarGraph e escolha Add / Class.
Neste laboratório, vamos embutir em código alguns recursos do gráfico, portanto adicione os
seguintes campos à classe para representar essas configurações fixas:
Já que precisaremos repetir os mesmos passos para cada barra do gráfico, comece com um
loop:
29
{
}
Nós precisamos de uma coluna de grade para cada barra do gráfico, então adicione o seguinte
código:
Cada barra será representada por um Rectangle, então vamos criar um com preenchimento e
contorno adequados:
A Margem garante que haja algum espaço dos lados da barra. O VerticalAlignment garante que
a barra inicie na parte inferior do gráfico.
Note que é considerada uma escala vertical de 0 a 0.25. É uma escala razoável para essa
aplicação específica. Uma ferramenta de gráfico mais sofisticada precisaria, é claro, fazer algo
mais inteligente a respeito das escalas.
Para vê-la, temos que adicionar a barra ao gráfico. Isso significa definir sua coluna de grade e
adicioná-la à grade:
Finalmente, para ver os resultados de seu trabalho, você precisa chamar o código que escreveu.
Abra o arquivo code-behind Page.xaml.cs, e no construtor adicione o seguinte depois do
método InitializeComponent:
GraphBuilder.BuildGraphInGrid(LayoutRoot);
30
Execute a aplicação. Você deve ver uma série de barras como esta:
Se você não vir nada na tela, é possível que tenha pulado o passo em que define a altura e a
largura na grade. Definir essas propriedades na grade (em vez do controle) é importante,
porque sem ela o gráfico de barras é desenhado antes do dimensionamento da grade, o que
significa que ela terá largura e altura de “Auto” e altura e largura reais de 0. Como resultado,
todas as alturas das barras serão 0!
(Avançado). Remova a largura e a altura fixas do controle da grade e modifique a aplicação para
permitir que a grade seja reescalada conforme o usuário redimensiona a janela do navegador.
(Dica: você terá que interceptar o evento SizeChanged e corrigir um pouco o método
BuildGraphInGrid para que ele não continue adicionando colunas e retângulos toda vez que o
tamanho for alterado).
(Opcional). Use essa aplicação para testar mais o Silverlight. Aqui estão algumas idéias:
31
Seção 4: Manipulação de Entrada e
Eventos
Esta parte do laboratório se concentra em vários aspectos da manipulação de entrada.
Começamos olhando a manipulação básica de eventos de mouse e teclado, antes de cobrir
manipulações de eventos roteados mais avançadas, à medida que criamos um mini-jogo que
exercita tudo o que aprendemos até agora.
Nesta seção, você vai realizar algumas manipulações de eventos bastante simples, para permitir
que um objeto seja arrastado pelo controle do Silverlight com o mouse, e sua cor seja alterada
com o teclado.
Crie um novo projeto do Silverlight no Visual Studio chamado BasicInput. Deixe que o Visual
Studio crie uma Web associada para hospedar o conteúdo do Silverlight.
No Page.xaml, mude o elemento Grid para um Canvas e adicione uma elipse dentro do
elemento Canvas, assim:
Construa o projeto (Ctrl+Shift+B ou Build / Build Solution) para garantir que o IntelliSense fique
atualizado com as mudanças que você fez no XAML.
Se você pressionar a tecla TAB duas vezes, ele vai gerar o construtor delegado primeiro, e o
método do manipulador de eventos depois. Faça isso para os três eventos.
32
Remova de cada método o código que abre uma exceção. O Visual Studio adiciona isso para que
você não se esqueça de escrever o método. Aqui, isso só vai atrapalhar conforme avançarmos
pelos passos.
Você vai adicionar código que permite ao usuário arrastar a elipse. O manipulador MouseMOve
fará o trabalho, mas ele precisa saber duas coisas: se a operação arrastar está em progresso no
momento e, se estiver, onde o mouse estava com relação à elipse quando a operação arrastar
começou, para saber onde posicioná-lo agora. Para armazenar esse estado, adicione os
seguintes campos à classe Page:
dragInProgress = true;
dragOffset = e.GetPosition(ellipse);
if (dragInProgress)
{
Point mousePoint = e.GetPosition(this);
Canvas.SetLeft(ellipse, mousePoint.X - dragOffset.X);
Canvas.SetTop(ellipse, mousePoint.Y - dragOffset.Y);
}
Execute a aplicação. Você deve conseguir clicar na elipse para começar a arrastá-la, mas há dois
problemas a resolver. O primeiro e mais óbvio é que a operação arrastar continua depois que
você solta o mouse. Para corrigir isso, adicione o seguinte código ao manipulador
MouseLeftButtonUp:
dragInProgress = false;
O segundo problema, mais sutil, é que se você mover o mouse rápido demais, ele pode deixar a
elipse para trás. A razão disso é que uma vez que o mouse deixa a elipse, o manipulador
MouseMove para de ser chamado. Para corrigir isso, adicione uma chamada para
ellipse.CaptureMouse() dentro do manipulador MouseLeftButtonDown – isso faz com que a
elipse continue a ter eventos de mouse durante o tempo em que o mouse estiver dentro do
plug-in do Silverlight, não importa se já tiver passado a elipse. Adicione também uma chamada
para ellipse.ReleaseMouseCapture() no manipulador de eventos MouseLeftButtonUp.
33
Execute a aplicação. Você deve conseguir mover o mouse mais rápido agora sem problemas,
contanto que permaneça dentro da área ocupada pelo controle do Silverlight.
A seguir você vai adicionar manipulação de teclado. Adicione um manipulador para o evento
KeyDown do Page: use essa palavra-chave para se referir ao objeto atual, assim:
Adicione um código que altere o preenchimento da elipse com base na tecla pressionada:
case Key.G:
c = Colors.Green;
break;
case Key.B:
c = Colors.Blue;
break;
default:
return;
}
Execute a aplicação. Quando clicar em algum lugar dentro do controle, ela responderá às teclas
pressionadas.
Muitos eventos no Silverlight 2 “se propagam”, assim como fazem no Silverlight 1.0 e no WPF.
Isso permite anexar um único manipulador de eventos que recebe notificações de eventos de
múltiplos elementos. No Silverlight 1.0 isso era um pouco limitado, já que não havia uma forma
de descobrir de qual elemento um determinado evento tinha se propagado. O Silverlight 2 tem
suporte para a propriedade Source no objeto de argumento do evento, o que resolve esse
problema.
34
Vamos colocar tudo o que aprendemos até agora em prática para criar um mini-jogo divertido
chamado “PopTheBubble”. Nesse jogo, vamos desenhar novas “bolhas” (elipses) na tela a cada
½ segundo, e o jogador deve removê-las o mais rápido possível clicando nelas.
1. Crie um novo projeto do Silverlight no Visual Studio chamado PopTheBubble. Deixe que o
Visual Studio crie uma Web associada para hospedar o conteúdo do Silverlight.
Abra o arquivo code-behind Page.xaml.cs. Nós precisamos que um evento de marcação (tick)
dispare a cada ½ segundo. Podemos fazer isso usando um DispatcherTimer, que dispara um
evento no thread da interface de usuário a um intervalo específico. O DispatcherTimer reside no
namespace System.Windows.Threading, portanto vamos adicioná-lo à nossa classe colocando a
seguinte cláusula no topo do projeto:
using System.Windows.Threading;
Agora vamos adicionar dois campos à classe, imediatamente após a declaração da classe e antes
do construtor:
Vamos criar um manipulador de eventos para o evento Tick que o objeto temporizador vai
disparar. Faça com que o Visual Studio gere um método chamado timer_Tick que vai manipular
o evento.
35
No método Timer_Tick, vamos ter uma elipse criada de tamanho e cor aleatórios que será
adicionada ao canvas:
Por último, precisamos iniciar o temporizador. Adicione a seguinte linha como a última instrução
do método InitializeComponent():
timer.Start();
Vamos construir e executar a aplicação. Você deve ver algumas elipses dispersas
aleatoriamente, aparecendo a cada meio segundo. Se as elipses aparecerem no mesmo lugar,
verifique se você mudou o elemento Grid no XAML para um Canvas (passo 2).
Em seguida, você vai adicionar código para manipular os cliques do mouse em qualquer uma
dessas Ellipses. No construtor, anexe um manipulador ao evento de botão esquerdo do mouse
pressionado no controle, e crie um manipulador de eventos de stub, conforme descrevemos no
início desta seção.
36
Se você não estiver familiarizado com o código .NET, a primeira instrução converte e.Source
(que é do tipo object) para o tipo Ellipse. Se a fonte não for realmente uma elipse (por exemplo,
você clica no segundo plano da página), o target será definido como nulo. Isso é diferente na
escrita: Ellipse target = (Ellipse) e.Source; (outra forma de converter que usamos anteriormente
no laboratório), já que o método gera uma exceção se o objeto não corresponder ao tipo target
(alvo).
Dentro do bloco if, vamos adicionar uma única instrução para remover a elipse em que o usuário
clicou da coleção Canvas pai. Isso vai apagá-la da tela e liberar os recursos que ela estava
usando.
if (target != null)
{
LayoutRoot.Children.Remove(target);
}
(Opcional). Use essa aplicação para testar mais o Silverlight. Aqui estão algumas idéias:
f. Use o Expression Blend para projetar uma “bolha” mais bonita em vez da Ellipse de
cor sólida. Substitua a elipse pela nova bolha baseada em XAML.
g. Use as técnicas da próxima seção do laboratório para permitir que o jogo seja
jogado em modo de tela inteira.
37
Seção 5: Modo de Tela Inteira
Anteriormente você viu como fazer seu conteúdo do Silverlight preencher completamente a
janela do navegador. No entanto, às vezes é útil ir um passo além disso, e fazer seu conteúdo
preencher a tela inteira. Os passos a seguir mostram como usar o suporte do Silverlight para
operações de tela inteira.
1. Crie um novo projeto do Silverlight chamado FullScreen. Deixe que o Visual Studio crie uma
Web associada para hospedar o conteúdo do Silverlight.
Uma pequena peculiaridade: note que o designer não mostrará o conteúdo nesse ponto, porque
nenhum tamanho é especificado no retângulo e portanto o designer dimensiona a grade de
acordo com seu conteúdo, que é 0px de largura e 0px de altura. O retângulo será exibido no
tempo de execução porque o container HTML para o controle do Silverlight fará com que o
conteúdo seja dimensionado de modo a caber no container (isto é, a largura e a altura da tela).
System.Windows.Interop.Content contentObject =
Application.Current.Host.Content;
6. Para fazer o plug-in mudar de tela inteira para o modo normal quando esse elemento for
clicado, adicione o seguinte código no manipulador:
contentObject.IsFullScreen = !contentObject.IsFullScreen;
7. Execute a aplicação. Quando você clicar no retângulo azul, a aplicação deve mudar para o
modo de tela inteira. Quando você clicar novamente ela voltará par o modo normal.
8. Note que quando for para a tela inteira, aparecerá uma mensagem indicando que o usuário
pode reverter para o modo normal pressionando Esc. (Essa mensagem é fornecida
automaticamente pelo Silverlight. Você não pode desativá-la – ela faz parte do design, para
impedir que um código mal-intencionado crie uma imagem falsa de estação de trabalho,
38
com aparência plausível, para enganar o usuário e fazê-lo digitar uma senha). Isso significa
que a aplicação pode sair do modo de tela inteira sem que seu código seja envolvido. Para
essa aplicação em particular, isso não é problema – a única coisa interessante que acontece
quando vamos para a tela inteira é que o retângulo se redimensiona, e isso acontece
automaticamente graças ao elemento Grid raiz. Entretanto, uma aplicação mais útil pode
ter que fazer algo quando transitar entre o modo de tela inteira e o modo normal. Para lidar
com isso, adicione código ao construtor para anexar um manipulador ao evento
FullScreenChanged do objeto de conteúdo:
Application.Current.Host.Content.FullScreenChanged +=
new EventHandler(Content_FullScreenChanged);
9. No manipulador desse evento, escreva o seguinte código para mudar a cor do retângulo a
fim de indicar o modo:
10. Execute a aplicação. Note que o retângulo será vermelho quando for tela inteira e azul
quando for modo normal. A volta para a cor azul acontece mesmo que o modo normal entre
pela tecla Escape.
39
B- Animação no Silverlight
Primeiros Passos na criação e no uso de animações
Neste laboratório, você terá uma visão geral da API de Animação no Silverlight, vai se familiarizar com
as ferramentas de design visual para animação disponíveis no Blend e executar uma aplicação bastante
simples que usa código de procedimento para gerar e reutilizar Storyboards. E no final aprenderá a usar
um DispatcherTimer.
40
Seção 1: Uma olhada na API de
Animação
Animação no contexto do Silverlight pode ser resumida em uma linha – mudar o valor de uma
propriedade de um objeto com o tempo (variando de instantâneo a infinito). Criar animações é na
verdade algo bastante simples de aprender. Basicamente, você cria um Storyboard que executa uma ou
mais Animações quando o Storyboard é começado. A parte difícil das animações é saber quando e onde
usá-las e o que animar.
Após este Laboratório, você terá uma boa idéia de como animar propriedades. Com relação a quando e
onde usá-las, pode não ser tão difícil quanto mencionamos acima. Há milhões de exemplos (bons e
maus (e péssimos)) de animações em sites, interfaces de usuário de aplicações, e ocultos naqueles GIFs
animados que você adiciona à sua assinatura de e-mail e encaminha a todos os seus amigos.
Agora vamos nos divertir um pouco e ver como os Storyboards e as Animações funcionam, depois
vamos levá-los para um teste no Expression Blend.
Storyboards
A classe Storyboard é o container e a interface de suas Animações. Storyboards contêm uma ou mais
Animações e as controlam com base em métodos simples de transporte como Begin, Pause, Stop,
Resume, Seek e SkipToFill. Os quatro primeiros são auto-explicativos (Começar, Pausar, Parar e
Continuar), mas Seek significa mover para um ponto específico na linha do tempo e SkipToFill move a
linha do tempo dos Storyboards para o final de seu período ativo.
Os storyboards também têm propriedades que podem modificar radicalmente seu comportamento.
AutoReverse determina se um Storyboard deve ser reproduzido inversamente após concluir a
iteração de avanço.
BeginTime pode ser usado para atrasar a reprodução.
Duration define a duração total do Storyboard.
FillBehavior determina se o novo valor deve ser mantido quando o storyboard for concluído.
RepeatBehavior determina quanto tempo ou quantas vezes o Storyboard deve ser repetido.
Os storyboards têm um único evento chamado Completed que dispara quando todas as iterações de
avanço, inversas e repetições do Storyboard tiverem sido executadas até o final. A manipulação desse
evento permite decidir qual código executar, se houver algum, após a animação, o que poderia iniciar
outro Storyboard. Ou você pode modificar o Storyboard e as Animações e executá-lo novamente.
41
Animações
Todas as Animações e Storyboards herdam da classe Timeline que fornece a funcionalidade baseada em
tempo mencionada acima. Quando um Storyboard ou uma Animação iteram, quanto tempo, quantas
vezes, etc. O que torna cada classe de Animação única é o tipo de propriedade animada e a
interpolação entre os valores atuais e de destino.
Primeiro vamos ver Animações simples que têm propriedades From, To e By.
From é opcional e define quando a animação começa o que o valor de partida é. Se a From não
for definida o valor de partida será o valor atual da propriedade.
To define o valor final da propriedade.
By aumenta o valor da propriedade animada com seu valor. Por exemplo, se você tem um
Rectangle com um Canvas.Left definido em 0 e o anima com By=50 e RepeatBehavior definido
em 2x no final da Animação o Canvas.Left do Rectangle seria igual a 100.
Em uma animação simples, a interpolação entre os valores durante a transição é linear- uma mudança
tranqüila e constante. Os três tipos de Animações simples incluem:
ColorAnimation
Usando um exemplo de animação da cor de um Traço (Stroke)
de Retângulo, você pode ver que a cor mudou de azul escuro
para vermelho.
DoubleAnimation
Neste exemplo o deslocamento do Gradiente Stop de azul
mais escuro foi animado para dar uma sensação de
sobreposição do Retângulo.
PointAnimation
Aqui o StartPoint e o EndPoint do LinearGradientBrush foram
animados para dar um Preenchimento radicalmente
diferente para o Retângulo.
As animações de quadro chave permitem definir múltiplos valores e controlar a interpolação entre
valores iniciais e finais. Os KeyFrames (quadros chave) são adicionados à Animação e cada um define
um Valor e um KeyTime usados durante a animação. A interpolação é controlada definindo a
propriedade KeySpline que só está disponível no tipo SplineKeyFrame. Animações de Quadro Chave
possibilitam animações muito mais orgânicas, envolvendo aceleração e desaceleração.
42
Cada tipo de animação simples tem um tipo de animação KeyFrame correspondente, incluindo
ColorAnimationUsingKeyFrames, DoubleAnimationUsingKeyFrames, PointAnimationUsingKeyFrames e
ObjectAnimationUsingKeyFrames.
Em animações simples nós explicamos que a interpolação Linear é tranqüila e constante do valor inicial
ao valor final. Quando você começa a usar AnimationUsingKeyFrames, pode tirar proveito da
interpolação baseada em Spline.
Aqui estão alguns exemplos para ilustrar o conceito de KeyFrames e KeySplines. Sinta-se à vontade para
seguir estes exemplos no Blend ou no Visual Studio para ver as Animações se moverem em tempo real.
A seguinte animação simples da propriedade Canvas.Left de nosso objeto OrangeShip mudará o valor de
0 para 500 em um segundo:
<Storyboard x:Name="SplineTest">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="OrangeShip"
Storyboard.TargetProperty="(Canvas.Left)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:01" Value="500"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Note que o KeySpline à direita (representado pela ferramenta visual do Blend) está definido com o valor
padrão, que é equivalente à interpolação Linear. A linha verde abaixo representa a taxa de mudança
conforme a nave desliza pela tela. Ela vai de forma suave e estável.
<Storyboard x:Name="SplineTest">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="OrangeShip"
Storyboard.TargetProperty="(Canvas.Left)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:01" Value="500">
<SplineDoubleKeyFrame.KeySpline>
<KeySpline ControlPoint1="1,0" ControlPoint2="1,1"/>
</SplineDoubleKeyFrame.KeySpline>
</SplineDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
43
Com o KeySpline definido assim, a nave cobre pouco espaço no início mas acelera bastante até o final.
<Storyboard x:Name="SplineTest">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="OrangeShip"
Storyboard.TargetProperty="(Canvas.Left)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:01" Value="200">
<SplineDoubleKeyFrame.KeySpline>
<KeySpline ControlPoint1="0,1" ControlPoint2="1,1"/>
</SplineDoubleKeyFrame.KeySpline>
</SplineDoubleKeyFrame>
<SplineDoubleKeyFrame KeyTime="00:00:03" Value="500" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
A nave agora acelera até 200 e depois vai deslizando daí para 500. Embora seja um pouco mais
complexa de ver em XAML, Animações baseadas em Quadro Chave podem ser muito potentes e
bastante simples de criar no Blend.
Animações de Objeto
Mencionadas rapidamente acima, as Animações de Objeto são novas no Silverlight 2 beta 2 e permitem
definir valores de Objetos que não são Doubles, Colors ou Points. As Animações de Objeto só podem ser
usadas com KeyFrames e com a Interpolação Discrete. Discrete significa completamente alterada no
final da duração. Olhando o exemplo abaixo você pode entender o porquê. Seria muito difícil
(impossível) interpolar entre dois valores Enumeration (Enumeração).
44
Animar a propriedade Visibility é um caso de uso comum, especialmente quando você considera que ia
usar Opacity em vez de Visibility, mesmo com uma opacidade 0 os eventos de mouse ainda são
capturados.
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="OrangeShip"
Storyboard.TargetProperty="(FrameworkElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:01">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
45
Seção 2: Usando o Blend para Projetar
Animações
O Blend é a ferramenta visual para layout interatividade e criação de gráficos básicos para aplicações do
WPF e do Silverlight. As tecnologias WPF trazem novos paradigmas de programação para
desenvolvedores, mas também trazem inovações para os designers. No contexto da Animação, o Blend
fornece um conjunto bastante robusto de ferramentas. Abaixo está um passo a passo sobre como usar
cada uma das Ferramentas de Animação e como elas se relacionam ao conceito de API acima.
Agora você tem um objeto interessante para manipular com um segundo plano bastante contrastante.
Note que o Storyboard é exibido agora por nome na área superior do painel de Objetos.
A Linha do Tempo é mostrada à direita da árvore de Objetos.
Finalmente a superfície de design tem um contorno vermelho, notificando que você está em
modo de gravação. Edições no objeto serão agora acompanhadas no Storyboard.
Você pode ligar e desligar a gravação clicando no círculo vermelho, que vai alternar para cinza quando
estiver desligado.
O padrão do Expression Blend é usar KeyFrames, já que visualmente esse é o modo mais fácil de
projetar animações complexas. Olhando a Linha do Tempo você pode ver o playhead, que é a linha
vertical amarela com a seta no topo.
46
Acima do marcador de 0 segundos você verá o botão Record KeyFrame , com o OrangeShip
selecionado, clique nesse botão e grave um KeyFrame no marcador de 0 segundos.
Arraste o playhead para o marcador de 1 segundo.
Arraste o OrangeShip de onde está para um novo local.
Clique no botão Record KeyFrame novamente.
Acima da linha do tempo você encontrará controles de transporte que permitem pré-visualizar
sua animação. Clique no botão Play.
Bela animação! Muito suave e linear.
Você pode inspecionar quais propriedades está animando visualmente expandindo os objetos no Painel
de Objetos que têm o ícone vermelho selecionado. É claro que também pode mudar para a exibição
XAML ou abrir o arquivo no Visual Studio para ver as propriedades alvo.
Editando o storyboard
Se seu Storyboard não estiver mais aberto ou você quiser selecionar um diferente, clique no botão
que vai mostrar a lista dos Storyboards existentes. Com um Storyboard selecionado, você vai ver as
propriedades do Storyboard no Painel de Propriedades. Aqui você pode editar o AutoReverse e o
RepeatBehavior.
Editando KeySplines
Com um Storyboard aberto, selecione um KeyFrame na área da Linha do Tempo. Note que agora o
painel de Propriedades mudou para trazer acima o editor do KeySpline, bem como uma forma de inserir
um Valor para um KeyFrame. Desse modo, se você não puder arrastar algo para o ponto exato que
deseja, pode apenas digitar o valor exato.
Resumo
Em alto nível, a criação de Storyboards pode ser realizada simplesmente movendo o playhead para
tempos diferentes e modificando qualquer propriedade de seu objeto. Lembre-se que um Storyboard
pode conter mais que uma animação e pode ser reutilizado com alguma ajuda do code-behind.
47
Seção 3: Reutilizando Storyboards
A habilidade de criar e projetar storyboards visualmente dentro do Blend é muito potente, mas em
algum ponto você pode precisar entrar em seu código para manipular ou reutilizar o storyboard com
base em dados dinâmicos ou entrada do usuário. Vamos usar a Animação Simples para ver um exemplo
básico de como fazer isso.
Aqui estamos usando código de procedimento para instanciar um novo Storyboard. Depois
instanciamos uma DoubleAnimation para animar a propriedade Canvas.Left do objeto OrangeShip para
350 pixels em 800 milissegundos.
Usando o código acima como um modelo, tente adicionar outra DoubleAnimation ao mesmo
Storyboard que anima a propriedade Canvas.Top do OrangeShip.
Agora faça a chamada para Begin BasicAnimation.
Execute a aplicação para ver o OrangeShip voar pela tela.
Agora vamos modificar e executar novamente o Storyboard com base na entrada do usuário.
da = BasicAnimation.Children[0] as DoubleAnimation;
da.To = e.GetPosition(LayoutRoot).X - OrangeShip.Width;
da = BasicAnimation.Children[1] as DoubleAnimation;
da.To = e.GetPosition(LayoutRoot).Y - OrangeShip.Height / 2;
BasicAnimation.Begin();
48
Como o Storyboard foi armazenado em uma variável de nível de classe, nós podemos manipulá-lo. Esse
código passa pela árvore de Filhos do Storyboard e redefine as propriedades To com base na posição do
mouse e no tamanho da nave.
Esse tipo de acesso a Storyboards possibilita uma maior flexibilidade, como a habilidade de modificar os
Storyboards existentes projetados dentro do Blend no tempo de execução para corresponder à sua
interação ou seus dados de tempo de execução.
49
Seção 4: Usando o DispatchTimer para
Animação de Procedimento
A construção do Storyboard é uma forma muito útil de animar sua interface de usuário, mas há alguns
casos em que você pode querer um evento de marcação de jogo para atualizar manualmente os objetos
usando seu próprio código. Abaixo você usará a classe DispatcherTimer para criar um efeito de chama
bastante simples para sua nave conduzida pela entrada do mouse.
Essa é uma instanciação simples da classe DispatcherTimer. Uma vez que o método Start é chamado, o
evento Tick começa a disparar com base no Intervalo definido.
Agora o objeto Tail vai se reposicionar para ficar um pouco mais próximo à nave a cada Tick. Ao
executar a aplicação, você verá algo como a imagem abaixo. Note a saída da cauda azul atrás do motor.
50
C- Integração de Navegador
do Silverlight
Tornando o Silverlight um cidadão de navegador de primeira classe
Introdução
O Silverlight 2 fornece uma funcionalidade que lhe permite ser um cidadão de primeira classe em uma
página HTML dentro do navegador. Ele possibilita uma série de recursos, incluindo (mas não limitado a):
Funções de código .NET podem ser expostas ao navegador e chamadas a partir do JavaScript
A árvore de renderização XAML pode ser exposta ao navegador e manipulada a partir de
JavaScript
O código JavaScript dentro do HTML pode ser chamado de dentro do code-behind do .NET
Neste Laboratório você vai explorar cada um desses recursos, e as classes dentro do namespace
System.Windows.Browser que habilita essa funcionalidade. Você vai trabalhar com os conceitos por
trás de cada um deles, usando o Microsoft Virtual Earth como base, antes de explorar como eles são
usados dentro da aplicação de exemplo, a Margie’s Travel.
As aplicações de exemplo são chamadas de Sample 1, Sample 2 e Sample 3. Elas têm cópias com os
sufixos ‘Start’ e ‘Completed’. Você deve começar com as versões ‘Start’ e adicionar código a elas
conforme as instruções. Se tiver problemas, as versões de trabalho concluídas são fornecidas.
51
Seção 1 – Expondo Funções .NET ao
Navegador.
Dentro do diretório dos Laboratórios você encontrará um projeto chamado Sample 1. Abra a versão do
diretório Sample 1 – Completed e execute-a. Você verá uma tela como a da Figura 1. O objeto bege no
topo à esquerda é um objeto do Silverlight, abaixo dele estão três controles <Input> HTML e à direita
está um mapa do Virtual Earth. Se pressionar os botões, o conteúdo do Silverlight será atualizado com
as cidades do país selecionado.
Nós vamos construir a partir desse exemplo conforme avançarmos, então feche esse projeto e abra o do
diretório Sample 1 – Start.
O conteúdo do Silverlight na Figura 1 usa XAML que contém um ItemsControl que contém um TextBlock,
que está ligado ao nome de uma cidade (‘CityName’).
52
<ItemsControl x:Name="_cities">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="14" Height="30" Text="{Binding CityName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
O Code-Behind contém uma Classe usada para representar Cidades, e contém um elemento membro
chamado CityName.
switch (strCountry)
{
case "uk":
{
ret.Add(new CityData("London", 51.5, 0));
ret.Add(new CityData("Stratford-Upon-Avon", 52.3, -1.71));
ret.Add(new CityData("Edinburgh", 55.95, -3.16));
break;
}
…
Para ligar esses resultados ao ItemsControl, basta construir o List<CityData> e defini-lo de acordo
com a propriedade ItemsSource do ItemsControl. (‘_cities’ é o nome do ItemsControl)
Aqui está uma função que consegue isso. Adicione-a à página de code-behind do Page.xaml.cs:
53
_cities.ItemsSource = myCities;
}
Essa função está disponível para o código .NET, mas como podemos expor ao navegador? Você verá
isso na próxima seção.
Para expor seu código .NET ao navegador, você primeiro terá que fazer referência ao
System.Windows.Browser dentro de seu código no topo de seu code behind.
using System.Windows.Browser;
Em seguida você terá que adicionar um evento Loaded e um manipulador de eventos à sua página. Você
pode fazer isso dentro do construtor Page(), portanto adicione esta linha ao construtor Page():
Agora você vai implementar o manipulador de eventos Page_Loaded e usá-lo para registrar seu controle
do Silverlight como um objeto “scriptável”. Nesse caso você vai registrar o objeto scriptable (não o
confunda com o objeto do Silverlight propriamente dito) como MySilverlightObject
Talvez você tenha notado, enquanto estava digitando a linha anterior, que o Visual Studio podia gerar
automaticamente um manipulador de eventos Page_Loaded para você. Se ele o fez, edite-o para ficar
como o código abaixo, caso contrário apenas adicione este código ao code-behind de seu Page.xaml.cs.
Quando tiver feito isso, você poderá registrar seus métodos Public para serem “scriptáveis”, usando o
atributo [ScriptableMember]. Veja como expor o método upDateCities que vimos anteriormente
para que ele possa ser chamado do navegador, então lembre-se de adicionar o atributo, assim:
[ScriptableMember]
public void upDateCities(string strCountry)
{
myCities = getCities(strCountry);
_cities.ItemsSource = myCities;
}
54
Na próxima seção você verá como chamar isso a partir do JavaScript.
A primeira coisa da qual deve se certificar é se o objeto do Silverlight tem um ID. Isso é necessário para
que o JavaScript possa ter uma referência a ele.
<object data="data:application/x-silverlight,"
type="application/x-silverlight-2-b2"
width="300" height="400" id="slControl">
...
</object>
Agora o JavaScript pode ter uma referência ao seu controle do Silverlight com base neste ID:
<PluginID>.content.<ScriptableObjectName>.method(parameters)
slPlugin.content.MySilverlightObject.upDateCities("uk");
No Projeto Sample 1 você precisará de uma função do JavaScript chamada doCities que pega um
parâmetro e o usa para chamar o código .NET. Aqui está a função - adicione-a a um bloco do script em
Sample1TestPage.html dentro do projeto Sample1Web:
function doCities(country)
{
var slPlugin = document.getElementById("slControl");
slPlugin.content.MySilverlightObject.upDateCities(country);
}
Os botões de Entrada de HTML chamam isso e passam o devido país. Aqui está sua declaração, você
pode vê-la no final do Sample1TestPage.html:
55
<input id="bFrance" type="button" value="france" onclick="doCities('france');"
/>
O resultado final é que quando o usuário pressiona um botão de HTML, a função doCities do JavaScript é
executada. Isso chama o objeto scriptável do Silverlight passando a ele o parâmetro que recebe. Agora o
código .NET assume e usa esse parâmetro para criar uma List<CityData> de cidades para o país
selecionado, que será então ligada ao Items Presenter.
56
Seção 2 – Manipulando a Árvore de
Renderização XAML a partir do
Navegador
No exemplo anterior você viu como pode acessar o código .NET dentro do JavaScript, mas além disso
você também pode manipular o XAML que o Silverlight renderiza usando o JavaScript no navegador.
Você tem várias opções para fazer isso.
Primeiro, se você tem um elemento XAMl existente, pode encontrá-lo usando o método findName do
controle do Silverlight, e definir seus conteúdos.
Abra o projeto Sample2 do diretório Sample2 – Completed e execute-o. Você pode ver isso na Figura 2.
57
Você pode ver que isso atualiza o Sample 1 adicionando o nome do país ao topo do conteúdo do
Silverlight. Feche isso e abra o projeto Sample2 – Start, que você usará para trabalhar.
O XAML precisa ser atualizado com um novo TextBlock, então adicione o XAML destacado ao Page.xaml
no lugar correto.
<UserControl x:Class="Sample1.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FontFamily="Trebuchet MS" FontSize="11"
Width="300" Height="400">
<Grid x:Name="LayoutRoot" Background="Beige">
<StackPanel x:Name="stk">
<TextBlock FontSize="40" Foreground="Red"
x:Name="txtCountry">Country</TextBlock>
<ItemsControl x:Name="_cities">
…
</ItemsControl>
</StackPanel>
</Grid>
</UserControl>
No JavaScript, se você tiver uma referência ao objeto do Silverlight chamado slControl, pode corrigir os
conteúdos do TextBlock usando o seguinte JavaScript:
slPlugin.content.findName("txtCountry").text = "germany";
function doCities(country)
{
var slPlugin = document.getElementById("slControl");
slPlugin.content.MySilverlightObject.upDateCities(country);
slPlugin.content.findName("txtCountry").text = country;
}
Agora o efeito é que quando você pressiona os botões de HTML, a lista de cidades do Silverlight se
atualiza com as cidades desse país, e o título do país é definido de acordo.
O Silverlight não se restringe ao XAML que é definido como parte do projeto Visual Studio / Blend. Ele
pode ser adicionado dinamicamente no tempo de execução dentro da ferramenta do JavaScript. Neste
exemplo simples você verá como fazer isso.
58
Se você consultar a listagem do XAML anterior, verá que o StackPanel que contém a lista de cidades é
chamada de ‘stk’. Você vai adicionar o novo XAML a esse elemento como filhos desse elemento.
Veja um exemplo:
var xamlFragment =
'<TextBlock FontSize="20" Foreground="Blue">' + Date() + '</TextBlock>';
tb = slPlugin.content.createFromXaml(xamlFragment,false);
slPlugin.content.findName("stk").children.add(tb);
Você pode adicionar esse código à função doCities do outro exemplo, e sempre que o usuário clicar no
botão um novo TextBlock do XAML será adicionado ao StackPanel, e esse TextBlock vai conter a Data e o
Horário atuais. Aqui está o código que faz isso:
function doCities(country)
{
var slPlugin = document.getElementById("slControl");
slPlugin.content.MySilverlightObject.upDateCities(country);
slPlugin.content.findName("txtCountry").text = country;
var xamlFragment =
'<TextBlock FontSize="20" Foreground="Blue">' + Date() + '</TextBlock>';
tb = slPlugin.content.createFromXaml(xamlFragment,false);
slPlugin.content.findName("stk").children.add(tb);
}
59
Lembre-se de que não é um XAML existente que você está manipulando. Você está adicionando um
novo XAML à árvore de renderização no tempo de execução. Isso torna o Silverlight bastante flexível
para atender as necessidades de suas aplicações conectadas.
Mais Estudo
Além de manipular XAML existente e adicionar novo XAML, você também pode remover o XAML.
Quando tiver uma referência a um elemento de container (como ‘stk’), você pode usar Remove ou
RemoveAt para remover elementos. Além disso, pode fazer referência a itens nos filhos de um container
usando getItem(index). Aqui há um bom material: http://msdn.microsoft.com/en-
us/library/bb980118(VS.95).aspx
60
Seção 3 – Chamando o Script do
Navegador a partir de .NET
Agora nós vimos como você pode chamar o código .NET a partir do JavaScript dentro do navegador –
mas e a outra maneira? Nesta seção você verá como fazer exatamente isso. Como exemplo, o SDK do
Virtual Earth é baseado em JavaScript, então, em vez de construir seu próprio host do Silverlight para o
Virtual Earth, é muito mais fácil fazer o Silverlight chamar o navegador e o JavaScript chamar os serviços
do Virtual Earth em seu nome.
Carregue o projeto ‘Sample3’ do diretório Sample3 – Completed e execute-o. Anteriormente você viu
que pressionar os botões de HTML que representam os diferentes países fará com que as cidades desses
países sejam carregadas para o conteúdo do Silverlight. O projeto Sample3 contribui para isso – quando
você seleciona o nome de uma cidade (lembre-se disso na área do Silverlight), será feita uma chamada
para o navegador, para uma função do JavaScript que localiza a cidade selecionada no mapa com base
em sua latitude e longitude.
61
Figura 4. Chamando o navegador a partir do Silverlight para usar o SDK do Virtual Earth
Feche esse projeto e abra o projeto Sample3 – Start, que você usará para construir a funcionalidade
completa.
Primeiro, note que o XAML precisa ser atualizado para que o ItemsControl se ligue a CityName,
Longitude e Latitude. Os últimos elementos ficam ‘ocultos’ se você definir sua altura em ‘0’. Você terá
que atualizar o XAML para adicionar o seguindo código ao DataTemplate.
<ItemsControl x:Name="_cities">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
MouseLeftButtonUp="StackPanel_MouseLeftButtonUp">
<TextBlock FontSize="14" Height="30" Text="{Binding CityName}" />
<TextBlock Height="0" Text="{Binding Latitude}" />
<TextBlock Height="0" Text="{Binding Longitude}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note também que o manipulador de eventos de Mouse é conectado ao StackPanel que contém os
elementos TextBlock. Isso significa que o evento será capturado pelo container, e os valores de cada um
de seus filhos podem ser derivados, permitindo receber o Name, a Latitude e a Longitude da cidade
atual.
Vamos dar uma olhada nesse manipulador de eventos. Adicione este código ao Page.xaml.cs quando
estiver trabalhando.
Agora podemos receber o nome da cidade, sua latitude e longitude a partir destes objetos:
strCurrentCity = t0.Text;
nCurrentLatitude = Convert.ToDouble(t1.Text);
nCurrentLongitude = Convert.ToDouble(t2.Text);
62
que precisaremos: A classe HtmlPage nos permite ter uma referência a uma função do JavaScript
invocando seu método Window.GetProperty e passando a ele o nome da função. Isso tem que ser
convertido como um ScriptObject para poder ser chamado:
ScriptObject myScriptMethod =
(ScriptObject) HtmlPage.Window.GetProperty("plotCity");
myScriptMethod.InvokeSelf(nCurrentLatitude, nCurrentLongitude);
É claro que a função plotCity tem que existir na página, e tem que corresponder à assinatura que está
sendo usada para chamá-la.
Aqui está a função do JavaScript que pega a latitude e a longitude e centraliza o mapa do Virtual Earth
conforme essas coordenadas. Adicione isso ao Sample3TestPage.html:
*Note que ‘8’ é o nível de zoom. Veja o SDK do Virtual Earth para mais detalhes:
http://dev.live.com/virtualearth/sdk/]
Mais Estudo
Além de chamar Funções do JavaScript, você também pode manipular elementos HTML.
Você faz isso atribuindo um HtmlElement aos resultados de uma chamada de função
HtmlPage.Document.GetElementByID(‘elementName’).
Depois você pode manipular isso chamando o método ‘setAttibute’ da instância de HtmlElement
passando a ele um nome e um valor de atributo como esse element.setAttribute(“attributeName”,
value).
63
D- Personalizando a Aparência
Modelagem de Controle, Styling (Estilo), Visual State Manager, controles de
Subclasse.
Introdução
O Silverlight oferece muitas opções diferentes para personalizar sua interface de usuário e torná-la
atraente:
Você pode simplesmente definir propriedades em cada controle (usando código ou atributos
XAML) e ter um nível básico de personalização.
Você também pode usar o Styling, que oferece o mesmo nível de personalização (definição de
valores em propriedades existentes) de modo mais reutilizável e amigável para o designer.
Finalmente, a modelagem de controle o libera para redefinir a aparência de um controle
substituindo suas partes.
Todos esses recursos podem ser combinados e correspondidos para ter a maior flexibilidade e
maximizar a reutilização de seus ativos.
Objetivos do Laboratório:
Neste laboratório você vai aprender sobre recursos, estilo e modelagem de controle. Vamos criar um
controle deslizante personalizado para a aplicação Voyager.
64
Exercício 1: Criando o controle deslizante do Voyager
Neste exercício você vai usar o Expression Blend para criar um controle deslizante com certa
personalização para ser usado no Voyager.
No Exercício 1, você vai usar o Expression Blend para desativar os RepeatButtons e criar a aparência
personalizada para o elevador. Você não vai escrever nenhum código neste exercício.
65
Tarefa 1: Montando seu controle deslizante
1. Inicie o Expression Blend e crie uma nova Aplicação do Silverlight 2. O nome do projeto não
importa, já que você vai criar XAML e pode então recortar e colar na aplicação do Voyager.
3. Clique com o botão direito em seu controle deslizante e selecione ‘Edit a Copy’ para Editar o
Modelo.
66
Editar o Modelo dessa forma nos permitirá personalizar o Modelo de Controle padrão para
controle deslizante (podemos adicionar/remover partes, mudar as transições de estado, etc.).
A caixa de diálogo Edit Template vai pedir o nome e um escopo para nosso modelo.
67
6. Clique na exibição SplitView ou XAML para analisar o que o Blend acabou de fazer por você:
O Blend extraiu o Estilo padrão (e o Modelo de Controle para o Controle Deslizante) e o colocou na
coleção UserControl.Resources para que você possa reutilizá-lo dentro da página.
68
Tarefa 2: Personalizando o controle deslizante
Se você olhar o ControlTemplate para controle deslizante, verá que há dois Grids principais dentro do
modelo: “HorizontalTemplate” e “VerticalTemplate”. Essas grades encapsulam a aparência padrão do
controle deslizante quando ele está na respectiva Orientação. Este exercício vai focar apenas na
personalização do Modelo Horizontal (Horizontal Template).
O HorizontalTemplate tem:
Se você estiver na exibição de Design, pode vê-los na exibição de Objetos e Linha do Tempo – assim:
No controle deslizante do Voyager, não há nenhuma faixa visível, então comece tornando a “Track”
(Faixa) transparente.
Agora, desative os RepeatButtons para que eles não interfiram em nossos controles deslizantes
sobrepostos.
69
3. Mude a propriedade IsHitTestVisible para “False” (ou Unchecked).
[Dica: você pode usar a Janela de Pesquisa na Guia de propriedades; digite “IsH” (menos as
aspas) e o Filtro vai trazer IsHitTestVisible].
Você está mudando IsHitTestVisible para falso em oposição a configurar a Visibilidade como
recolhida porque a Visibilidade afeta o layout e o Controle Deslizante está alongando/reduzindo
o botão para alterar a posição do Elevador.
Você não mudou “IsEnabled” para falso apenas por causa de um problema conhecido na beta2.
Para o RTM, IsEnabled deve resolver o problema.
Ótimo! Agora nosso trabalho no controle deslizante está pronto, mas precisamos modificar o
modelo do Elevador dentro do controle deslizante.
70
Tarefa 3: Personalizando o Elevador
6. Quando nome e local forem solicitados, insira “SliderThumbStyle” no nome e o escopo para
definição está dentro de This document.
71
Note como o Modelo do elevador tem muitos elementos: ThumbOurterBorderFill,
ThumbOuterRoundBorder, etc. Em nosso caso, queremos uma aparência completamente
diferente/nova, então podemos excluir todos eles.
7. Selecione todos os elementos em VoyagerThumbStyle e exclua todos eles, exceto o Grid na Raiz.
72
OBSERVAÇÃO: Para tornar meu desenho mais fácil, usei o zoom de 800%, tinha Snaplines sendo
exibidos e “Snap to grid” estava ativo também.
73
Tarefa 4: Testando nosso controle deslizante.
Essas são todas as alterações necessárias para personalizar o Controle Deslizante e o Elevador no
Voyager. Agora vamos ver se funciona.
9. Dentro do Blend, clique em Test Solution (no Menu Project) para ver como é seu controle
deslizante. Não se preocupe se não for muita coisa, ele vai se integrar bem ao controle de linha
do tempo de seu Voyager.
74
Apêndices
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup
x:Name="CommonStates">
<vsm:VisualStateGroup.Transitions>
<vsm:VisualTransition Duration="0"/>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState
x:Name="Normal"/>
<vsm:VisualState
x:Name="MouseOver"/>
<vsm:VisualState
x:Name="Disabled">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Root"
Storyboard.TargetProperty="(UIElement.Opacity)">
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
<vsm:VisualStateGroup
x:Name="FocusStates">
75
<vsm:VisualStateGroup.Transitions>
<vsm:VisualTransition Duration="0"/>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState
x:Name="Unfocused"/>
<vsm:VisualState
x:Name="Focused">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual"
Storyboard.TargetProperty="(UIElement.Opacity)">
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Grid
x:Name="HorizontalTemplate">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="Auto"/>
<ColumnDefinition
Width="Auto"/>
<ColumnDefinition
Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle Height="3"
Margin="5,0,5,0" Grid.Column="0" Grid.ColumnSpan="3" StrokeThickness="0.5"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="HorizontalTrackLargeChangeDecreaseRepeatButton" Grid.Column="0"
IsHitTestVisible="False"/>
<Thumb Height="18"
x:Name="HorizontalThumb" Width="11" Grid.Column="1"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="HorizontalTrackLargeChangeIncreaseRepeatButton" Grid.Column="2"
IsHitTestVisible="False"/>
</Grid>
<Grid x:Name="VerticalTemplate"
Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition
Height="*"/>
<RowDefinition
Height="Auto"/>
<RowDefinition
Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle
Margin="0,5,0,5" Width="3" Grid.Row="0" Grid.RowSpan="3" Fill="#FFE6EFF7"
Stroke="Black" StrokeThickness="0.5"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="VerticalTrackLargeChangeDecreaseRepeatButton" Grid.Row="2"/>
76
<Thumb Height="11"
x:Name="VerticalThumb" Width="18" Grid.Row="1"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="VerticalTrackLargeChangeIncreaseRepeatButton" Grid.Row="0"/>
</Grid>
<Rectangle x:Name="FocusVisual"
Stroke="#666666" StrokeDashArray=".2 5" StrokeDashCap="Round"
IsHitTestVisible="false" Opacity="0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<UserControl.Resources>
<Style x:Key="VoyagetThumbStyle" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Grid>
<Grid.Resources>
<SolidColorBrush
x:Key="Background" Color="#FF003255"/>
<Color
x:Key="ThumbOuterBorderFillColor1">#FFF9FAFA</Color>
<Color
x:Key="ThumbOuterBorderFillColor2">#FFEDF1F4</Color>
<Color
x:Key="ThumbOuterBorderFillColor3">#FFE2E8EF</Color>
<Color
x:Key="ThumbOuterBorderFillColor4">#FFAFB9C1</Color>
<SolidColorBrush
x:Key="ThumbInnerRoundBorderBrush" Color="#FFFFFFFF"/>
<SolidColorBrush
x:Key="ThumbOuterRoundBorderBrush" Color="#FF000000"/>
<Color
x:Key="ThumbInnerBorderFillColor1">#CDFFFFFF</Color>
<Color
x:Key="ThumbInnerBorderFillColor2">#45FFFFFF</Color>
<Color
x:Key="MouseOverThumbOuterBorderFillColor1">#FFEAF0F0</Color>
<Color
x:Key="MouseOverThumbOuterBorderFillColor2">#FFDCE5EC</Color>
<Color
x:Key="MouseOverThumbOuterBorderFillColor3">#FFD5DDE6</Color>
<Color
x:Key="MouseOverThumbOuterBorderFillColor4">#FF798893</Color>
<Color
x:Key="MouseOverThumbInnerBorderFillColor1">#CDFFFFFF</Color>
<Color
x:Key="MouseOverThumbInnerBorderFillColor2">#45FFFFFF</Color>
<Color
x:Key="PressedThumbOuterBorderFillColor1">#FFEAF0F0</Color>
<Color
x:Key="PressedThumbOuterBorderFillColor2">#FFDCE5EC</Color>
77
<Color
x:Key="PressedThumbOuterBorderFillColor3">#FFD5DDE6</Color>
<Color
x:Key="PressedThumbOuterBorderFillColor4">#FF798893</Color>
<Color
x:Key="PressedThumbInnerBorderFillColor1">#CDFFFFFF</Color>
<Color
x:Key="PressedThumbInnerBorderFillColor2">#45FFFFFF</Color>
<Color
x:Key="DisabledThumbOuterBorderFillColor1">#FFF9FAFA</Color>
<Color
x:Key="DisabledThumbOuterBorderFillColor2">#FFEDF1F4</Color>
<Color
x:Key="DisabledThumbOuterBorderFillColor3">#FFE2E8EF</Color>
<Color
x:Key="DisabledThumbOuterBorderFillColor4">#FFC3C9CD</Color>
<Color
x:Key="DisabledThumbInnerBorderFillColor1">#CDFFFFFF</Color>
<Color
x:Key="DisabledThumbInnerBorderFillColor2">#45FFFFFF</Color>
</Grid.Resources>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup
x:Name="CommonStates">
<vsm:VisualStateGroup.Transitions>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState
x:Name="Normal"/>
<vsm:VisualState
x:Name="MouseOver">
<Storyboard/>
</vsm:VisualState>
<vsm:VisualState
x:Name="Pressed">
<Storyboard/>
</vsm:VisualState>
<vsm:VisualState
x:Name="Disabled">
<Storyboard/>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Path
HorizontalAlignment="Stretch" Margin="-0.625,-0.5,-0.75,0.125"
VerticalAlignment="Stretch" Stretch="Fill" StrokeThickness="1" Data="M-
0.12461852,-0.0002709807 L11.250342,-0.0002709807 L11.249977,9.5004301
L6.0003605,17.375883 L0.00038105118,9.7503767 z" Stroke="#FF696A6E">
<Path.Fill>
78
<GradientStop
Color="#FFFFFFFF" Offset="0.002"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="VoyagerSlider" TargetType="Slider">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid x:Name="Root">
<Grid.Resources>
<ControlTemplate
x:Key="RepeatButtonTemplate">
<Grid x:Name="Root"
Background="Transparent" Opacity="0"/>
</ControlTemplate>
</Grid.Resources>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup
x:Name="CommonStates">
<vsm:VisualStateGroup.Transitions>
<vsm:VisualTransition Duration="0"/>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState
x:Name="Normal"/>
<vsm:VisualState
x:Name="MouseOver"/>
<vsm:VisualState
x:Name="Disabled">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Root"
Storyboard.TargetProperty="(UIElement.Opacity)">
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
<vsm:VisualStateGroup
x:Name="FocusStates">
<vsm:VisualStateGroup.Transitions>
<vsm:VisualTransition Duration="0"/>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState
x:Name="Unfocused"/>
<vsm:VisualState
x:Name="Focused">
<Storyboard>
79
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual"
Storyboard.TargetProperty="(UIElement.Opacity)">
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Grid
x:Name="HorizontalTemplate">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="Auto"/>
<ColumnDefinition
Width="Auto"/>
<ColumnDefinition
Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle Height="3"
Margin="5,0,5,0" Grid.Column="0" Grid.ColumnSpan="3" StrokeThickness="0.5"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="HorizontalTrackLargeChangeDecreaseRepeatButton" Grid.Column="0"
IsHitTestVisible="False"/>
<Thumb Height="18"
x:Name="HorizontalThumb" Style="{StaticResource VoyagetThumbStyle}" Width="11"
Grid.Column="1"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="HorizontalTrackLargeChangeIncreaseRepeatButton" Grid.Column="2"
IsHitTestVisible="False"/>
</Grid>
<Grid x:Name="VerticalTemplate"
Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition
Height="*"/>
<RowDefinition
Height="Auto"/>
<RowDefinition
Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle
Margin="0,5,0,5" Width="3" Grid.Row="0" Grid.RowSpan="3" Fill="#FFE6EFF7"
Stroke="Black" StrokeThickness="0.5"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="VerticalTrackLargeChangeDecreaseRepeatButton" Grid.Row="2"/>
<Thumb Height="11"
x:Name="VerticalThumb" Width="18" Grid.Row="1"/>
<RepeatButton
IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}"
x:Name="VerticalTrackLargeChangeIncreaseRepeatButton" Grid.Row="0"/>
</Grid>
<Rectangle x:Name="FocusVisual"
Stroke="#666666" StrokeDashArray=".2 5" StrokeDashCap="Round"
IsHitTestVisible="false" Opacity="0"/>
</Grid>
</ControlTemplate>
80
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
81
E- Layout Personalizado no
Silverlight
Criando Painéis de Layout Personalizado
Introdução
A maioria das aplicações web podem se beneficiar com um layout dinâmico que pode se ‘redimensionar’
para tirar proveito do estado real disponível na tela.
No Silverlight2, os ‘containers’ usados para Layout são chamados de Panels (painéis) porque são classes
que geralmente herdam da classe Panel.
Se você precisar de um layout diferente dos que vêm com o produto, é fácil criar um painel
personalizado. O Silverlight, como o WPF, faz o que é chamado de layout em dois passos:
1. Um container vai chamar Measure () em cada um de seus filhos. Durante o passo Measure, o
container está dizendo aos filhos quanto elemento está disponível.
a. Durante o Measure, cada Filho define sua propriedade DesiredSize para que o container
saiba de quanto espaço o elemento Filho vai precisar.
82
2. Quando o container tiver medido seus filhos, ele os organiza (Arrange()) nos lugares adequados.
Organizá-los significa posicionar no deslocamento certo a partir da coordenada 0,0 no Painel.
Objetivos do Laboratório:
Neste laboratório você vai além dos painéis básicos que vêm com o Silverlight 2, criando vários painéis
personalizados. Você vai construir:
83
Seção 1: Criando um WrapPanel
Personalizado
Um WrapPanel posiciona seus filhos em um layout de fluxo seqüencial, da esquerda para a direita.
Se o painel alcançar o final do lado direito, ele começará uma nova linha e continuará dispondo os itens
da esquerda para a direita na linha seguinte.
Para criar um WrapPanel você vai herdar de Panel; ele dá a você a coleção Children (Filhos), e as funções
Measure/Arrange (Medir/Organizar) necessárias; você vai substituí-los para personalizar o layout.
84
Tarefa 1: Crie uma classe WrapPanel
[Se o Visual Studio pedir para que você crie uma aplicação web para o projeto, fique à vontade para
dizer Não e apenas diga ao VS para criar uma página HTML para teste].
85
Tarefa 2: Meça seus Filhos para encontrar seu Tamanho
Desejado.
O WrapPanel herda uma coleção de Children (Filhos) de Panel, e é assim que vai acessar itens nela.
Para descobrir o DesiredSize (Tamanho Desejado) de cada um de seus filhos, o WrapPanel terá que
chamar Measure() em cada filho. Você pode realizar isso implementando (ou substituindo) a função
MeasureOverride do Panel. Essa função será chamada sempre que ocorrer um passo de layout (e antes
de Arrange).
Nós não fazemos nenhum trabalho além de Medir (Measure) os itens (isto é, não os posicionamos
durante um passo de medida).
1. Substitua a classe MeasureOverride de seu WrapPanel e chame Measure() para cada um dos
Children do painel.
Note que o parâmetro availableSize que você está passando para Measure é o tamanho disponível para
nosso WrapPanel. Passando esse Size (Tamanho) para cada filho, o WrapPanel está dizendo a cada Child
(Filho) que esse espaço está disponível. Se o DesiredSize (tamanho desejado) do filho for maior que o
availableSize (tamanho disponível), ele será recortado. Por exemplo, se o DesiredSize.Width do Child
for 500, mas o availableSize.Width do WrapPanel for 400, apenas os primeiros 400 pixels estarão
visíveis. Os outros 100 serão recortados.
86
Tarefa 3: Organize nossos filhos
Quando você mediu as dimensões dos filhos, cada um deles definiu sua propriedade DesiredSize com o
tamanho que queria ter; agora você precisa ler esse tamanho e posicioná-los dentro do espaço do Panel.
O código está abaixo, mas ele é pré-comentado, então você pode comentar as linhas de que precisa.
(Sou astuto, não?)
87
Tarefa 4: Exercitando nosso Painel
O WrapPanel está bastante básico agora, ele não manipula Margem ou Visibilidade, mas é bom o
suficiente para ser exibido. Vamos entrar no Page.xaml e criar uma instância do WrapPanel e dar a ele
alguns filhos.
1. No Page.xaml, na declaração UserControl, adicione uma declaração xmlns para seu namespace
<UserControl x:Class="MargiesTravel.Controls.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcl="clr-namespace:MargiesTravel.Controls"
Width="400" Height="300">
2. Dentro do Grid, insira um WrapPanel e lembre-se de colocar nele um prefixo com o namespace
xml que você declarou no passo acima (se copiou e colou, o namespace é lcl).
<lcl:WrapPanel>
3. Agora, dentro do WrapPanel, apenas digite Elementos XAML válidos (Button, Rectangle,
TextBlock, etc.). Já que nosso WrapPanel é burro e não faz o alongamento, lembre-se de
especificar para todos os seus itens uma Width e uma Height. Novamente, se você passar do
espaço disponível seus Filhos serão recortados.
[Dica, olhe as Respostas para ver sugestões sobre inserção de Filhos]
88
Seção 2 – Implementando um
TimelineStackPanel para a aplicação do
Voyager
O WrapPanel é fácil porque não há nenhum metadado fornecido dentro do Panel. Isso é bastante
incomum. Se reparar nos outros containers de layout (como Grid e Canvas), você anexou propriedades
como Canvas.Left e Canvas.Top ou Grid.Row e Grid.Column que os itens inseridos nesses painéis usam
como dicas do painel em que precisam estar.
Desta vez, para sua aplicação de viagem, vamos criar um TimelinePanel básico.
Será um Panel que organiza seus Children com base em datas, cada Child diz a ele qual é sua data inicial
e final e a partir daí o Panel vai dizer a ele onde ele precisa estar.
89
[se você pensar bem, Viagem é baseada em tempo, aviões partem e pousam em horários específicos,
você faz reservas em hotéis para dias, etc., então o painel será útil para dispor as coisas com base no
tempo].
90
Tarefa 1: Crie uma classe TimelineStackPanel
Se você se lembrar do WrapPanel, nós implementamos MeasureOverride para fazer os Filhos calcularem
seu DesiredSize. Na verdade nós NÃO temos que fazer isso para TimelineStackPanel porque ele não
respeita o DesiredSize dos Filhos; ele calcula seu tamanho com base em sua Data Inicial/Final.
91
Tarefa 3 Adicionando Propriedades de Dependência Anexadas ao
TimelineStackPanel
O TimelineStackPanel precisa saber onde colocar seus filhos; os Filhos precisarão definir sua
Propriedade Begin/End para que o TimelineStackPanel saiba onde colocá-los.
Os filhos, no entanto, são controles e UIElements existentes (como Rectangle), então você não pode
voltar a eles e adicionar uma propriedade Begin/End. Propriedades Anexadas salvam o dia; o
TimelineStackPanel vai expor uma propriedade Begin/End que os Filhos poderão definir.
O modo mais fácil de criar uma propriedade anexada no editor de Código do Visual Studio é através de
trechos de código.
Se você digitar propa, pressionar Enter e depois Tab, o gerenciador de trechos vai criar uma Propriedade
de Dependência Anexada. Isso, infelizmente, usa a sintaxe do WPF, que é um pouco diferente do
Silverlight mas ainda ajuda bastante. Tudo o que você tem que fazer é mudar o último parâmetro na
propriedade de dependência anexada para que seja nulo, em vez de uma nova UIPropertyMetadata (0).
A Propriedade de Dependência anexada para uma propriedade chamada Begin deve ficar assim:
Vamos ao trabalho:
92
Tarefa 4: Notificando o Panel quando um Begin ou End for alterado
Imagine que os itens são inseridos no TimelineStackPanel, o painel está fazendo a Organização de
nossos itens, se uma propriedade Begin ou End mudar ou for modificada, o Panel deve invalidar seu
layout e Reorganizar os filhos apropriadamente. Infelizmente, na declaração das propriedades na Tarefa
3, nós não vimos uma Change Notification Callback (Chamada de Notificação de Mudança).
5. Volte às Propriedades Begin/End e na declaração RegisterAttached (), onde você põe nulo no
último parâmetro, mude-a para uma instância de PropertyMetaData com um Manipulador
PropertyChangedCallback, e isso será chamado sempre que Begin ou End forem modificados. O
nome da função chamada será OnBeginEndChanged.
Note que a assinatura é Estática, ela tem que ser assim porque é chamada a partir de RegisterAttached,
que também é estático.
Agora OnBeginEndChanged não está fazendo nada, e ele precisa avisar o TimelineStackPanel que este
deve invalidar o layout. Como podemos fazer isso?
93
// {
// TimelineStackPanel parent = fe.Parent as TimelineStackPanel;
// if (parent != null)
// {
// parent.InvalidateArrange();
// }
// else
// fe.InvalidateArrange();
// }
//}
94
Tarefa 5: Adicionando Propriedades de Dependência Low e High ao nosso
Painel.
Este passo poderia ser opcional, mas é necessário para a aplicação do Voyager e faz sentido até para o
Panel. Vamos dar a ele uma propriedade Low (Baixa) e High (Alta) para seu layout. Imagine por exemplo
que o TimelineStackPanel está plotando um vôo. O vôo pode ser de 9:45 a 12:15 mas nós queremos
plotá-lo como um dia inteiro, ou ao menos como 9 da manhã a 1 da tarde. É isso que a Low e a High
farão; elas definem o intervalo.
Low e High não são propriedades de dependência anexadas. Elas são propriedades de dependência
regulares, pois são definidas na instância do Panel. É como definir Width/Height ou qualquer outra
propriedade anexada.
Similar ao trecho propa, há um trecho propdp que podemos usar para criar nossas propriedades no
Editor de Código.
Digite propdp, pressione Enter e depois Tab no editor do VS, dentro de nossa classe TimelineStackPanel.
Você vai precisar substituir novamente o último parâmetro já que são trechos do WPF.
Para uma propriedade DateTime chamada Low, possuída pelo TimelineStackPanel, ficará assim:
Dica:
95
11. Adicione uma DependencyProperty High ao nosso TimelineStackPanel (igual ao passo acima mas
com Low em vez de High).
96
Tarefa 6: Notificando o Panel que as propriedades Low/High mudaram
Similar a quando uma propriedade do Filho mudou, o TimelineStackPanel precisa invalidar seu layout
quando suas propriedades Low e High mudaram.
[O trecho abaixo mostra a sintaxe; em destaque está o que mudou na declaração LowProperty].
13. Repita o passo acima e adicione OnRangeChanged como notificação, mas desta vez para a
Propriedade High.
97
Tarefa 7: Implementando o Arrange (Organizar)
Agora que o TimelineStackPanel tem um Low e um High para o intervalo, é hora de Organizar nossos
Filhos com base em sua linha do tempo. Aqui está tudo o que temos que fazer; a maior parte é lógica de
negócios, então o código está incluído.
Note que eu fiz algo engraçado e converti as datas para o dobro. Fica mais fácil comparar e
calcular larguras...
if (min == 0 || max == 0)
{
GetMinMax(ref min, ref max);
}
98
18. Agora que temos um intervalo de datas, pegue o espaço disponível e divida-o pelo
intervalo para calcular um multiplicador para onde colocar os itens.
19. Finalmente, organize os filhos de modo similar ao que fizemos antes no WrapPanel.
}
return finalSize;
99
Tarefa 8: Resolvendo um problema de Conversor
[Esse passo é opcional]. Você implementou cada coisa necessária para a aplicação do Voyager. Mas
para testar de forma fácil o laboratório você deve querer fazê-lo em XAML, certo??
Na beta2, há um problema em aberto: nós não podemos anexar um Conversor de DateTime to String a
uma propriedade anexada. Sem um conversor, não seria fácil definir a propriedade Begin/End a partir
do XAML. Como solução temporária, você pode anexar a propriedade de Dependências Anexadas (como
na Tarefa 3), mas desta vez do tipo string. O TimelineStackPanel vai conectar essas propriedades às
propriedades Begin/End originais.
A tarefa é apenas uma repetição de tudo que fizemos antes (Tarefa 3).
100
Tarefa 9: Testando nosso TimelineStackPanel a partir do código
O Voyager é controlado por dados, então vamos usar o TimelineStackPanel a partir do código. Portanto
você podia ter pulado o passo 8. Para testar a partir do código vamos ter que:
23. Voltar ao Page.xaml, onde testamos nosso WrapPanel, e substituir a declaração WrapPanel por
uma declaração TimelineStackPanel. [Certifique-se de dar a ela um x:Name no XAML para que
possamos acessá-la a partir do código].
O End deve ser maior que o Begin porque não há verificação de erros em nosso Panel.
timepanel.Low = DateTime.Today;
timepanel.High = DateTime.Today.AddDays(30);
for (int x = 0; x < 5; x++)
{
Rectangle rect = new Rectangle();
rect.Fill = new SolidColorBrush(Color.FromArgb((byte)255,
(byte)(x * 70), (byte)(x * 70), (byte)(x * 70)));
TimelineStackPanel.SetBegin(rect, DateTime.Today.AddDays((4 *
x)));
TimelineStackPanel.SetEnd(rect, DateTime.Today.AddDays((4 * x)
+ 1));
timepanel.Children.Add(rect);
}
}
101
Tarefa 10: Testando nosso TimelineStackPanel a partir do XAML
Se você implementou o passo 8, pode testar nosso painel no XAML. Basta entrar na declaração
TimelineStackPanel no XAML e inserir qualquer tipo de UIElement no painel. Lembre-se de colocar datas
StreBegin e StrEnd no item. Essas são propriedades anexadas, então têm esta sintaxe atribuída (para
uma declaração de namespace de lcl)
Divirta-se um pouco com o painel. Faça combinações e correspondências, inserindo por exemplo itens a
partir do XAML e do Código.
Adicione um botão ao seu código ou algum controle de datas que altere as datas no vôo para poder ver
o painel de pilha se reorganizar conforme o necessário.
102
Apêndices
//É assim que fica o WrapPanel inteiro. Em destaque está o código que você teria adicionado.
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace MargiesTravel.Controls
{
public class WrapPanel : Panel
{
}
}
103
Tarefa 3: Passo 2 -- Implementando o Arrange
<UserControl x:Class="MargiesTravel.Controls.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcl="clr-namespace:MargiesTravel.Controls"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<lcl:WrapPanel>
<Rectangle Width="200" Height="50" Fill="Red" > </Rectangle>
<Rectangle Width="100" Height="20" Fill="Yellow" ></Rectangle>
<Rectangle Width="70" Height="70" Fill="Green" ></Rectangle>
<Rectangle Width="100" Height="50" Fill="Red" ></Rectangle>
<Rectangle Width="100" Height="100" Fill="Yellow" ></Rectangle>
<Rectangle Width="400" Height="70" Fill="Green" ></Rectangle>
<Rectangle Width="500" Height="70" Fill="Red" ></Rectangle>
</lcl:WrapPanel>
</Grid>
</UserControl>
OU
<UserControl x:Class="MargiesTravel.Controls.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
104
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcl="clr-namespace:MargiesTravel.Controls"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<lcl:WrapPanel>
<Button Content="button" Width="200" Height="50" />
<TextBlock Text="TextBlock" Width="150" Height="30"/>
<Slider Width="300" Value="6" Height="50"/>
<TextBox Width="200" Height="30" />
<TextBlock Text="Autosize text" />
<CheckBox Content="checkbox" Width="140" />
</lcl:WrapPanel>
</Grid>
</UserControl>
105
}
//Esta tarefa mostra em destaque as alterações que você teve que fazer para conectar a notificação de
Alteração.
//Abaixo disso está o código para OnBeginEndChanged. É ‘código novo’.
106
Tarefa 5: Adicionando Propriedades de Dependência Low e High ao nosso
Painel.
107
Tarefa 7: Implementando o Arrange
if ( min == 0 || max == 0 )
{
GetMinMax ( ref min, ref max );
}
}
return finalSize;
}
108
Tarefa 8: Resolvendo um problema de Conversor
109
Tarefa 9: Testando nosso TimelineStackPanel a partir do código
timepanel.Low = DateTime.Today;
timepanel.High = DateTime.Today.AddDays(30);
for (int x = 0; x < 5; x++)
{
Rectangle rect = new Rectangle();
rect.Fill = new SolidColorBrush(Color.FromArgb((byte)255,
(byte)(x * 70), (byte)(x * 70), (byte)(x * 70)));
TimelineStackPanel.SetBegin(rect, DateTime.Today.AddDays((4 *
x)));
TimelineStackPanel.SetEnd(rect, DateTime.Today.AddDays((4 * x)
+ 1));
timepanel.Children.Add(rect);
}
}
<UserControl x:Class="MargiesTravel.Controls.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcl="clr-namespace:MargiesTravel.Controls"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<lcl:TimelineStackPanel x:Name="timepanel" >
<Rectangle Fill="Red" lcl:TimelineStackPanel.StrBegin="6/11/2008"
lcl:TimelineStackPanel.StrEnd="6/12/2008" />
<Rectangle Fill="Yellow"
lcl:TimelineStackPanel.StrBegin="6/13/2008"
lcl:TimelineStackPanel.StrEnd="6/15/2008" />
<Rectangle Fill="Green" lcl:TimelineStackPanel.StrBegin="6/17/2008"
lcl:TimelineStackPanel.StrEnd="6/18/2008" />
</lcl:TimelineStackPanel>
</Grid>
</UserControl>
110
F- Usando Dados nas Aplicações do
Silverlight
Ligação de dados a objetos, coleções e o DataGrid.
Introdução
A ligação de dados é o processo de estabelecer uma conexão, ou ligação, entre a interface de usuário
(UI) e um objeto CLR para permitir que os dados fluam entre os dois: Se uma ligação Bidirecional é
estabelecida e os dados mudam, os elementos da interface de usuário ligados aos dados podem refletir
as mudanças automaticamente. Similarmente, as mudanças feitas através da interface de usuário são
refletidas no objeto de dados.
Objetivos do Laboratório:
111
Ligando uma Coleção a uma ListBox e criando Datatemplates
Criando uma Exibição Mestre/Detalhes
No Exercício 2 (laboratório separado), você vai implementar a ligação de dados necessária para a
aplicação do Voyager.
112
Tarefa 1: Criando uma Ligação Simples usando XAML e
DataContext
1.A partir do code-behind, no construtor Page(), após a chamada InitalizeComponent, defina o valor
de packageGrid.DataContext para TestData.package.
2.Agora edite o XAML para que ele ligue a Interface de Usuário às propriedades de
TestData.Package.
3. Execute sua aplicação e note que a interface de usuário exibe agora todos os dados de
TestData.Package.
Note que o DataContext pode ser substituído localmente, e também que um DataContext local pode ser ligado ao
DataContext herdado de um elemento.
113
Tarefa 2: Ligando a uma Coleção (usando um
DataTemplate)
Ligar a um item foi ótimo para testar, mas é necessário neste caso ligar a uma coleção (a propriedade
TestData.Packages).
Pegue o XAML na Página 1 e transforme-o em um UserControl; depois ligue os dados desse User
Control, dessa forma você acaba tendo um controle reutilizável para pôr em nossas coleções.
Crie um DataTemplate, que também dá a você um modelo reutilizável e não incorre na
sobrecarga de criar o UserControl (o que não é necessário neste caso).
this.packagesListbox.ItemsSource = TestData.Packages;
114
8.Execute a aplicação para ver se a Listbox funciona.
115
Tarefa 3: Substituindo a Listbox por um DataGrid
Uma alternativa à substituição do modelo da caixa de listagem é usar um controle diferente, como o
DataGrid. A grade, com sua habilidade de exibir colunas, seria ótima para vermos todas as colunas de
uma vez em um formato tabular.
<UserControl x:Class="DataLab.Task3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300"
xmlns:data="clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
10. Agora adicione uma instância do DataGrid para substituir a Listbox (em LayoutRoot)
11. Selecione Auto-Gerar Colunas para não termos que fazer todo o trabalho.
[Não era bem o que eu esperava... teria ficado melhor se Package fosse um objeto plano, você
não acha?? Bem, é tarde demais para mudar o modelo do objeto, então vamos corrigir as
Colunas no DataGrid
116
Tarefa 4: Personalizando as colunas no DataGrid
É claro que o DataGrid também usa o DataTemplate para personalizar suas colunas.
Infelizmente não podemos reutilizar o Modelo de Dados que usamos para a ListBox, pois aquele é para
todos os dados e aqui no DataGrid queremos criar um por coluna.
<data:DataGrid.Columns>
<data:DataGridTemplateColumn Header=”Tracking No.” >
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding TrackingNo}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
117
Tarefa 5 – Exibição Mestre/Detalhes usando Ligações a
partir do código
Agora que o DataGrid está mostrando os dados em linhas, você pode trazer de volta o modelo Package
único e usá-lo como uma Exibição de Detalhes para um pacote – aquele selecionado na grade.
Vamos primeiro adicionar a interface de usuário para os “detalhes”.
5. Adicione uma classe simples que expõe uma propriedade do tipo objeto, o nome da propriedade
é SelectedItem. A classe deve implementar INotifyPropertyChanged para notificação de
mudanças.
[Você pode ver a resposta para ter uma dica, mas tente fazer, pois você vai implementar
INotifyPropertyChanged muito quando fizer dados com o Silverlight]
Agora que o objeto de negócios ViewModel está pronto, precisamos criar uma Ligação. Neste caso
vamos fazer isso a partir do código, já que todas as nossas outras ligações foram feitas a partir do
118
XAML.
6. Adicione um manipulador de eventos Loaded ao construtor de sua Página, logo depois do lugar
em que estava definindo o itemsSource do DataGrid.
7. No manipulador de eventos Loaded, instancie uma instância do ViewModel. Isso pode ser feito
em escopo local.
A fonte será o objeto ViewModel v criado no passo anterior. O destino será o DataGrid (ainda
chamado de packagesListBox) e a ligação será bidirecional. O código comentado abaixo deve dar
uma dica a você.
Isso liga o selectedItem do DataGrid ao nosso objeto fictício, mas nós precisamos desse mesmo objeto
para guiar nosso ContentPresenter de detalhes.
9. Crie uma ligação com v como a Source, e nosso ContentControl de “detalhes” como o
SelectedItem como a fonte, mas desta vez para a Propriedade Content de detalhes.
10. Agora você pode executar a aplicação e conforme mudar a seleção no DataGrid, seu
Apresentador de conteúdos deve ser atualizado também.
119
Tarefa 6: Exercício para o usuário
Note que a seleção do DataGrid funciona bem para atualizar detalhes, mas se você fizer alterações nos
campos de detalhes (como mudar o endereço), elas não serão propagadas para a grade. Por quê??
Obviamente porque o Package não implementou ainda o INotifyPropertyChanged. Vá em frente e
implemente-o para poder ver a atualização das mudanças.
120
Apêndice
this.packageGrid.DataContext = TestData.Package;
this.packagesListbox.ItemsSource = TestData.Packages;
O XAML fica como o de abaixo, embora sua x:Class possa ser chamada de Page em vez de Task2.
<UserControl x:Class="DataLab.Task2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" xmlns:DataLab="clr-namespace:DataLab"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
121
<Style TargetType="TextBlock" x:Key="rightLabel">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Margin" Value="0,2,5,2" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="Foreground" Value="#FF264EA7" />
</Style>
<DataTemplate x:Key="PackageTemplate">
<Grid Height="256" Width="336" x:Name="packageGrid" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.286*"/>
<ColumnDefinition Width="0.238*"/>
<ColumnDefinition Width="0.254*"/>
<ColumnDefinition Width="0.222*"/>
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource rightLabel}" Grid.Column="0"
Grid.ColumnSpan="1" Grid.Row="0" Text="Tracking No." Width="Auto" Margin="0,2,-
5,2" />
<TextBlock Style="{StaticResource rightLabel}" Grid.Column="0"
Grid.ColumnSpan="1" Grid.Row="2" Text="Address" x:Name="lblAddress"/>
<TextBlock Style="{StaticResource rightLabel}"
Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="1" Text="Name" x:Name="lblName"/>
122
<TextBox Style="{StaticResource leftFE}" Grid.Row="4" Grid.Column="1"
Text="{Binding Address.ZipCode}" x:Name="txtZip"/>
<TextBox Style="{StaticResource leftFE}" Grid.Row="4" Grid.Column="3"
Text="{Binding Address.Country}" x:Name="txtCountry"/>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" >
</Grid>
</UserControl>
123
Tarefa 3: Substituindo a Listbox por um DataGrid
<!— É assim que fica o LayoutRoot no Page.xaml -->
124
Tarefa 4: Personalizando as colunas no DataGrid
<!— é assim que fica o XAML para o Grid do LayoutRoot inteiro -->
<data:DataGridTemplateColumn Header="Name">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Address.Name}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTemplateColumn Header="Address">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Address.Street}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTemplateColumn Header="City">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Address.City}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTemplateColumn Header="Delivered">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<extended:DatePicker SelectedDate="{Binding DeliveredDate}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
125
Tarefa 5: Implementando InotifyPropertyChanged (Passo 17)
#endregion
}
126
Tarefa 6 - Implementando INotifyPropertyChanged (Passo 9).
b = new Binding("SelectedItem");
b.Source = v;
b.Mode = BindingMode.TwoWay;
details.SetBinding(ContentControl.ContentProperty, b);
127
G- Construindo um Media
Player Simples
Primeiros Passos na Construção de um Media Player no Silverlight 2
Neste laboratório você vai construir um media player simples usando o controle <MediaElement> do
Silverlight. Você verá como usar a funcionalidade Play (Executar), Stop (Parar) e Pause (Pausar), bem
como manipular o progresso, o buffering e os marcadores de mídia.
128
Seção 1: Criando uma Página de Mídia
no Silverlight
Usando o Visual Studio, crie um novo projeto do Silverlight e chame-o de MediaLab. Lembre-se de
adicionar um Site (padrão MediaPageWeb) à solução.
No Site, certifique-se de que o MediaLabTestPage.aspx está definido como a página padrão para
o site. Execute a aplicação e você verá algo como a Figura 1.
129
Figura 1. O Media Player Simples
Você pode ver que o vídeo está sendo reproduzido sem problemas. No próximo passo, você vai
adicionar alguns Controles Play, Stop e Pause simples a ele.
130
Seção 2: Adicionando controles de
Reprodução à sua Mídia
O elemento de mídia do Silverlight fornece controles Play, Stop e Pause que podem ser usados para
controlar a reprodução de vídeo. Neste passo você vai adicionar uma interface de usuário simples que
sobrepõe o vídeo com os controles 'Play', 'Stop' e 'Pause', e você escreverá os manipuladores de eventos
para eles.
Adicione este XAML à interface de usuário. (Note que isso deve ser em um Canvas e não o Grid
padrão. Veja se você pode descobrir como fazer isso!). Ponha-o no lugar apropriado para que os
controles sejam escritos no vídeo. Se você digitar este código, notará que quando especifica os
eventos ‘MouseLeftButtonUp’, o Visual Studio pede que você selecione um novo manipulador
de eventos. Vá em frente e aceite, e os stubs do código serão escritos para você.
<StackPanel Orientation="Horizontal"
Canvas.Top="260" Width="400" Background="Beige">
<TextBlock x:Name="tPlay" Text="Play "
MouseLeftButtonUp="tPlay_MouseLeftButtonUp" />
<TextBlock x:Name="tPause" Text="Pause "
MouseLeftButtonUp="tPause_MouseLeftButtonUp"/>
<TextBlock x:Name="tStop" Text="Stop "
MouseLeftButtonUp="tStop_MouseLeftButtonUp"/>
</StackPanel>
Quando tiver terminado, execute a aplicação e você poderá executar, parar ou pausar o vídeo.
Você pode ver como isso ficaria na Figura 2.
131
Figura 2. Media Player com controles simples de reprodução
132
Seção 3: Usando o Progresso de
Download e o Progresso de Buffer
DownloadProgressChanged="mel_DownloadProgressChanged"
Adicione este TextBlock ao mesmo <StackPanel> dos blocos de texto Play, Stop e Pause:
A fonte do evento é o MediaElement, então você pode converter o e.Source e ter a propriedade
DownloadProgress como é mostrado.
O DownloadProgress contém um número entre 0 e 1, com 1 sendo 100% completo. Se você
executá-lo, verá o status ‘piscar’ rapidamente pois ele está fazendo o download muito rápido a
partir de seu disco rígido. Ao acessar o vídeo pela web, não será tão rápido.
Você pode formatar o valor em uma porcentagem de forma fácil – numérica ou visualmente!
Similarmente, você pode conectar o BufferingProgressChanged e visualizar a propriedade
BufferingProgress. Isso é útil se você tiver um vídeo baixado progressivo.
133
Seção 4: Gerenciando Marcadores de
Mídia
Neste passo vamos ver o uso do Expression Encoder para adicionar marcadores ao vídeo. Vamos
também capturar esses marcadores em nosso código do Silverlight.
Abra o Expression Encoder 2 e adicione o Bear Video (Vídeo do Urso) a ele. Você pode ver isso na Figura
3.
134
Em torno da marca de 4,2 segundos, adicione um novo marcador e dê a ele o valor ‘Urso Fareja
Gaivota’.
Ao redor da marca de 8,6 segundos, adicione um novo marcador e dê a ele o valor ‘Urso decide
comer gaivota’.
Ao redor da marca de 8,9 segundos, adicione um novo marcador e dê a ele o valor ‘Gaivota
decide voar para longe’.
Em torno da marca de 11,5 segundos, adicione um novo marcador e dê a ele o valor ‘Urso pensa
‘Droga’’.
Clique no botão ‘Encode’ na parte inferior da tela.
O arquivo irá para a pasta Documents\Expression\Expression Encoder.
Substitua o Bear.wmv em seu projeto pelo que você acabou de codificar.
Em seu projeto do Silverlight, adicione este Atributo ao seu Media Element
MarkerReached="mel_MarkerReached"
Em seu code-behind você pode agora capturar os marcadores que acabou de adicionar ao vídeo,
e escrevê-los para o status do vídeo – veja o código:
135
H- Silverlight e Aplicações
Conectadas
Conectando suas Aplicações do Silverlight a serviços de Dados e Web
Introdução
O Silverlight 2 fornece uma funcionalidade que permite conectar sua aplicação, conforme ela é
executada no navegador, a recursos baseados em servidor. Há várias maneiras em que o Silverlight pode
se integrar a eles, desde uma simples solicitação HTTP usando um WebClient a solicitações HTTP mais
complexas usando as classes WebRequest/WebResponse, e assim por diante, até classes proxy para
consumo de serviços da Web WCF bem como serviços de dados ADO.
Usam um Cliente da Web para obter Dados de Cidades de uma página da web que serão
plotados em um Mapa do Virtual Earth
Usam uma interação Web Request / Web Response para ver como os dados HTTP podem ser
postados de volta a um servidor Web
Constroem um serviço da Web WCF que fornece dados, e usam um proxy gerado no Silverlight
para consumi-lo
Constroem um serviço de Dados ADO que fornece dados, e o consomem dentro do Silverlight
A terceira seção, usando WCF, é particularmente especial – você verá como o WCF e o Silverlight
trabalham ‘melhor juntos’ para dar a você uma experiência muito melhor como desenvolvedor na
criação da aplicação ligada a dados! Quando comparado ao uso de WebRequest/WebResponse, você
tem muito mais facilidade, e escreve menos de 1/3 do código para fazer a mesma coisa.
136
Seção 1: Usando o WebClient para Ler
Dados Remotos de Ligação para o
Silverlight
Neste exercício você vai construir um serviço POX (Plain Old XML) simples que fornece dados de cidades
quando chamado, e vai ligar conteúdos a esses dados dentro do Silverlight.
Crie uma nova aplicação do Silverlight e chame-a de Sample1. Lembre-se de selecionar que quer um Site
como parte da solução quando o fizer.
3. Adicione uma nova Classe, chamada CityData.cs à parte de site de sua solução.
4. Adicione variáveis de membro para CityName (seqüência de caracteres) Latitude (dobro) e
Longitude (dobro).
5. Mantenha o construtor padrão (sem parâmetros)
6. Adicione outro construtor que pega uma seqüência de caracteres e dois dobros e inicializa as
variáveis de membro
137
Tarefa 2: Crie o Serviço XML
Nesta tarefa você vai adicionar um manipulador genérico e fazê-lo retornar dados XML fictícios ao
chamador.
using System.Linq;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
Seus dados de cidades serão mantidos em um objeto List<T>, então adicione a declaração a ele
no topo da classe de manipulador genérico
Se você construiu corretamente o manipulador Genérico, pode agora chamá-lo e ver os resultados como
os da Figura 1.
138
Você pode notar que o nó ArrayOfCityData foi gerado para você pelo XmlWriter. Também foi dado a ele
um namespace e um XSD padrão.
139
Tarefa 3: Crie o XAML ao qual fará ligações
O ItemsControl do XAML permite definir como renderizar dados ligados de acordo com um
DataTemplate. Você pode ver aqui como especificar um XAML que defina um único TextBlock que se
liga ao campo CityName. [Isto deve estar no arquivo Page.xaml em seu projeto do Silverlight]
<ItemsControl x:Name="_cities">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="14" Height="30" Text="{Binding CityName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Veja se consegue atualizar isso para ter 3 TextBlocks, com os outros dois estando ligados a
Latitude e Longitude respectivamente
140
Tarefa 4: Crie a solicitação e o retorno de chamada do
WebClient
Antes de codificar o WebClient, é uma boa idéia definir uma porta estática para seu projeto da Web ser
executado. Para isso, selecione o projeto da Web no Solution Explorer e pressione F4 para abrir a janela
de propriedades.
Encontre a entrada ‘Use Dynamic Ports’ e defina-a como ‘False’. Salve tudo, encontre a configuração '
Port Number' e coloque ‘8001’.
Agora o URI para o manipulador que retorna XML para você pode ser determinado para estar em:
http://localhost:8001/Sample1Web/GetData.ashx
141
Olhe o code-behind do Page.xaml.cs para o projeto do Silverlight. Você verá um construtor
Page() que tem uma única linha (‘InitializeComponent()’). Adicione novo código a ele para criar
uma nova instância da classe WebClient e instrua-o a fazer download de uma seqüência de
caracteres do URI acima, bem como conectar um retorno de chamada completado do
manipulador de eventos.
142
Tarefa 5: Ligando os Dados no Retorno de Chamada
O ItemsControl que você criou na Tarefa 3 se ligará a um tipo de IEnumerable, então você precisa obter
os resultados do retorno de chamada do serviço de dados e formatá-los apropriadamente.
Enquanto fizer esta Tarefa, adicione o código que vir a esta função.
*Note que você precisará fazer uma referência a System.Xml.Linq e adicionar um ‘using System.Xml.Linq’
ao topo de sua página de código]
Antes de continuar você precisa de uma declaração da classe CityData dentro de seu projeto do
Silverlight também, então agora é um bom momento para adicionar uma e torná-la idêntica à da Tarefa
1. Um dos novos recursos de linguagem do .NET e do Silverlight é a LINQ, que traz alguma programação
funcional ao Silverlight.
Veja como você pode usá-la para criar um IEnumerable de CityData a partir do XML retornado.
Isso vai criar um IEnumerable de objetos CityData com n objetos, onde n é determinado pelo número de
nós de CityData dentro do XML. O XML está embutido em código com 3 elementos, então esse código
data a você 3 objetos CityData dentro do IEnumerable, e suas propriedades CityName, Latitude e
Longitude serão baseadas nos valores dentro dos elementos XML.
Agora que você tem seu IEnumerable, basta ligá-lo ao ItemsControl que, se você se lembra, se chama
‘_cities’.
143
_cities.ItemsSource = cities;
Mais Estudo
Neste exemplo seu ASHX forneceu dados embutidos em código para 1 cidade. Você consegue construí-
lo de modo que aceite parâmetros na seqüência de caracteres URI (isto é,
http://localhost:8001/Sample1Web/GetData.ashx?city=whatever)
144
Seção 2: Usando WebRequest /
WebResponse para obter Dados
Nesta seção do laboratório vamos ver como usar as classes WebRequest e WebResponse para ter um
controle mais refinado sobre a comunicação entre o cliente do Silverlight e o servidor Web. No exemplo
anterior você viu como o WebClient foi usado para chamar uma aplicação de servidor usando seu URI.
Você poderia passar parâmetros a ele na querystring de URI, o que seria um método perfeitamente
válido, mas para o propósito deste exercício, você usará um HTTP-POST para passar os parâmetros como
parte dos cabeçalhos HTTP, e a aplicação de servidor vai abri-los, inspecioná-los e retornar uma
resposta.
Você passará um parâmetro ‘CountryName’, que o servidor vai usar para derivar cidades nesse país e
retorná-las ao chamador.
145
Tarefa 1: Crie o Projeto e instale a aplicação de servidor
Crie uma nova aplicação do Silverlight chamada Sample 2. Lembre-se de selecionar que quer um Site
criado como parte dela.
Adicione uma nova classe CityData, exatamente o mesmo que fez na Seção 1.
Adicione também um Manipulador Genérico e chame-o de GetData.ashx
Certifique-se de que tem as seguintes instruções using no topo do GetData.ashx
using System;
using System.Web;
using System.Linq;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
O “burro de carga” dessa função é a função ProcessRequest, então o próximo passo é adicionar
uma verificação de que estamos usando um HTTP-POST
if (context.Request.HttpMethod == "POST")
{}
strCountry = context.Request.Form["country"].ToString();
Escreva uma função que pegue um país e construa uma List<CityData> de várias cidades para
esse país. Aqui estão algumas cidades e suas latitudes e longitudes:
146
Finalmente, crie um serializador XML e faça um writeback da List<CityData> para o fluxo de
resposta. É idêntico ao que você fez na Seção 1. O código complete está disponível nos
apêndices.
Finalmente, defina as propriedades do projeto da Web para que ele use uma porta estática em vez de
portas dinâmicas, e atribua a ele a porta ‘8002’. Se você não souber fazer isso, verifique a Seção 1.
147
Tarefa 2: Crie a interface de usuário do Silverlight
Vamos criar uma interface de usuário simples que enviará um parâmetro a esse serviço, e obterá os
resultados da List<CityData> para depois ligá-los à interface de usuário.
Adicione um ItemsControl chamado ‘_cities’ que contém um DataTemplate que liga três
controles de TextBlock a CityName, Latitude e Longitude, respectivamente.
Adicione três botões, chamados bUk, bFrance e bGermany respectivamente, com ‘Reino Unido’,
‘França’ e ‘Alemanha’ como suas legendas.
Adicione um manipulador de eventos Click a cada um desses botões
148
Tarefa 3: Escreva a lógica da interface de usuário e da Ligação
de Dados
Antes de continuar, certifique-se de que tem as referências certas:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;
using System.Xml.Linq;
Certifique-se também de que adicionou uma referência a ‘System.Net’ e ‘System.Xml.Linq’ usando ‘Add
Reference’ no Solution Explorer.
A seguir você vai escrever uma função getCitiesFromService() que chama o serviço e faz um
HTTP-POST do país para obter a List<CityData> apropriada
Aqui está o código:
Aqui você instalou o objeto request, e ele está chamando o serviço GetData.ashx. Depois você
começa o fluxo de solicitação (request) e especifica que quando ele estiver pronto você chamará
a função RequestProceed em um retorno de chamada.
Agora vamos ver como construí-lo.
Primeiro, a assinatura do método. Um retorno de chamada dessa natureza é vazio, e aceita um
parâmetro IASyncResult.
Você pode ter uma referência ao seu objeto de solicitação a partir deste asyncResult assim:
149
HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
Em seguida você deve criar um escritor de fluxo que escreva para esse fluxo de solicitação, e
escreva um valor para o parâmetro ‘country=’. Fechar o fluxo faz o writeout.
Finalmente, você deve definir um retorno de chamada para processar a resposta do serviço,
para poder capturar os dados e ligá-los à interface de usuário.
Agora você precisa construir o manipulador de resposta. Isso tem a mesma assinatura de
método do manipulador de resposta que você viu anteriormente.
A primeira coisa que você terá que fazer nessa função é ter uma referência ao seu objeto de
solicitação novamente:
HttpWebResponse response =
(HttpWebResponse)request.EndGetResponse(asyncResult);
A resposta é codificada em XML em uma seqüência de caracteres, então você vai ler o fluxo em
uma seqüência de caracteres:
Para ligar esses dados ao ItemsSource eles precisam ser carregados para um IEnumerable.
Podemos usar a LINQ para fazer isso com facilidade:
150
CityName = city.Element("CityName").Value,
Latitude = Convert.ToDouble(city.Element("Latitude").Value),
Longitude = Convert.ToDouble(city.Element("Longitude").Value)
};
_cities.ItemsSource = cities;
Mas isso não funcionaria! A razão é que o WebRequest/WebResponse atua em um thread de segundo
plano e não no thread da interface de usuário, portanto a interface de usuário não seria atualizada.
Felizmente, há uma solução simples usando o Dispatcher. Este código vai funcionar:
Para seu exercício final, escreva os manipuladores de eventos para os botões para que quando o
usuário clicar neles, a função getCitiesfromService seja chamada e os dados apropriados sejam
retornados.
151
Seção 3: Construindo e Ligando a um
Serviço WCF
Nas seções anteriores, você viu primeiro como construir um serviço POX simples que era acessado via
um WebClient, e depois como estendê-lo para aceitar verbos HTTP-POST usando
WebRequest/WebResponse assíncrono.
Agora você vai ver como o WCF pode ser usado para implementar esse serviço, simplificando-o e
permitindo que você tenha os aspectos seguros, transacionáveis e confiáveis do WCF, bem como a
facilidade de gerar automaticamente classes proxy cliente que manipulam a ‘conexão’ da comunicação
para você.
Além disso, você notará que os dois exemplos anteriores precisaram do modelo de dados para ser
sincronizados entre o cliente e o servidor – isto é, você precisou de uma classe CityData em ambos, e
qualquer diferença entre o código nessas classes faria sua aplicação ser interrompida.
Ao construir o serviço no WCF você vai atribuir seu serviço e suas classes de dados, e a geração do proxy
vai mantê-los em sincronia.
152
Tarefa 1: Crie o Projeto do Silverlight e adicione o Serviço WCF
[ServiceContract]
public interface IGetCities
{
[OperationContract]
List<CityData> getCities(string strCountry);
}
De forma similar aos contratos de Dados que você viu em sua classe, isso especifica os contratos
de operação para seu serviço.
Agora é hora de editar o código do serviço. Vá à classe GetCities.cs e escreva uma função que
retorna uma List<CityData> para um parâmetro ‘country’ de entrada. Você já fez isso (como
uma função auxiliar) no Cenário 2. O código completo está nos apêndices se você precisar.
O último passo é mudar seu projeto da web que usa portas dinâmicas para o uso de uma porta
estática em 8003. Faça isso, clique com o botão direito no arquivo SVC e visualize-o no
navegador para se certificar de que funciona. Note que é uma boa idéia copiar o URI para a área
de transferência, já que você precisará dele para criar o cliente de serviço na próxima tarefa.
153
Tarefa 2: Crie o Cliente do Silverlight e Ligue-o ao Serviço
Nesta tarefa você vai criar o mesmo cliente do Silverlight que criou na seção anterior, mas agora em vez
de escrever todo o código para manipular o WebRequest e o WebResponse, o gerador de proxy do WCF
fará isso por você! Você também verá como é mais fácil ligar o conteúdo do Silverlight aos dados
retornados, porque em vez de serializar e desserializar o XML, a List<CityData> é passada diretamente
ao chamador.
Em seu projeto do Silverlight, adicione uma nova referência de Serviço e aponte-a ao URI do
serviço que criou na Tarefa 1. Dê a ela o nome de CitiesService.
Instale o XAML para que sua interface de usuário tenha exatamente o mesmo XAML que você
usou na Seção 2, contendo um ItemsControl e 3 botões para Reino Unido, França e Alemanha.
Vá ao seu arquivo Page.xaml.cs e adicione as 3 instruções a seguir no topo da página de código -
os 2 primeiros são para o WCF, o terceiro é para seu proxy de serviço. Neste caso o namespace
Sample3 foi usado. Se você chamou o projeto de algo diferente de Sample 3, use esse nome no
lugar:
using System.ServiceModel;
using System.ServiceModel.Channels;
using Sample3.CitiesService;
Codifique os manipuladores de eventos para Clicar nos Botões. Aqui está o de ‘uk’ como
exemplo. Você deve conseguir copiar isto para os outros:
getCitiesfromService("uk");
}
Isso chama uma função chamada getCitiesfromService, passando a ela uma seqüência de
caracteres. Seu próximo passo é escrever essa função, que usa o proxy de serviço para obter a
List<CityData> de volta do serviço. Como ela está usando o proxy, é muito simples - aqui está o
código:
154
Esse código é bastante fácil de entender. Você cria primeiro uma instância da classe proxy,
depois especifica o retorno de chamada, e então chama a função getCitiesAsync passando a ela
a seqüência de caracteres.
O retorno de chamada receberá a List<CityData> de volta, que você pode ligar ao seu
ItemsControl. Aqui está o método completo:
155
Apêndices
public CityData()
{
using System;
using System.Web;
using System.Linq;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
public class GetData : IHttpHandler {
156
using (XmlWriter writer =
XmlWriter.Create(context.Response.OutputStream))
{
context.Response.ContentType = "text/xml";
ser.Serialize(writer, myCities,ns);
}
<ItemsControl x:Name="_cities">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="14" Height="30" Text="{Binding CityName}" />
<TextBlock FontSize="14" Height="0" Text="{Binding Latitude}" />
<TextBlock FontSize="14" Height="0" Text="{Binding Longitude}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note que a altura dos TextBlocks de Latitude e Longitude foi ocultada para mantê-los invisíveis na
renderização.
public Page()
{
InitializeComponent();
WebClient wc = new WebClient();
wc.DownloadStringAsync(new
Uri("http://localhost:8001/Sample1Web/GetData.ashx"));
wc.DownloadStringCompleted += new
DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
}
157
Tarefa 5: Ligando os Dados no Retorno de Chamada
};
_cities.ItemsSource = cities;
}
Seção 2:
switch (strCountry)
{
case "france":
{
ret.Add(new CityData("Paris", 48.87, 2.33));
ret.Add(new CityData("Lourdes", 43.1, 0.05));
ret.Add(new CityData("Toulouse", 43.6, 1.38));
break;
}
case "uk":
{
ret.Add(new CityData("London", 51.5, 0));
ret.Add(new CityData("Stratford-Upon-Avon", 52.3, - .71));
ret.Add(new CityData("Edinburgh", 55.95, -3.16));
break;
}
case "germany":
{
ret.Add(new CityData("Berlin", 52.52, 13.42));
ret.Add(new CityData("Munich", 48.13, 11.57));
ret.Add(new CityData("Hamburg", 53.58, 9.98));
break;
}
default:
{
ret.Add(new CityData("London", 51.5, 0));
ret.Add(new CityData("Stratford-Upon-Avon", 52.3, -1.71));
ret.Add(new CityData("Edinburgh", 55.95, -3.16));
158
break;
}
}
return ret;
}
List<CityData> myCities;
<UserControl x:Class="Sample2.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FontFamily="Trebuchet MS" FontSize="11"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<ItemsControl x:Name="_cities">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="14" Height="30" Text="{Binding
CityName}" ></TextBlock>
<TextBlock FontSize="14" Height="0" Text="{Binding
Latitude}" ></TextBlock>
<TextBlock FontSize="14" Height="0" Text="{Binding
Longitude}" ></TextBlock>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button x:Name="bUk" Content="UK" Click="bUk_Click" />
159
<Button x:Name="bFrance" Content="France" Click="bFrance_Click" />
<Button x:Name="bGermany" Content="Germany" Click="bGermany_Click"
/>
</StackPanel>
</Grid>
</UserControl>
Tarefa 3: Código da Página
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace Sample2
{
public partial class Page : UserControl
{
IEnumerable<CityData> cities;
string strCountry = "uk";
public Page()
{
InitializeComponent();
IEnumerable<CityData> cities =
from city in xReturn.Descendants("CityData")
select new CityData
{
CityName = city.Element("CityName").Value,
Latitude = Convert.ToDouble(city.Element("Latitude").Value),
Longitude = Convert.ToDouble(city.Element("Longitude").Value)
160
};
Seção 3
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Runtime.Serialization;
[DataContract]
public class CityData
{
[DataMember]
161
public string CityName { get; set; }
[DataMember]
public double Latitude { get; set; }
[DataMember]
public double Longitude { get; set; }
public CityData()
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
switch (strCountry)
{
case "france":
{
ret.Add(new CityData("Paris", 48.87, 2.33));
ret.Add(new CityData("Lourdes", 43.1, 0.05));
ret.Add(new CityData("Toulouse", 43.6, 1.38));
break;
}
case "uk":
{
ret.Add(new CityData("London", 51.5, 0));
ret.Add(new CityData("Stratford-Upon-Avon", 52.3, -1.71));
ret.Add(new CityData("Edinburgh", 55.95, -3.16));
break;
}
case "germany":
{
ret.Add(new CityData("Berlin", 52.52, 13.42));
ret.Add(new CityData("Munich", 48.13, 11.57));
ret.Add(new CityData("Hamburg", 53.58, 9.98));
break;
}
162
default:
{
ret.Add(new CityData("London", 51.5, 0));
ret.Add(new CityData("Stratford-Upon-Avon", 52.3, -1.71));
ret.Add(new CityData("Edinburgh", 55.95, -3.16));
break;
}
}
return ret;
}
}
163