Element Binding e 3D em Silverlight 3

A versão beta do Silverlight 3 foi lançada no Mix 2009 e trouxe diversas novidades. Entre elas estão o Element Binding e a possibilidade de simular 3D nas aplicações.


O Element Binding é um tipo de data binding já existente no WPF, mas que não tinha sido implementado no Silverlight 2. No Silverlight 2 podiamos fazer ligação da interface com os dados de uma classe interna, mas não podíamos ligar 2 as propriedades de dois elementos visuais. Por exemplo, se quiséssemos colocar um TextBlock e um Slider na janela e mostrar a posição do Slider no TextBlock, deveríamos criar uma classe no código e ligar os dados da classe aos dois componentes. O código ficaria assim:


Code behind:


namespace SL2Binding


{


    public class Binder : INotifyPropertyChanged


    {


        private double posicao;


        public double Posicao


        {


            get { return posicao; }


            set


            {


                posicao = value;


                if (PropertyChanged != null)


                    PropertyChanged(this, new PropertyChangedEventArgs(“Posicao”));


            }


        }


 


        #region INotifyPropertyChanged Members


 


        public event PropertyChangedEventHandler PropertyChanged;


 


        #endregion


    }


 


    public partial class MainPage : UserControl


    {


        public MainPage()


        {


            InitializeComponent();


        }


    }


}


 


XAML:


<UserControl x:Class=”SL2Binding.MainPage”


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


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


             xmlns:local=”clr-namespace:SL2Binding”


             Width=”400″ Height=”300″>


    <UserControl.Resources>


        <local:Binder x:Key=”binder” />


    </UserControl.Resources>


    <Grid x:Name=”LayoutRoot” Background=”White”>


        <StackPanel Orientation=”Horizontal”>


            <Slider Width=”150″ Margin=”5″ Value=”{Binding Source={StaticResource binder}, Path=Posicao, Mode=TwoWay}”/>


            <TextBlock VerticalAlignment=”Center”  Margin=”5″ Text=”{Binding Source={StaticResource binder}, Path=Posicao, Mode=TwoWay}”/>


        </StackPanel>


    </Grid>


</UserControl>


 


Embora isto funcione, é um pouco complicado: precisamos criar uma classe de ligação que implementa a interface INotifyPropertyChanged, declará-la no XAML e fazer data binding dos dois elementos com ela.  Com a introdução do Element Binding no Silverlight 3, as coisas ficam muito mais fáceis: não precisamos implementar classes no código e o XAML fica muito mais simples:


<UserControl x:Class=”SL2Binding.MainPage”


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


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


             Width=”400″ Height=”300″>


    <Grid x:Name=”LayoutRoot” Background=”White”>


        <StackPanel Orientation=”Horizontal”>


            <Slider x:Name=”slider” Width=”150″ Margin=”5″ />


            <TextBlock x:Name=”textBlock” VerticalAlignment=”Center”  Margin=”5″ Text=”{Binding ElementName=slider, Path=Value, Mode=OneWay}”/>


        </StackPanel>


    </Grid>


</UserControl>


 


Precisamos apenas de um binding do texto do TextBlock com o slider e temos exatamente o mesmo comportamento do código anterior.


Simultaneamente à introdução do Element Binding, o Silverlight 3 também trouxe, entre outras coisas, uma simulação de 3D. Não é um 3D real, mas é muito simples de usar e deve satisfazer as necessidades de grande parte dos usuários: o Silverlight 3 permite criar a projeção de um plano girá-la nos eixos X, Y ou Z. Por exemplo. Se tivermos uma janela como esta:


