Implementação de clique em botão e vinculação de propriedades

Na aula anterior, adicionamos um botão no XAML e geramos um evento associado. A primeira funcionalidade implementada alterava o texto do botão ao clicar nele.

Primeiro, volte ao arquivo XAML. Precisamos nomear o botão com x:Name="btnAdd" para manipulá-lo no código C++ do back-end.

<Grid>
    <Button x:Name="btnAdd" Content="Click Me" HorizontalAlignment="Center" VerticalAlignment="Center" Click="OnButtonClick"/>
</Grid>Code language: HTML, XML (xml)

Em seguida, acesse a função de implementação OnButtonClick dentro de MainWindow.xaml.cpp.

Podemos obter diretamente o objeto botão por meio da variável btnAdd declarada acima.

Ao clicar, definimos sua propriedade Content como “Welcome to FoxDevelop.com”.

Vamos executar o projeto para testar o funcionamento.

void winrt::WinuiCppDemo::implementation::MainWindow::OnButtonClick(winrt::Windows::Foundation::IInspectable const& sender, 
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    btnAdd().Content(box_value(L"Welcome to FoxDevelop.com"));
}
Code language: C++ (cpp)

Como podemos ver, o clique consegue modificar propriedades da interface. Em seguida, criaremos uma propriedade inteira para contar cliques, incrementando seu valor cada vez que o botão for pressionado. Essa propriedade será vinculada a um TextBlock no XAML para que a interface seja atualizada automaticamente com o valor mais recente.

Vinculação de Propriedades

Para evitar interferências de códigos de exemplos anteriores, você pode criar um novo projeto vazio.

Siga os passos abaixo:

Modifique o XAML e adicione um TextBlock.

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="WinuiDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinuiDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="WinuiDemo">

    <Grid>
        <TextBlock Text="{x:Bind MyProperty}" FontSize="24"/>
    </Grid>
</Window>
Code language: C++ (cpp)

Depois, no arquivo .cpp, faça com que MyProperty retorne um número.

namespace winrt::WinuiDemo::implementation
{
    int32_t MainWindow::MyProperty()
    {
        return 100;
    }

    void MainWindow::MyProperty(int32_t /* value */)
    {
        throw hresult_not_implemented();
    }
}
Code language: C++ (cpp)

Compile e execute em seguida.

Seu ambiente de desenvolvimento pode exibir o erro abaixo e o processo de compilação ficará travado indefinidamente.

Build started at 14:42...
1>------ Build started: Project: WinuiCppDemo, Configuration: Debug x64 ------
1>WindowsAppSDKMLDeploymentMode=Framework
1>MainWindow.xaml.cpp

A mensagem de erro é a seguinte:

#error directive: "C++/WinRT no longer supports pre-standardization coroutines. 
If you use co_await, switch to /await:strict or upgrade to C++20. If you do not,
 remove /await from the compiler flags."Code language: PHP (php)

Atualizar para C++20

O WinUI 3 e o C++/WinRT são baseados em corrotinas padronizadas, e a atualização para C++20 facilita a manutenção futura.

Acesse Propriedades do Projeto → C/C++ → Linguagem → Padrão de Linguagem C++ e selecione C++20.

Recompile o projeto. O processo demorará muito tempo e gerará 1,3 GB de arquivos intermediários no caminho D:\Demos\WinuiDemo\WinuiDemo\x64\Debug, explicando a lentidão. O tempo varia conforme o hardware do computador. Após compilar com sucesso, ao rodar o app, o número 100 aparecerá na tela.

int32_t MainWindow::MyProperty()
    {
        return 100;
    }Code language: C++ (cpp)

A janela exibe diretamente o valor retornado por essa propriedade.

Implementar contador incremental ao clicar no botão

Agora adicionamos um botão e vinculamos um evento de clique a ele.

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="WinuiDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinuiDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="WinuiDemo">

    <StackPanel Orientation="Vertical">
        <TextBlock Text="{x:Bind MyProperty}" FontSize="24"/>
        <Button Content="Click Me" Click="Button_Click"/>
    </StackPanel>
