Arquivo da tag: silverlight

Entendendo os Panels: Um Exemplo

Este é uma série de artigos em quatro partes. Leia o que foi escrito sobre Canvas, Stack Panel e sobre Grid.

Vamos ver um exemplo de um layout mesclando todos os painéis nativos que vimos até agora?

<Grid x:Name=”LayoutRoot” Background=”AliceBlue” Height=”600″ Width=”600″>        
    <Grid.RowDefinitions>
<RowDefinition Height=”100″ />
        <RowDefinition Height=”auto”/>
        <RowDefinition />
</Grid.RowDefinitions>


<Canvas Grid.Row=”0″>
        <TextBlock Canvas.Top=”20″ Canvas.Left=”20″ Text=”Logo” 
                   FontWeight=”Bold” FontSize=”40″ />
        <Border Canvas.Top=”20″ Canvas.Left=”250″ 
                Background=”Yellow” Height=”60″ Width=”300″>
            <TextBlock Text=”Banner” HorizontalAlignment=”Center” 
                       VerticalAlignment=”Center” />
        </Border>                
    </Canvas>


<StackPanel Orientation=”Horizontal” Grid.Row=”1″ Background=”Black”>
        <TextBlock Margin=”20″ Foreground=”White” 
                   Text=”File” FontSize=”20″ />
        <TextBlock Margin=”20″ Foreground=”White”
                   Text=”|” FontSize=”20″ />
        <TextBlock Margin=”20″ Foreground=”White” 
                   Text=”Editar” FontSize=”20″ />
        <TextBlock Margin=”20″ Foreground=”White” 
                   Text=”|” FontSize=”20″ />
        <TextBlock Margin=”20″ Foreground=”White” 
                   Text=”View” FontSize=”20″ />
        <TextBlock Margin=”20″ Foreground=”White” 
   
                Text=”|” FontSize=”20″ />
        <TextBlock Margin=”20″ Foreground=”White” 
                   Text=”Projeto” FontSize=”20″ />
    </StackPanel>

    <Grid Grid.Row=”2″>
        <Grid.ColumnDefinitions>
<ColumnDefinition Width=”3*” />
            <ColumnDefinition />
</Grid.ColumnDefinitions>

        <TextBlock Margin=”10″ Grid.Column=”0″ TextWrapping=”Wrap”>
            <Run FontSize=”30″ Foreground=”Blue” 
                 FontWeight=”Black”>Título do Post</Run>
<LineBreak />
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 

            Maecenas porttitor congue massa. Fusce posuere, magna sed 
            pulvinar ultricies, purus lectus malesuada libero, sit amet 
            commodo magna eros quis urna. Nunc viverra imperdiet enim. 
            Fusce est. Vivamus a tellus. Pellentesque habitant morbi 
            tristique senectus et netus et malesuada fames ac turpis 
            egestas. Proin pharetra nonummy pede. Mauris et orci. 
            Aenean nec lorem.
            <LineBreak />
<LineBreak />
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 

            Maecenas porttitor congue massa. Fusce posuere, magna sed 
            pulvinar ultricies, purus lectus malesuada libero, sit amet 
            commodo magna eros quis urna. Nunc viverra imperdiet enim. 
            Fusce est. Vivamus a tellus. Pellentesque habitant morbi 
            tristique senectus et netus et malesuada fames ac turpis 
            egestas. Proin pharetra nonummy pede. Mauris et orci. 
            Aenean nec lorem.
            <LineBreak />
<LineBreak />
<Run FontSize=”20″ Foreground=”Blue”>Sub-seção</Run>
<LineBreak />
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 

            Maecenas porttitor congue massa. Fusce posuere, magna sed 
            pulvinar ultricies, purus lectus malesuada libero, sit amet 
            commodo magna eros quis urna. Nunc viverra imperdiet enim. 
            Fusce est. Vivamus a tellus. Pellentesque habitant morbi 
            tristique senectus et netus et malesuada fames ac turpis 
            egestas. Proin pharetra nonummy pede. Mauris et orci. 
            Aenean nec lorem.
        </TextBlock>

        <StackPanel Grid.Column=”1″ Background=”Gray”  >
            <TextBlock Margin=”10 0 0 0″ Text=”Veja mais em” 
                       FontSize=”16″ FontWeight=”Bold” Foreground=”White” />
            <TextBlock Margin=”10 0 0 0″ 
                       Text=”blah blah blah” Foreground=”White” />
            <TextBlock Margin=”10 0 0 0″ 
                       Text=”blah blah blah” Foreground=”White” />
            <TextBlock Margin=”10 0 0 0″ 
      
                 Text=”blah blah blah” Foreground=”White” />
            <TextBlock Margin=”10 0 0 0″ 
                       Text=”blah blah blah” Foreground=”White” />
            <TextBlock Margin=”10 0 0 0″ 
                       Text=”blah blah blah” Foreground=”White” />
            <TextBlock Margin=”10 0 0 0″ 
                       Text=”blah blah blah” Foreground=”White” />
        </StackPanel>
