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:
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:
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:
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.
Bruno, vendo este artigo não posso deixar de comentar, isso é fantástico. Parabéns pelo seu trabalho e obrigado por compartilhar informação.
Um abraço.
Atenciosamente,
André Baltieri
andre.baltieri@insidedotnet.com.br
http://www.insidedotnet.com.br/
Fico contente que gostou. Aguarde, quero postar mais sobre novidades do Silverlight.
Bruno, tem algum tutorial que você recomenda sobre StackPanels e alinhamento dos objetos na tela. estou tendo problemas com isto.
Abraços e obrigado
Dê uma olhada em um artigo que escrevi com menu filho para o MSDN: http://www.microsoft.com/brasil/msdn/Tecnologias/netframework/objetos.mspx
Bruno
Estou criando objetos em run-time e precisa aplicar um binding, você teria algum site onde possa ver como é feito esse codigo todo no code behind?
Dê uma olhada aqui: http://www.c-sharpcorner.com/UploadFile/dhananjaycoder/Runtimedatabinding04202009041801AM/Runtimedatabinding.aspx
Bruno