<Grid x:Name=”rotateGrid” Margin=”10″ Background=”LightGray” >


    <Grid.RowDefinitions>


        <RowDefinition Height=”30″ />


        <RowDefinition Height=”30″ />


        <RowDefinition Height=”30″ />


        <RowDefinition Height=”30″ />


        <RowDefinition Height=”*” />


    </Grid.RowDefinitions>


    <Grid.ColumnDefinitions>


        <ColumnDefinition Width=”*” />


        <ColumnDefinition Width=”2*” />


    </Grid.ColumnDefinitions>


    <TextBlock Text=”Nome” Grid.Row=”0″ Margin=”5″/>


    <TextBlock Text=”Endereço” Grid.Row=”1″ Margin=”5″/>


    <TextBlock Text=”Cidade” Grid.Row=”2″ Margin=”5″/>


    <TextBlock Text=”Estado” Grid.Row=”3″ Margin=”5″/>


    <TextBox Grid.Row=”0″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


    <TextBox Grid.Row=”1″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


    <TextBox Grid.Row=”2″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


    <TextBox Grid.Row=”3″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


    <StackPanel Orientation=”Horizontal” Grid.Row=”4″ Grid.Column=”1″ Margin=”5″


                HorizontalAlignment=”Center” VerticalAlignment=”Top”>


        <Button Content=”Ok” Height=”27″ Width=”75″ Margin=”5″/>


        <Button Content=”Cancelar” Height=”27″ Width=”75″ Margin=”5″/>


    </StackPanel>


</Grid>


 


Podemos girá-la usando o seguinte markup:


<Grid.Projection>


    <PlaneProjection RotationY=”30″/>


</Grid.Projection>


 


Estamos aqui indicando que queremos girar a grid em 30º ao redor do eixo Y. Ao executarmos o programa, temos a seguinte figura:


 Figura 1



Note que, embora a figura esteja girada, ela é perfeitamente funcional. Da mesma maneira que giramos em torno do eixo Y, podemos ainda girar o plano em torno dos eixos X e Z. Os eixos estão dispostos como na figura abaixo:



 Figura 2


Agora, podemos juntar as duas partes (Element Binding e 3D) fazer o painel girar na horizontal (rotação no eixo Y) com o uso de um slider, sem precisar usar código. Para isso, usamos o seguinte XAML:


<UserControl x:Class=”SL3Plane.MainPage”


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


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


    Width=”400″ Height=”300″>


    <Grid x:Name=”LayoutRoot” Background=”White”>


        <Grid.RowDefinitions>


            <RowDefinition Height=”*” />


            <RowDefinition Height=”30″ />


        </Grid.RowDefinitions>


        <Grid x:Name=”rotateGrid” Margin=”10″ Background=”LightGray” >


            <Grid.Projection>


                <PlaneProjection x:Name=”Projecao” />


            </Grid.Projection>


            <Grid.RowDefinitions>


                <RowDefinition Height=”30″ />


                <RowDefinition Height=”30″ />


                <RowDefinition Height=”30″ />


                <RowDefinition Height=”30″ />


                <RowDefinition Height=”*” />


            </Grid.RowDefinitions>


            <Grid.ColumnDefinitions>


                <ColumnDefinition Width=”*” />


                <ColumnDefinition Width=”2*” />


            </Grid.ColumnDefinitions>


            <TextBlock Text=”Nome” Grid.Row=”0″ Margin=”5″/>


            <TextBlock Text=”Endereço” Grid.Row=”1″ Margin=”5″/>


            <TextBlock Text=”Cidade” Grid.Row=”2″ Margin=”5″/>


            <TextBlock Text=”Estado” Grid.Row=”3″ Margin=”5″/>


            <TextBox Grid.Row=”0″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


            <TextBox Grid.Row=”1″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


            <TextBox Grid.Row=”2″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


            <TextBox Grid.Row=”3″ Grid.Column=”1″ HorizontalAlignment=”Stretch” Margin=”5″ />


            <StackPanel Orientation=”Horizontal” Grid.Row=”4″ Grid.Column=”1″ Margin=”5″


                        HorizontalAlignment=”Center” VerticalAlignment=”Top”>


                <Button Content=”Ok” Height=”27″ Width=”75″ Margin=”5″/>


                <Button Content=”Cancelar” Height=”27″ Width=”75″ Margin=”5″/>


            </StackPanel>


        </Grid>


        <Slider Grid.Row=”1″ Width=”150″ Minimum=”0″ Maximum=”180″


           Value=”{Binding ElementName=Projecao, Path=RotationY,


                     Mode=TwoWay}” />


    </Grid>


</UserControl>


 


Demos um nome à projeção para poder fazer Binding com ela e colocamos um slider na página, para poder girar o plano. Ao executarmos o projeto, vemos que o slider gira o plano sem que haja a necessidade de escrever código. Porém, ao girar mais de 90º vemos um efeito indesejado: o 3D do Silverlight é apenas uma simulação e estamos vendo a frente do painel, invertida:



Figura3


Mesmo assim, a tela continua funcional, podemos digitar nas caixas de texto normalmente. Com quase toda certeza, não é este efeito que você está procurando, e devemos dar um jeito nisso.  Para simular o efeito 3D devemos ter dois painéis, um para a frente e outro para o fundo. Criamos então o painel do fundo e deixamos com visibilidade Collapsed, para que não seja mostrado:


<Grid x:Name=”gridFundo” Background=”Aquamarine” Visibility=”Collapsed”


      RenderTransformOrigin=”0.5,0.5″>


    <TextBlock Text=”Verso do painel” FontFamily=”Tahoma”


               FontSize=”24″


               HorizontalAlignment=”Center” VerticalAlignment=”Center”


               RenderTransformOrigin=”0.5,0.5″>


        <TextBlock.RenderTransform>


            <RotateTransform Angle=”45″ />


        </TextBlock.RenderTransform>


    </TextBlock>


</Grid>


 


Este painel contém apenas um TextBlock para exemplificar, mas poderíamos colocar aí qualquer componente (um exemplo seria simular uma ficha, mostrando a frente e o verso dos dados). Para fazer a troca dos painéis devemos usar code behind, ativado pelo evento ValueChanged do slider:


private double anguloAnt;


 


private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)


{


    double anguloAtu = (sender as Slider).Value;


 


    if ((anguloAnt < 90 && anguloAtu >= 90 ) ||


        (anguloAnt > 90 && anguloAtu <= 90 ))


    {


        MostraGrids(anguloAtu);


    }


    anguloAnt = anguloAtu;


}


 


private void MostraGrids(double angulo)


{


    if (angulo < 90)


    {


        gridFrente.Visibility = Visibility.Visible;


        gridFundo.Visibility = Visibility.Collapsed;


    }


    else


    {


        gridFrente.Visibility = Visibility.Collapsed;


        gridFundo.Visibility = Visibility.Visible;


    }


}


 


Temos uma variável para guardar o ângulo atual. Quando o ângulo atual passa de 90º e o anterior é menor que 90º ou vice versa, mostramos uma grid e escondemos a outra. Temos que fazer um pequeno truque no painel de fundo:  quando estamos girando em torno do eixo Y (rotação na horizontal), o painel do fundo fica invertido. Podemos solucionar isso aplicando uma transformação que inverte o painel:


<Grid x:Name=”gridFundo” Background=”Aquamarine” Visibility=”Collapsed”


      RenderTransformOrigin=”0.5,0.5″>


    <Grid.RenderTransform>


        <ScaleTransform x:Name=”gridTransform” ScaleX=”-1″/>


    </Grid.RenderTransform>


    <TextBlock Text=”Verso do painel” FontFamily=”Tahoma” FontSize=”24″


               HorizontalAlignment=”Center” VerticalAlignment=”Center”


               RenderTransformOrigin=”0.5,0.5″>


        <TextBlock.RenderTransform>


            <RotateTransform Angle=”45″ />


        </TextBlock.RenderTransform>


    </TextBlock>


</Grid>


 


Desta maneira, mostramos o painel da frente e do verso usando os novos recursos de 3D e element binding do Silverlight 3.


Figura 4


Criando uma aplicação LOB com Silverlight e WCF


Meu artigo sobre criação de aplicativos LOB (Line of Business) com Silverlight foi publicado na revista .net Magazine número 60 (aliás, ele é o artigo de capa). Neste artigo, mostro como criar uma aplicação LOB usando o Silverlight e WCF.


Lá eu mostro como criar um serviço WCF que acessa os dados de um banco de dados usando Linq to SQL e um programa Silverlight que acessa este serviço. A aplicação mostra como pesquisar, incluir,  editar ou excluir os dados. Além disso, mostro como fazer a mudança entre as páginas de uma aplicação Silverlight, mostrando a lista numa página e os detalhes em outra.


Enfim, se você quer saber como criar uma aplicação comercial usando Silverlight, vale a pena dar uma conferida no artigo.

Acessando dados com Silverlight