</Grid>        
</Grid>

Este é o resultado:

Conclusão

Com Silverlight tudo é mais fácil e organizado. Utilize-o no seu dia-a-dia e verá que a curva de aprendizado é pequena para realizar coisas poderosas. Fora que seu aprendizado valerá não só para aplicações web, mas também para aplicações Out-Of-Browser e aplicações para Windows Phone 7 – a qual todos os conceitos podem ser aplicados.

Espero que vocês tenham gostado da série de artigos a respeito dos Panels.

Até a próxima!

Etiquetado ,

Entendendo os Panels: Grid

Este é uma série de artigos em quatro partes. Leia o que foi escrito sobre Canvas e sobre Stack Panel.

O Grid, provavelmente, vai ser a sua escolha para montar o layout em 90% das vezes. Ele, por exemplo, é o painel definido como LayoutRoot para qualquer página ou User Control por padrão.

Ele funciona de forma muito semelhante ao elemento table do HTML. Você cria uma série de linhas e colunas e insere os objetos nela. Entretanto aqui a coisa é feita de forma mais organizada. Ao invés de sair colocando o conteúdo dentro de TRs
eTDs, você define antes as colunas e as linhas e através de Attached Properties você diz a qual linha/coluna o objeto deve ser exibido.

Vamos analisar através de um exemplo? Para isto vamos montar uma layout com quatro linhas e três colunas:

<Grid x:Name=”LayoutRoot” Background=”AliceBlue” Width=”500″ Height=”500″>   
    <Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

    <TextBlock Grid.Column=”0″ Grid.Row=”0″ Grid.ColumnSpan=”3″ 
                Text=”Título da aplicação” HorizontalAlignment=”Center” />

    <Button Grid.Column=”0″ Grid.Row=”1″ Height=”50″ Width=”50″ Content=”1″/>
    <Button Grid.Column=”1″ Grid.Row=”1″ Height=”50″ Width=”50″ Content=”2″/>
    <Button Grid.Column=”2″ Grid.Row=”1″ Height=”50″ Width=”50″ Content=”3″/>        
    <Button Grid.Column=”0″ Grid.Row=”2″ Height=”50″ Width=”50″ Content=”4″/>
    <Button Grid.Column=”1″ Grid.Row=”2″ Height=”50″ Width=”50″ Content=”5″/>
    <Button Grid.Column=”2″ Grid.Row=”2″ Height=”50″ Width=”50″ Content=”6″/>
    <Button Grid.Column=”0″ Grid.Row=”3″ Height=”50″ Width=”50″ Content=”7″/>
    <Button Grid.Column=”1″ Grid.Row=”3″ Height=”50″ Width=”50″ Content=”8″/>
    <Button Grid.Column=”2″ Grid.Row=”3″ Height=”50″ Width=”50″ Content=”9″/ 
</Grid>

O resultado é o seguinte:

Vamos ao que acontece:

Observe que nós declaramos a propriedade <Grid.RowDefinitions>
e dentro dela colocamos quatro <RowDefinition/>. Isto significa que a Grid terá quatro linhas. Do mesmo modo definimos as colunas com apenas três.

Nas linhas abaixo nós configuramos as Attached Properties
Grid.Row e Grid.Column. Se nós não atribuirmos este valor, o Silverlight irá considerar 0 para a propriedade que deixamos de configurar.

Outro ponto interessante é que no TextBlock nós configuramos uma Attached Property chamada Grid.ColumnSpan, que é semelhante também o span do Html. Neste caso nós definimos um span de 3 colunas, logo o Silverlight faz merge da primeira linha inteira para o título.

Observe também que os 500 pixels utilizados tanto para a largura como para a altura do Grid (Width e Height) são distribuídos exatamente da mesma forma entre as células. Isto por que não definimos nenhum valor para largura e altura para as células. Logo, é atribuído um valor padrão conhecido como * (asterisco), que faz a divisão por igual.

Mas vamos alterar isto para entendermos melhor o funcionamento.

Altere as Grid.RowDefinitions de:

<Grid.RowDefinitions>


<RowDefinition/>


<RowDefinition />


<RowDefinition />


<RowDefinition />

</Grid.RowDefinitions>

para

<Grid.RowDefinitions>


<RowDefinition Height=”auto” />


<RowDefinition />


<RowDefinition />


<RowDefinition />

</Grid.RowDefinitions>

A propriedade Height configurada como “auto” fará com que a linha a altura necessária para exibir todos os objetos que fazem parte dela. Logo, teremos o seguinte resultado:

Observe que, além da altura da primeira linha ter sido redimensionado apenas para caber os seus objetos, as outras três linhas tiveram o seu conteúdo divido por igual entre elas.

Vamos alterar mais uma propriedade da Grid.RowsDefinitions:

<Grid.RowDefinitions>
<RowDefinition Height=”auto” />
    <RowDefinition />
<RowDefinition Height=”3*” />
    <RowDefinition />
</Grid.RowDefinitions>

A quarta linha pega a altura que havia sido atribuída para si e multiplica por três, diminuindo a altura das demais linhas.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Outro recurso interessante é o GridSplitter, que permite ao usuário redimensionar as colunas e ou linhas de uma forma bem bacana. O GridSplitter é um controle estendido que faz parte do componente System.Windows.Controls. Um bom atalho é abrir a ToolBox e traze-lo para o seu XAML (automaticamente ele importará o namespace – que ficará algo como xmlns:sdk=”http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk&#8221;).

Vamos montar um outro layout apenas para ver na prática o funcionamento deste objeto:

 <Grid x:Name="LayoutRoot" Background="AliceBlue"
       Width="500" Height="500" ShowGridLines="True">
            <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="auto" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <sdk:GridSplitter Grid.Column="1" Grid.RowSpan="3"
                       HorizontalAlignment="Center" />
        <Button Width="50" Height="50" Grid.Column="0" Grid.Row="0" Content="1"/>
    <Button Width="50" Height="50" Grid.Column="2" Grid.Row="0" Content="2"/>
    <Button Width="50" Height="50" Grid.Column="0" Grid.Row="1" Content="3"/>
    <Button Width="50" Height="50" Grid.Column="2" Grid.Row="1" Content="4"/>
    <Button Width="50" Height="50" Grid.Column="0" Grid.Row="2" Content="5"/>
    <Button Width="50" Height="50" Grid.Column="2" Grid.Row="2" Content="6"/>
</Grid> 

Veja que será adicionado um controle que permite que o usuário possa aumentar o diminuir a largura de uma coluna. De maneira semelhante, ele pode criar um GridSplitter para aumentar ou diminuir a altura das linhas.

No próximo artigo iremos ver como todos estes painéis trabalham em conjunto. Não percam a apresentação da sinfonia de Painéis!

Até lá!

Etiquetado , ,

Entendendo os Panels: Stack Panel

Este é uma série de artigos em quatro partes. Clique aqui para ler o artigo anterior (Canvas).

O Stack Panel, como diz o nome, é um painel em formato de pilha. Ou seja, você consegue enfileirar uma pilha de objetos dentro deles. A ideia é facilitar o desenho daqueles objetos que são construídos num formato de fila, como um menu vertical ou horizontal.

Inclusive existe uma propriedade chamada Orientation que define justamente isto: se os objetos serão alinhados na vertical (valor padrão) ou na horizontal.

Este painel foi desenhado com a intenção de organizar poucos objetos, ou seja, a ideia não é utilizar estes painéis para desenhar um layout inteiro, mas parte deles. De fato, ele convive bem com outros painéis como o Canvas e o Grid.

Vamos ver um exemplo simples:

<StackPanel>
    <Button Margin="3" Height="50" Width="50" Content="Arquivo" />
    <Button Margin="3" Height="50" Width="50" Content="Editar" />
    <Button Margin="3" Height="50" Width="50" Content="Visualizar" />        
</StackPanel> 

Resultado:

Agora vamos ver na vertical como fica:

<StackPanel Orientation="Horizontal">
    <Button Margin="3" Height="50" Width="50" Content="Arquivo" />
    <Button Margin="3" Height="50" Width="50" Content="Editar" />
    <Button Margin="3" Height="50" Width="50" Content="Visualizar" />
</StackPanel> 

Resultado:

No próximo artigo iremos ver o último e talvez mais importante painel: a Grid.

Etiquetado , , ,

Entendendo os Panels: Canvas

Para você criar um layout qualquer dentro do Silverlight deverá, obrigatoriamente, arranjar os seus objetos dentro de um ou mais painéis (Panels). Os painéis funcionam como uma espécie de container para hospedar os seus objetos, sendo que os mesmos disponibilizam propriedades que permitem você posicionar os seus objetos da maneira como achar mais conveniente.

Inclusive você pode criar os seus painéis customizados e utilizá-los sozinhos ou em combinação com outros já existentes, porém vamos falar agora dos painéis que vem disponível com o Silverlight: o Canvas, o StackPanel e a Grid.

O Canvas é um painel que deixa você movimentar seus objetos livremente dentro dele. O nome do objeto, inclusive, é inspirado pela possibilidade você ter uma folha em branco e um lápis – ou seja, tem total liberdade para fazer o que bem desejar.

Para isto o Canvas disponibiliza algumas Attached Properties para seus objetos:

  • Canvas.Top: o padrão é 0, ou seja o desenho como no pixel 0 de onde o Canvas é disponibilizado. A partir dai você pode adicionar pixels para posicionar o seu objeto de cima para baixo. Por exemplo, se um objeto estiver configurado como Canvas.Top=”10″ o Silverlight calculará 10 pixels para baixo e então renderizará o seu objeto.
  • Canvas.Left: muito parecido com o Canvas.Top, só que ao invés de calcular de cima para baixo, o Silverlight calcula da esquerda para a direita. Ou seja, um objeto configurado como Canvas.Left=”10″ fará com que o Silverlight contem 10 pixels e somente a partir disto ele renderiza o seu objeto.
  • Canvas.ZIndex: esta propriedade configura a prioridade do objeto para exibição em relação aos demais. O padrão é 0. Como se trata de Canvas, você pode posicionar objetos do modo que eles se entrelacem ou mesmo que sobrepõem um ao outro – deste modo você configurar esta propriedade para definir qual o objeto deve aparecer por cima dos demais. Caso esta propriedade não seja configurada, sempre o objeto declarado por último aparecerá por cima de seu antecessor.

Importante salientar que em termos de performance, o Canvas é o que obtém o melhor resultado, visto que os pixels estão declarado de forma explicita – ou seja, o Silverlight não precisará de muito esforço para calcular onde os objetos devem aparecer na tela. Entretanto isto só é significativo numa tela que possui muitos elementos visuais (muitos mesmo), o que dificilmente ocorrerá na prática.

Vamos há alguns exemplos?

<Canvas>
<Rectangle Height=”150″ Width=”150″ Fill=”Blue” />
    <Rectangle Height=”150″ Width=”150″ Fill=”Yellow” />
    <Rectangle Height=”150″ Width=”150″ Fill=”Green” />
</Canvas>

Temos três retângulos idênticos declarados dentro deste layout, com a diferença da coloração interna. O primeiro é azul, o segundo é amarelo e o terceiro é verde. Como isto será exibido? A resposta é um retângulo verde, nada mais.

Isto por que como ele vem por último, ele acaba sobrepondo o amarelo, que por acaba sobrepor o azul.

Agora, vamos mudar o nosso exemplo e repetir a pergunta:

<Canvas>
    <Rectangle Height="150" Width="150" Fill="Blue" />
    <Rectangle Height="150" Width="150" Fill="Yellow" Canvas.ZIndex="1" />
    <Rectangle Height="150" Width="150" Fill="Green" />
</Canvas> 

Respondeu corretamente quem diz que o que aparecerá agora será um retângulo amarelo, visto que o ZIndex dos demais, por padrão, é 0! Logo, quem tem o maior ZIndex é o retângulo amarelo.

Agora vamos mexer um pouco no posicionamento dos objetos.

<Canvas>
    <Rectangle Height="150" Width="150" Fill="Blue"
                Canvas.ZIndex="1" />
    <Rectangle Height="150" Width="150" Fill="Yellow"
                Canvas.ZIndex="2"
                Canvas.Left="50"
                Canvas.Top="100" />
    <Rectangle Height="150" Width="150" Fill="Green"
                Canvas.Left="100"
                Canvas.Top="25" />
</Canvas> 

O resultado é o seguinte:

Veja só que interessante: o retângulo amarelo (ZIndex=”2″) tem prioridade sobre o azul (ZIndex=”1″) que tem prioridade sobre o verde (ZIndex=”0″).

No próximo artigo iremos ver sobre o Stack Panel.

Até lá!

Etiquetado , ,

Drag-and-Drop Através de AllowDrop

Uma das propriedades mais incríveis que foram introduzidas no Silverlight foi a propriedade AllowDrop. A mesma permite que você adicione suporte a Drag-and-Drop em seus controles. Para quem não sabe, Drag-and-Drop é a possibilidade de você pegar algum arquivo do seu computador e arrastar para dentro de outro local. Por exemplo, você pode ir no seu computador, selecionar um arquivo XML e arrastar para o Visual Studio que prontamente ele abrirá o seu arquivo.

Com Drag-And-Drop no Silverlight, você consegue fazer upload de arquivos ou mesmo exibir fotos e vídeos que estão em seu computador sob demanda. Imagine que você monte uma aplicação que leia um vídeo de sua máquina e que guarde o mesmo num drive nas nuvens (como o SkyDrive). Através da propriedade AllowDrop isto é facilmente realizável.

Por ser parte da classe UIElement isto significa que TODOS os controles visuais nativos (controls/user controls) herdam esta propriedade, assim como os eventos que controlam esta feature, que são os seguintes:

DragEnter: Ocorre no exato momento que o arquivo que está sendo arrastado alcança a fronteira onde ele pode ser solto para que o evento Drop seja acionado.

DragLeave: Ocorre quando você deixa a área onde o arquivo poderia ser solto para acionar o evento Drop.

DragOver: Ocorre enquanto você está dentro da área onde o arquivo pode ser solto.

Drop: Ocorre no momento que você solta o arquivo dentro da área do objeto a qual você habilitou o AllowDrop. Este é, certamente, o evento mais importante, visto que é aqui que fazemos a manipulação dos arquivos.

Não há mais o que dizer, o negócio é simples mesmo! Vamos ver um exemplo na prática!

<Grid x:Name=”LayoutRoot” Background=”AliceBlue” Height=”600″ Width=”600″>
    <Grid.RowDefinitions>
<RowDefinition Height=”100″ />
        <RowDefinition />
</Grid.RowDefinitions>


<TextBlock x:Name=”TituloTextBlock” 
                Text=”Arraste o seu arquivo aqui” 

                FontSize=”20″ AllowDrop=”True” 
                DragLeave=”NomeArquivoStackPanel_DragLeave” 

                DragOver=”NomeArquivoStackPanel_DragOver” 
                Drop=”NomeArquivoStackPanel_Drop”/>
        
    <TextBox x:Name=”ConteudoArquivoTextBox” Grid.Row=”1″ 
                AcceptsReturn=”True” VerticalScrollBarVisibility=”Auto” 
                HorizontalScrollBarVisibility=”Auto” />                      
</Grid>

Observe que nós habilitamos o AllowDrop no primeiro TextBlock, a qual está escrito “Arraste o seu arquivo aqui”. Também adicionamos, para efeitos ilustrativos, três eventos: um para o DragLeave, um para o DragOver e outro para o Drop.

O arquivo arrastado para dentro deste TextBlock irá ser exibido no TextBox logo abaixo. Vamos ver como isto é codificado?

private void NomeArquivoStackPanel_DragLeave( object sender, DragEventArgs e) {

    TituloTextBlock.Text = “Arraste o seu arquivo para o painél a esquerda”;

}

private void NomeArquivoStackPanel_DragOver( object sender, DragEventArgs e) {

    TituloTextBlock.Text = “Pode soltar o arquivo.”;

}

private void NomeArquivoStackPanel_Drop(object sender, DragEventArgs e) {

    TituloTextBlock.Text = “Exibição do arquivo.”;

    var sb = new StringBuilder();

        var conteudo = string.Empty;

 

 

        if (e.Data == null)

            return;

    var arquivos = e.Data.GetData(DataFormats.FileDrop) as FileInfo[];

    foreach (var fi in arquivos) {

        using (var sr = fi.OpenText()) {

            sb.Append(string.Concat(sr.ReadToEnd(), “\n”));

        }

    }

    ConteudoArquivoTextBox.Text = sb.ToString();

}

O que importa mesmo, neste nosso cenário, é o que ocorre no evento Drop. Nós declaramos um StringBuilder, obtemos os dados dos arquivos (caso você arraste mais de um) e, por fim, inserimos no TextBox destinado para este proposito!

Muito legal e muito simples, não? Agora você já sabe como criar aplicativos como o SkyDrive!

Etiquetado ,

Entendendo DependencyProperty

Olá pessoal! Hoje vamos ver um pouco sobre DependencyProperty, um recurso muito interessante de ser explorado pelas ferramentas da Microsoft que fornecem recursos para atribuição de propriedades nos seus controles visuais através de Binding – como WPF, Silverlight e WF.

Grosso modo, a função da DependencyProperty é prover o mesmo mecanismo de uma propriedade CLR comum, porém de forma visual e enriquecida com funcionalidades que são muito uteis. Dentro estas funcionalidades, temos desde atribuição de valor padrão, como validação em tempo real e notificação de alteração de valor.

Além disto, uma propriedade comum trabalha como um intermediário que configura (set) ou resgata (get) um membro privado da própria classe – que armazena estes valores. Já uma DependencyProperty varia o local onde seu valor será armazenado dependendo do estado atual. O modo como este local será definido é chamado de Value Precedence, que é uma espécie de polimorfismo de atribuição de valores – onde a precedência de maior nível tem sempre a prioridade para armazenar o valor. Vamos a um exemplo?

Dentro de uma xaml, observe a seguinte sintaxe:

<UserControl.Resources>
    <Style TargetType="TextBlock">
 <Setter Property="Foreground" Value="Blue" />
     </Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
 <TextBlock x:Name="NomeTextBlock" Foreground="Black">
    <TextBlock.Style>
      <Style TargetType="TextBlock">
        <Setter Property="Foreground" Value="Green" />
      </Style>
    </TextBlock.Style>
  </TextBlock>
</Grid> 

Qual será a cor do TextBlock? Será azul, preto ou verde?

Conforme a regra da precedência de valor, o nível mais alto tem prioridade sobre o mais baixo. Neste caso estamos falando no valor atribuído na declaração do objeto TextBlock, ou seja, a sua cor será preta (Local Value).

Mas e se arrancarmos esta propriedade, será que a cor ficará verde ou azul? Acertou quem respondeu que é verde – afinal na precedência, o estilo definido no próprio objeto é mais alto do que o definido fora do objeto.

Para saber qual é a ordem dos níveis precedências, basta seguir a seguinte tabela (ordenada do nível mais alto para o mais baixo):

  1. Por coerção e animação: Os dois operam em nível de Base Value. Durante uma animação, por razões óbvias, a sua precedência deve ser respeitada. Imagine se você tem uma animação que altera o Background de uma propriedade em um determinado período de tempo: se a animação não tivesse prioridade, o fundo não seria alterado, logo não haveria animação.
  2. Por Local Value
  3. Por Template: para propriedades criadas dentro de um template ou controle. Dentro deles também há uma ordem de precedência: a) por trigger (mesma razão da animação); b) por configuração direta de propriedade;
  4. Por estilos (Style Setters)
  5. Por temas
  6. Por herança
  7. Por valor padrão