</Window>
Code language: HTML, XML (xml)

Passe o cursor sobre Button_Click dentro de Click=”Button_Click” e pressione F12: o Visual Studio gerará automaticamente a assinatura da função de evento nos arquivos .h e .cpp.

void Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

A sintaxe é idêntica ao exemplo anterior. Precisamos então de uma variável membro privada do tipo int32_t para armazenar o número de cliques.

Primeiro, adicione uma propriedade inteira no arquivo MainWindow.xaml.h para guardar o valor do contador.

Propriedades definidas em arquivos .idl são apenas uma interface para acesso externo; devemos criar um campo privado próprio para armazenar os dados reais.

Ao escrever Int32 MyProperty no IDL, a classe expõe uma propriedade Int32 de leitura e gravação para componentes externos.

O compilador gera automaticamente os métodos virtuais Get/Set e o evento de alteração de propriedade MyPropertyChanged

int32_t m_myPropValue = 0; // Variável privada que armazena a quantidade de cliques!Code language: C++ (cpp)
#pragma once

#include "MainWindow.g.h"

namespace winrt::WinuiDemo::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
    private:
        int32_t m_myPropValue = 0; // Armazena o valor de MyProperty

    public:
        MainWindow()
        {
            // Objetos Xaml não devem chamar InitializeComponent no construtor.
            // Veja https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
        }

		
		//funções getter & setter
        int32_t MyProperty();
        void MyProperty(int32_t value);

        //Função de clique
        void Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
    };
}

namespace winrt::WinuiDemo::factory_implementation
{
    struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
    {
    };
}


Code language: C++ (cpp)

Agora modifique as funções getter e setter no arquivo .cpp. No manipulador de clique, pegue o valor atual com MyProperty(), some 1 e atribua novamente. Há um ponto essencial:

this->Bindings->Update(); Não omita essa linha em hipótese alguma. Ela avisa todos os elementos de interface vinculados a essa propriedade para se atualizarem; sem ela, a tela nunca mudará os valores.

#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

using namespace winrt;
using namespace Microsoft::UI::Xaml;

// Para saber mais sobre WinUI, estrutura de projetos e modelos: http://aka.ms/winui-project-info.

namespace winrt::WinuiDemo::implementation
{
    int32_t MainWindow::MyProperty()
    {
        return m_myPropValue; //recupera o valor de m_myPropValue
    }

    void MainWindow::MyProperty(int32_t  value)
    {
        m_myPropValue = value; //define o valor em m_myPropValue
        this->Bindings->Update(); // Força a atualização de todos os x:Bind da página para atualizar a UI
    }
}

void winrt::WinuiDemo::implementation::MainWindow::Button_Click(winrt::Windows::Foundation::IInspectable const& sender,
 winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    MyProperty(MyProperty() + 1);//atualiza m_myPropValue, soma 1
}
Code language: C++ (cpp)

Recompile e execute o aplicativo novamente.

No meu computador, a compilação demorou muito tempo; o tempo varia conforme o hardware.

Build started at 15:29...
1>------ Build started: Project: WinuiDemo, Configuration: Debug x64 ------
1>WindowsAppSDKMLDeploymentMode=Framework
1>App.xaml.cpp
1>MainWindow.xaml.cpp

A compilação C++ gera muitos arquivos intermediários; na minha máquina o processo levou mais de dez minutos sem concluir no início.

Às 15:40 do horário local, a compilação finalmente terminou e a janela do app abriu. Todo o processo levou 11 minutos inteiros. Várias vezes achei que o programa tinha travado e quase fechei o Visual Studio.

Resultado final da execução

Esta aula termina aqui. Hoje aprendemos dois pontos principais: primeiro, executar lógica de back-end e alterar o conteúdo da interface ao clicar em um botão; segundo, o mecanismo de vinculação de propriedades, que faz a UI se atualizar automaticamente quando o valor de uma propriedade do back-end muda.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *