WPF - Calculadora (usando resources)


Neste artigo eu vou mostrar como usar os recursos do WPF para criar uma calculadora simples que usa a definição de resources para compor os números, operadores, resultado, etc.

O WPF usa a linguagem XAML e esta linguagem permite que você defina recursos (resources) que você pode usar para definir controles.  Depois que você define um recurso você pode usá-lo na definição de controles.

Vejamos um exemplo:

1- No código abaixo estamos definindo um recurso onde definimos um RadialGradientBrush chamado brNumero que começa com amarelo no centro e vai desvanecendo para laranja nas bordas do controle:

<Window.Resources>
  <RadialGradientBrush 
    Center="0.5,0.5"
    RadiusX="1.0"
    RadiusY="1.0"
    x:Key="brNumber">
    <GradientStop Color="Yellow" Offset="0.0" />
    <GradientStop Color="Orange" Offset="1.0" />
  </RadialGradientBrush>
</Window.Resources>

2- O código abaixo estamos definindo um recurso que define um Button contendo o texto "9" na célula (2,0) de uma grade. O atributo BackGround indica que o  botão deverá usar um recurso estático chamado brNumero previamente definido:

<Button
  Background="{StaticResource brNumber}"
  Grid.Row="2"
  Grid.Column="0"
  Margin="2,2,2,2"
  Name="btnNum7" Focusable="False">9</Button

É isso que estamos fazendo em nossa calculadora para criar os botões usando a mesma cor de fundo. A vantagem é que se você resolver mudar a cor de fundo você só precisa alterar a definição do recurso e todos os botões serão atualizados.

Outro recurso que estamos usando na calculadora é expresso pelo código XAML abaixo:

<Window.Resources>
  <RadialGradientBrush 
    Center="0.5,0.5"
    RadiusX="1.0"
    RadiusY="1.0"
    x:Key="brLimpar">
    <GradientStop Color="AliceBlue" Offset="0.0" />
    <GradientStop Color="Blue" Offset="1.0" />
  </RadialGradientBrush>

  <Style x:Key="styLimpar">
    <Setter Property="Control.Background" Value="{StaticResource brLimpar}" />
  </Style>
</Window.Resources>

 

Este código define o recurso RadialGradienteBrush chamado brLimpar e define também um estilo chamado styLimpar.

O estilo inclui um Setter que define a propriedade BackGround do controle para o recurso brLimpar.

Após definir o estilo , você pode usá-lo para definir controles. No código abaixo estamos definindo um Button chamado btnCe que exibe o texto "CE" e possui o estilo definido para o estilo styLimpar que foi criado. O atributo Click="ClickCe" indica que o botão vai chamar a rotina Visual Basic ClickCe quando for clicado.

Button 
  Style="{StaticResource styLimpar}"
  Grid.Row="1" Margin="2,20,2,2" 
  Name="btnCe"
  Click="ClickCe" Focusable="False">CE</Button>

 

A rotina ClickCe pode ser definida da seguinte forma:

Private Sub ClickCE(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
    ProcessarCE()
End Sub

A interface visual obtida pelo código XAML da nossa calculadora é dada abaixo:

O código XAML da calculadora vem a seguir:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Calculadora-XAML" Height="292" Width="227" Focusable="True">
  <Window.Resources>
    <RadialGradientBrush 
      Center="0.5,0.5"
      RadiusX="1.0"
      RadiusY="1.0"
      x:Key="brOperador">
      <GradientStop Color="Lime" Offset="0.0" />
      <GradientStop Color="Green" Offset="1.0" />
    </RadialGradientBrush>
    <RadialGradientBrush 
      Center="0.5,0.5"
      RadiusX="1.0"
      RadiusY="1.0"
      x:Key="brLimpar">
      <GradientStop Color="AliceBlue" Offset="0.0" />
      <GradientStop Color="Blue" Offset="1.0" />
    </RadialGradientBrush>
    <RadialGradientBrush 
      Center="0.5,0.5"
      RadiusX="1.0"
      RadiusY="1.0"
      x:Key="brNumero">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Orange" Offset="1.0" />
    </RadialGradientBrush>
    <LinearGradientBrush
       x:Key="brResultado"
       StartPoint="0,0"
       EndPoint="1,1"
    >
      <GradientStop Color="LightBlue" Offset="0.0" />
      <GradientStop Color="AliceBlue" Offset="1.0" />
    </LinearGradientBrush>
    <Border x:Key="bdrSelecionado" Width="5" />
    <Style x:Key="styButton">
      <Setter Property="Control.Background" Value="{StaticResource brNumero}" />
    </Style>
    <Style x:Key="styOperador">
      <Setter Property="Control.Background" Value="{StaticResource brOperador}" />
    </Style>
    <Style x:Key="styLimpar">
      <Setter Property="Control.Background" Value="{StaticResource brLimpar}" />
    </Style>
  </Window.Resources>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="0.25*" />
      <ColumnDefinition Width="0.25*" />
      <ColumnDefinition Width="0.25*" />
      <ColumnDefinition Width="0.25*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="0.10*" />
      <RowDefinition Height="0.22*" />
      <RowDefinition Height="0.17*" />
      <RowDefinition Height="0.17*" />
      <RowDefinition Height="0.17*" />
      <RowDefinition Height="0.17*" />
    </Grid.RowDefinitions>
    <!-- Linha 1 -->
      <Button 
        Style="{StaticResource styLimpar}"
        Grid.Row="1" Margin="2,20,2,2" 
        Name="btnCe"
        Click="ClickCe" Focusable="False">CE</Button>
      <Button 
        Style="{StaticResource styLimpar}"
        Grid.Row="1" 
        Grid.Column="1" 
        Margin="2,20,2,2" 
        Name="btnC" Focusable="False">C</Button>
      <Button 
        Style="{StaticResource styLimpar}"
        Grid.Row="1" 
        Grid.Column="3" 
        Margin="2,20,2,2" 
        Name="btnEquals" Focusable="False">=</Button>
    <!-- Linha 2 -->
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="2" 
        Grid.Column="0" 
        Margin="2,2,2,2" 
        Name="btnNum7" Focusable="False">7</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="2" 
        Grid.Column="1" 
        Margin="2,2,2,2" 
        Name="btnNum8" Focusable="False">8</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="2" 
        Grid.Column="2"
        Margin="2,2,2,2" 
        Name="btnNum9" Focusable="False">9</Button>
      <Button 
        Style="{StaticResource styOperador}"
        Grid.Row="2" 
        Grid.Column="3" 
        Margin="2,2,2,2" 
        Name="btnDivide" Focusable="False">/</Button>
      <!-- Linha 3 -->
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="3" 
        Grid.Column="0" 
        Margin="2,2,2,2" 
        Name="btnNum4" Focusable="False">4</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="3" 
        Grid.Column="1" 
        Margin="2,2,2,2" 
        Name="btnNum5" Focusable="False">5</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="3" 
        Grid.Column="2"
        Margin="2,2,2,2" 
        Name="btnNum6" Focusable="False">6</Button>
      <Button 
        Style="{StaticResource styOperador}"
        Grid.Row="3" 
        Grid.Column="3" 
        Margin="2,2,2,2" 
        Name="btnTimes" Focusable="False">*</Button>
      <!-- Linha 4 -->
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="4"
        Grid.Column="0" 
        Margin="2,2,2,2" 
        Name="btnNum1" Focusable="False">1</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="4" 
        Grid.Column="1" 
        Margin="2,2,2,2" 
        Name="btnNum2" Focusable="False">2</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="4" 
        Grid.Column="2"
        Margin="2,2,2,2" 
        Name="btnNum3" Focusable="False">3</Button>
      <Button 
        Style="{StaticResource styOperador}"
        Grid.Row="4" 
        Grid.Column="3" 
        Margin="2,2,2,2" 
        Name="btnMinus" Focusable="False">-</Button>
      <!-- Linha 5 -->
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="5" 
        Grid.Column="0" 
        Margin="2,2,2,2" 
        Name="btnNum0" Focusable="False">0</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="5" 
        Grid.Column="1" 
        Margin="2,2,2,2" 
        Name="btnPlusMinus" Focusable="False">+/-</Button>
      <Button 
        Background="{StaticResource brNumero}"
        Grid.Row="5" 
        Grid.Column="2"
        Margin="2,2,2,2" 
        Name="btnDecimal" Focusable="False">.</Button>
      <Button 
        Style="{StaticResource styOperador}"
        Grid.Row="5" 
        Grid.Column="3" 
        Margin="2,2,2,2" 
        Name="btnPlus" Focusable="False">+</Button>
    <Label 
      Background="{StaticResource brResultado}"
      Grid.ColumnSpan="4" 
      Margin="2,2,2,2" 
      Name="lblResult" 
      HorizontalContentAlignment="Right" 
      VerticalContentAlignment="Center">0</Label>
  </Grid>
</Window>

 

O código para processar a entrada do usuário e os eventos dos botões esta no arquivo Window1.xaml.vb.

Segue abaixo os códigos referente ao processamentos dos botões:

#Region "Buttons"
    ' foi clicado um digito
    Private Sub btnDigit_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) _
    Handles btnNum0.Click, btnNum1.Click, btnNum2.Click, btnNum3.Click, btnNum4.Click, _ 
    btnNum5.Click, btnNum6.Click, btnNum7.Click, btnNum8.Click, btnNum9.Click
        Dim btn As Button = DirectCast(sender, Button)
        ProcessarDigito(btn.Content.ToString())
    End Sub

    ' foi clicado um ponto decimal
    Private Sub btnDecimal_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnDecimal.Click
        ProcessarDecimal()
    End Sub

    ' foi clicado o  CE.
    Private Sub ClickCE(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
        ProcessarCE()
    End Sub

    ' Foi clicado o C
    Private Sub btnC_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnC.Click
        ProcessarC()
    End Sub

    ' Calcula 0 resultado.
    Private Sub btnEquals_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnEquals.Click
        ProcessarIgual()
    End Sub

    ' Armazena o operador diferente de igual
    Private Sub btnOperator_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) _ 
Handles btnPlus.Click, btnMinus.Click, btnTimes.Click, btnDivide.Click
        ' Processa oe operador.
        Dim btn As Button = DirectCast(sender, Button)
        Select Case btn.Content.ToString()
            Case "+"
                ProcessarOperador(Operadores.opSoma)
            Case "-"
                ProcessarOperador(Operadores.opSubtrai)
            Case "*"
                ProcessarOperador(Operadores.opVezes)
            Case "/"
                ProcessarOperador(Operadores.opDivide)
        End Select
    End Sub
    ' Clicou "+/-".
    Private Sub btnPlusMinus_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnPlusMinus.Click
        ProcessarMaisMenos()
    End Sub
#End Region ' Buttons

 

Executando o projeto podemos realizar algumas operações simples com a calculadora:

Aguarde mais artigos sobre WPF.

Pegue o projeto completo aqui: calculadoraWPF.zip (Abra com o VB 2010 Express)

Eu sei é apenas WPF, mas eu gosto...

Referências:


José Carlos Macoratti