Entendido este ponto, é importante frisar o seguinte: só é interessante utilizar DependencyProperty se você for fornecer uma propriedade pública para servir de alvo para o preenchimento através de Binding ou através de uma animação. Caso contrário, não há utilidade para sua utilização.

Como nestas tecnologias praticamente não há como escapar do Binding, seu entendimento é quase que essencial.

Mas vamos ver como isto funciona na prática. Crie um projeto do tipo Silverlight Application e adicione um Silverlight User Control chamado NomeCompletoControl.

No XAML, inclua um TextBlock da seguinte maneira:

<Grid x:Name=”LayoutRoot” Background=”White”>
    <TextBlock x:Name=”MeuTextBlock” FontSize=”20″ Foreground=”Blue” />
</Grid>

Vá agora no NomeCompletoControl.cs e adicione as seguintes propriedades:

public partial class NomeCompletoControl : UserControl {
        public NomeCompletoControl() {
         InitializeComponent();
          this.Loaded += (s, ea) => {
              this.MeuTextBlock.Text = String.Concat(Nome, " ", Sobrenome);
         };
     }
       private string  _nome = default(string),
         _sobrenome = default(string);
       public string Nome {
           get { return this._nome; }
           set { this._nome = value; }
      }
       public string Sobrenome {
           get { return this._sobrenome; }
           set { this._sobrenome = value; }
      }
 } 

