Desenvolvimento - Silverlight

Usando Timer no WPF e Silverlight

Quem procurar por um controle Timer na toolbox do WPF ou Silverlight, como de costume em aplicações Windows Forms ou VB6, não irá encontrar.

por Gustavo Malheiros



Quem procurar por um controle Timer na toolbox do WPF ou Silverlight, como de costume em aplicações Windows Forms ou VB6, não irá encontrar. O conceito de Timers é diferente, pois usa Multithreading, o que faz com que o uso seja muito cuidadoso. Se você tentar mudar uma propriedade de um objeto (elemento visual) da tela, vai receber um erro. Para evitar o trabalho tedioso de controlar as threads, você pode utilizar um tipo especial de Timer, chamado DispatcherTimer, que roda na Thread principal da aplicação, na interface do usuário. Assim você pode controlar objetos da tela de acordo com tempo configurado no Timer.

Como sempre, existem vantagens e desvantagens, porém a maior vantagem é o fato de rodar na thread principal. Um exemplo de cenário, seria a necessidade de periodicamente acessar um WebService para obter dados novos e atualizar uma grid ou gráfico na tela. Como desvantagem, pelo fato dele não usar Multithreading verdadeira, uma aplicação que precisa fazer pequenas tarefas em frações de segundo ou precisa ser mais responsiva com operações de alta latência, é aconselhável usar o System.Threading.Timer .

Vamos aqui fazer um pequeno exemplo de utilização:

Crie um projeto do tipo Silverlight Application no Visual Studio 2008.

Essa é a estrutura do projeto:

E este é nosso código XAML:

Aqui na MainPage.XAML foi criado um botão com uma ellipse que mudará de cor (vermelho ou verde), um TextBlock que mostra o estado da thread (Parado ou Processando) e um StackPanel onde será adicionado novos controles a cada segundo.

<UserControl x:Class="TimerSilverlight.MainPage"

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

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

xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

<Grid x:Name="LayoutRoot">

<Button Height="32" x:Name="btnIniciar" Width="126" Click="btnIniciar_Click">

<StackPanel Orientation="Horizontal">

<Ellipse Fill="Red" Height="24" HorizontalAlignment="Left" Name="Ellipse1" Stroke="Black" Width="25" />

<TextBlock Text="Parado" Height="28" HorizontalAlignment="Right" Name="lblStatus"/>

</StackPanel>

</Button>

<StackPanel Width="300" x:Name="stackP" />

</Grid>

</UserControl>

Vamos para o code behind da página (MainPage.xaml.vb)

O DispatcherTimer fica no Namespace System.Windows.Threading.DispatcherTimer e aqui fazemos a declaração do Timer(dt) e uma variável (_threadRun) para controlar o processo.

Dim dt As New System.Windows.Threading.DispatcherTimer

Private _threadRun As Boolean = False

No Load da página adicionamos um delegate para o método processar. Em seguida definimos o intervalo (1 seg.) e damos inicio ao timer:

Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

AddHandler dt.Tick, AddressOf Processar

dt.Interval = New TimeSpan(0, 0, 1)

dt.Start()

End Sub

Na sub Processar, verificamos se a thread está rodando e atualizamos a Interface do usuário, mudando a cor do circulo para vermelho(Parado) ou verde (Processando), adicionando um novo TextBlock a cada segundo.

Private Sub Processar()

If _threadRun Then

Ellipse1.Fill = New SolidColorBrush(Colors.Green)

lblStatus.Text = "Processando"

Dim t As New TextBlock

t.Text = "Processando"

stackP.Children.Add(t)

Else

Ellipse1.Fill = New SolidColorBrush(Colors.Red)

lblStatus.Text = "Parado"

stackP.Children.Clear()

End If

End Sub

O botão apenas muda o estado da variável _threadRun:

Private Sub btnIniciar_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

If _threadRun Then

_threadRun = False

Else

_threadRun = True

End If

End Sub

O código completo da página fica assim:

Partial Public Class MainPage

Inherits UserControl

Dim dt As New System.Windows.Threading.DispatcherTimer

Private _threadRun As Boolean = False

Public Sub New()

InitializeComponent()

End Sub

Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

AddHandler dt.Tick, AddressOf Processar

dt.Interval = New TimeSpan(0, 0, 1)

dt.Start()

End Sub

Private Sub Processar()

If _threadRun Then

Ellipse1.Fill = New SolidColorBrush(Colors.Green)

lblStatus.Text = "Processando"

Dim t As New TextBlock

t.Text = "Processando"

stackP.Children.Add(t)

Else

Ellipse1.Fill = New SolidColorBrush(Colors.Red)

lblStatus.Text = "Parado"

stackP.Children.Clear()

End If

End Sub

Private Sub btnIniciar_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

If _threadRun Then

_threadRun = False

Else

_threadRun = True

End If

End Sub

End Class

Rode a aplicação (F5) e no browser, clicando no botão, devemos ter as seguintes situações:

Antes de clicar

Depois de clicar

Conclusão

Dessa forma conseguimos demonstrar o uso do Timer numa aplicação Silverlight. Lembrando que o mesmo serve para aplicações WPF.

Abraços e bons estudos!

Gustavo Malheiros

Gustavo Malheiros - Trabalha com Consultoria, Análise e Desenvolvimento de sistemas há 11 anos, com ênfase em tecnologias Microsoft desde VB6, Microsoft .Net e SQL Server.
Líder do Grupo .NET PantaNet (
www.pantanet.net) de Mato Grosso do Sul. Formado em Análise de Sistemas, Pós Graduado com "MBA em Gestão Empresarial".
Desde 2005 trabalha para disseminar a Tecnologia .NET pela Comunidade, com palestras, eventos e treinamentos. Pode ser acompanhado através do blog: http://gustavomalheiros.spaces.live.com.