Uma das críticas mais comuns ao Silverlight é o fato que, embora a plataforma seja muito ampla e traga muitas facilidades para a criação de interfaces ricas para a Web, com o uso de videos, animações, controles, ele é apenas uma “carinha bonita, sem conteúdo”.


Nada está mais longe da verdade que esta afirmação: o Silverlight é, na realidade uma plataforma completa, com acesso à rede, acesso a dados, podendo inclusive usar LINQ para acessar os dados. Como os programas rodam no browser, o acesso à máquina cliente é muito restrito, mas isto não quer dizer que não há a possibilidade de acessar dados externos: há sim, e as possibilidades são inúmeras: podemos acessar dados de um servidor através de um WebService, acessar serviços REST ou mesmo consumir feeds RSS, apresentando os resultados numa interface rica, semelhante à de uma aplicação Desktop utilizando WPF.


O livro Data-Driven Services with Silverlight 2 vem suprir a falta de referências que mostram o acesso a dados com Silverlight: enquanto a maior parte dos livros sobre Silverlight ensinam a criar programas com a nova tecnologia, mostrando a criação da interface visual, este livro passa superficialmente sobre a interface, concentrando-se no acesso a dados.


O primeiro capítulo mostra uma introdução aos novos recursos do Silverlight, como o LINQ ou as alterações na linguagem introduzidas com o C# 3.0. A partir do capítulo 2 é que realmente começa o livro: os capítulos 2, 3 e 4 dão uma visão bastante completa da ligação de dados (Data binding), indispensável para conectar o dado vindo de um serviço à interface. Em seguida, o livro entra no acesso a dados propriamente dito: o capítulo 5 é uma introdução a WCF e WebServices, mostrando a criação de serviços com WCF ou AsmX. Este capítulo mostra ainda como fazer chamadas “Crossdomain”, que acessam serviços fora do domínio onde está situada a aplicação Silverlight: não há restrições para acesso a um serviço situado no mesmo domínio da aplicação Silverlight, mas o acesso a outros domínios é restrito e deve ser resolvido: muitas vezes, criamos um programa Silverlight e não conseguimos acessar os dados, devido a esta restrição. Aqui é mostrado como solucionar o problema de acesso entre domínios e como é possível debugar as requisições ao servidor.


O capítulo 6 mostra como serializar entidades usando o WCF. Usando o LINQ to SQL ou o LINQ to Entities, obtemos classes para acesso aos dados, mas estas estão restritas ao servidor. Este capítulo mostra como podemos serializar as entidades com o WCF e acessá-las no programa Silverlight, consumindo-as usando o LINQ to Objects.


Os capítulos 7, 8 e 9 falam sobre criação e consumo de serviços REST. Os serviços REST utilizam comandos HTTP (PUT, GET, DELETE, POST), podendo passar parâmetros para o serviço pela URL, o que facilita muito o uso do serviço, inclusive usando o browser, sem nenhum programa cliente específico. O capítulo 7 mostra como consumir serviços REST usando o WebClient e o HTTPWebRequest, inclusive usando múltiplas threads para obter os dados. O capítulo 8 mostra como consumir o serviço de acesso à Amazon, pesquisando livros na livraria virtual. Com a base deste capítulo, você pode inclusive estender a aplicação, criando um carrinho de compras no seu programa Silverlight. O capítulo 9 mostra a criação de um serviço REST e o assesso ao Twitter, criando um programa que permite acessar o serviço e postar mensagens, usando JSON ou mesmo XML para transferir os dados.


O capítulo 10 mostra o acesso a RSS feeds, usando a API de Syndication. Embora esta não esteja diretamente relacionada com o Silverlight, pois está disponível também no .net Framework completo, não vemos muitas referências a ela. Aqui temos uma visão clara de como usar esta API para acessar os dados de um RSS e apresentá-los em nossa aplicação. O último capítulo mostra o acesso a dados com o ADO.NET Data Services que, associado ao Entity Framework, facilita muito o acesso aos dados remotos.


Em resumo, este não é um livro para aprender Silverlight, há muitos bons livros para aprender esta tecnologia. Mas, se você já conhece Silverlight e quer saber como criar programas LOB, que não sejam apenas uma “carinha bonita”, deve ter este livro em sua estante.