A intenção é clara: queremos apenas um controle que concatene as informações de Nome e Sobrenome.

Vá no XAML da MainPage, abra a ToolBox e veja que o controle que acabamos de criar já está nela (se não estiver, basta dar um Build no projeto que ele irá aparecer). Arraste ele para o meio da Grid (automaticamente o Visual Studio adiciona o namespace no elemento raiz do XAML – chamado de UserControl neste contexto. Provavelmente o nome que ele criou para o namespace é “my”).

Depois configure as propriedades Nome e Sobrenome, de modo que seu documento deverá ficar mais ou menos assim:

<Grid x:Name="LayoutRoot" Background="White">
      <my:NomeCompletoControl Nome="José" Sobrenome="Saramago" />
</Grid> 

Se você executar o código, você terá sucesso (conforme o esperado).

Agora vamos passar os mesmos parâmetros como Binding do controle. Para isto vamos adicionar uma nova classe chamada “MeuRepositorio.cs” e vamos adicionar as seguintes propriedades:

public class MeuRepositorio {
       public string MeuNome { getset; }
       public string MeuSobrenome { getset; } 
} 

Agora vamos voltar o MainPage.xaml e alterar as propriedades do nosso controle, do modo que fique da seguinte maneira:

<Grid x:Name="LayoutRoot" Background="White">
    <my:NomeCompletoControl
         x:Name="MeuControle"
         Nome="{Binding MeuNome}"
         Sobrenome="{Binding MeuSobrenome}" /> 
</Grid> 

Agora vamos ao MainPage.xaml.cs (ou seja, no code behind) e vamos adicionar o seguinte:

public MainPage() {
     InitializeComponent();
     var repositorio = new MeuRepositorio {
          MeuNome = "José",
          MeuSobrenome = "Saramago" };
     this.MeuControle.DataContext = repositorio;
} 

Se você executar o código da forma como está irá ocorrer uma exceção. Isto por que nós estamos fazendo Data Binding, entretanto o nosso controle (NomeCompletoControl) não suporta Data Bound. É aí que entram as propriedades do tipo DependencyProperty. Vamos alterar o code behind de nosso controle. Para isto entre na classe NomeCompletoControl.xaml.cs e deixe do seguinte modo.

public partial class NomeCompletoControl : UserControl {
     public NomeCompletoControl() {
         InitializeComponent();
         this.Loaded += (s, ea) => {
             this.MeuTextBlock.Text = String.Concat(Nome, " ", Sobrenome);
         };
     }
     private static readonly DependencyProperty
        NomeProperty = DependencyProperty.Register(
             "Nome",
             typeof(string),
             typeof(NomeCompletoControl),
             null),
         SobrenomeProperty = DependencyProperty.Register(
             "Sobrenome",
             typeof(string),
             typeof(NomeCompletoControl),
             null);
     public string Nome {
         get { return this.GetValue(NomeProperty).ToString(); }
         set { this.SetValue(NomeProperty, value); }
     }
     public string Sobrenome {
         get { return this.GetValue(SobrenomeProperty).ToString(); }
         set { this.SetValue(SobrenomeProperty, value); }
     }
 } 

Execute novamente o código e veja que agora dá certo. Isto por que acabamos de adicionar suporte à Binding em nosso controle. A sintaxe parece um pouco complexa, mas não é nada do outro mundo. Vamos tentar esclarecer o que ocorreu.

Criamos duas propriedades do tipo DependencyProperty, uma chamada NomeProperty e outra chamada SobrenomeProperty. Para criar ambas as Dependency Properties nós não criamos uma nova instância do mesmo objeto – ao contrário, utilizamos o método estático Register da mesma classe. Assim podemos registrar a propriedade com alguns atributos: o nome da propriedade (Nome), o tipo da propriedade (string), o tipo proprietário da propriedade (no caso a própria classe) e o metadata da propriedade (aqui deixamos null).

Veja que as propriedades são declaradas de forma estática, logo o gerenciamento dos valores se dá internamente e somente uma instância do objeto é criada (diferente das propriedades CLR comuns). Logo é a propriedade framework que fará o gerenciamento dos valores – caso exista um valor padrão, o valor será o primeiro a ser armazenado, caso seja atribuído um novo valor o padrão será substituído por este e assim por diante.

Também criamos propriedades públicas que intermediam o acesso as Dependency Properties através do método GetValue e do método SetValue, que fazem parte da classe DependencyObject. Uma vez nossa classe herda de UserControl está tudo certo – uma vez que ela está lá dentro (sendo mais específico: UserControl herda de Control que herda de FrameworkElement que herda de UIElement que herda de DependencyObject!).

Quando em nossa MainPage.cs criamos uma nova instância de MeuRepositorio e definimos que o nosso UserControl receberia esta instância como fonte de dados (DataContext), indicamos ao Silverlight que as propriedades do UserControl seriam preenchidas por Binding (por isto havia dado erro quando você executou o código).

Lembra-se daquele quarto argumento da Dependency Properties que está nulo em nosso exemplo? Ele se refere ao PropertyMetada e tem duas funções bastante interessantes: atribuir um valor padrão para a propriedade (ou seja, enquanto nada for atribuído, este valor é o que passará a existir) e/ou um callback para quando houver alteração no valor da propriedade (útil em situações onde você precisa atribuir o valor alterado para outras propriedades da classe).

Vamos ver um exemplo tolo, mas que vale para ilustrar o funcionamento. Vamos alterar a dependency property do Nome deste modo:

private static readonly DependencyProperty
    NomeProperty = DependencyProperty.Register(
         "Nome",
         typeof(string),
         typeof(NomeCompletoControl),
         new PropertyMetadata("Nome"new PropertyChangedCallback((d, ea)=>{
             MessageBox.Show("Old Value: " + ea.OldValue.ToString());
             MessageBox.Show("New Value: " + ea.NewValue.ToString());
         }))); 

Veja que configuramos o valor padrão da propriedade para “Nome” e interceptamos o callback para exibir o valor antigo e o novo valor da propriedade.

Assim que executarmos o código, surgirá uma MessageBox escrito “Old Value: Nome”! Ao clicar em Ok abrirá uma nova MessageBox com “New Value: José”! Isto prova que havia um valor atribuído chamado “Nome” e que foi alterado depois para “José”, e quando isto aconteceu foi disparado o callback para notificar a alteração da propriedade.

Para finalizar, através de DependencyProperty você também pode registrar algo conhecido como Attached Property – que é uma propriedade que pode ser acessada pelos objetos filhos, ainda que os mesmos não os herdem. Sabe quando você utiliza uma Grid para posicionar os seus objetos? Se não sabe, veja abaixo (um simples layout com 3 linhas e 2 colunas):

<Grid x:Name=”LayoutRoot” Background=”White”>
    <Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

    <TextBlock 
Grid.Column=”0″ Grid.Row=”0″ Text=”Nome” />
    <TextBlock 
Grid.Column=”1″ Grid.Row=”0″ Text=”Sobrenome” />

    <TextBlock 
Grid.Column=”0″ Grid.Row=”1″ Text=”José” />
    <TextBlock 
Grid.Column=”1″ Grid.Row=”1″ Text=”Saramago” />

    <TextBlock 
Grid.Column=”0″ Grid.Row=”2″ Text=”Fiódor” />
    <TextBlock 
Grid.Column=”1″ Grid.Row=”2″ Text=”Dostoiévski” />

</Grid>

Estas propriedades em destaque (Grid.Column e Grid.Row) são Attached Properties do objeto Grid – ou seja, os objetos filhos conseguem configurá-las sem precisar criar uma nova instância do objeto e também ser herdá-las.

Caso você decida criar, por exemplo, uma Panel customizada, você pode valer deste recurso para saber como deverá organizar os seus objetos dentro da Panel.

A sintaxe é bem parecida, veja:

private static readonly DependencyProperty
TopPositionProperty = DependencyProperty.RegisterAttached(
        “TopPosition”,
        typeof(double),
        typeof(NomeCompletoControl),
        new PropertyMetadata(0d, new PropertyChangedCallback((d, ea)=>{
            MessageBox.Show(ea.NewValue.ToString());
})));

public static void SetTopPosition(UIElement element, double value) {
element.SetValue(TopPositionProperty, value);
}

public static double GetTopPosition(UIElement element) {
return (double)element.GetValue(TopPositionProperty);
}

Aí no nosso XAML podemos ter um código assim

<Grid x:Name=”LayoutRoot” Background=”White”>
    <my:NomeCompletoControl 
    x:Name=”MeuControle” 
    Nome=”{Binding MeuNome}” 
    Sobrenome=”{Binding MeuSobrenome}”>            
        <Button Content=”Blah” my:NomeCompletoControl.TopPosition=”5″ />     
    </my:NomeCompletoControl>
</Grid>

A principal diferença – além do método RegisterAttached – é a forma como a propriedade é configurada, através de dois métodos (um para set e um para get), cujo argumento UIElement é passado como argumento para que sirva como hospedeiro da Propriedade (algo também intuitivo e que faz todo sentido).

Importante salientar que os métodos seguem um padrão de nomenclatura: Set(nome da propriedade) e Get(nome da propriedade). Caso o nome seja diferente disto, como SetNomeQualquer, a coisa ficará um pouco estranha, visto que o XAML teria que ficar mais ou menos assim my:NomeCompletoControl.NomeQualquer=”5″.

Legal, não?

Espero o artigo tenha sido esclarecedor.

Dúvidas, críticas ou sugestões, aproveitem o espaço do blog e comentem!

Etiquetado , , , ,