En la lección anterior, añadimos un botón en XAML y generamos un evento asociado. La primera funcionalidad que implementamos consistía en modificar el texto del botón al pulsarlo.
Primero volvemos al archivo XAML. Tenemos que asignarle un nombre al botón con x:Name="btnAdd", para poder manipularlo desde el código C++ del backend.
<Grid>
<Button x:Name="btnAdd" Content="Click Me" HorizontalAlignment="Center" VerticalAlignment="Center" Click="OnButtonClick"/>
</Grid>Lenguaje del código: HTML, XML (xml)
A continuación, abrimos la función de implementación OnButtonClick dentro de MainWindow.xaml.cpp.

Podemos obtener directamente el objeto botón a través de la variable btnAdd definida arriba.
Al hacer clic, cambiamos su propiedad Content por el texto «Welcome to FoxDevelop.com».
Ahora ejecutamos el proyecto para comprobar el funcionamiento.

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"));
}
Lenguaje del código: C++ (cpp)
Como hemos visto, el clic permite modificar las propiedades de la interfaz. A continuación, crearemos una propiedad de tipo entero para contar los clics, incrementaremos su valor cada vez que se pulse el botón y la enlazaremos a un TextBlock del XAML para que la interfaz se actualice automáticamente con el número actual.
Enlace de propiedades
Para evitar interferencias con los códigos de ejemplos anteriores, puedes crear un proyecto vacío nuevo.
Sigue los pasos que se indican a continuación:
Modifica el archivo XAML y añade un control 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>
Lenguaje del código: C++ (cpp)
Luego, en el archivo .cpp, hacemos que MyProperty devuelva simplemente un número.
namespace winrt::WinuiDemo::implementation
{
int32_t MainWindow::MyProperty()
{
return 100;
}
void MainWindow::MyProperty(int32_t /* value */)
{
throw hresult_not_implemented();
}
}
Lenguaje del código: C++ (cpp)
Después compila y ejecuta el proyecto.
Es posible que tu entorno de desarrollo muestre el siguiente error y el proceso de compilación se quede bloqueado indefinidamente.
Build started at 14:42...
1>------ Build started: Project: WinuiCppDemo, Configuration: Debug x64 ------
1>WindowsAppSDKMLDeploymentMode=Framework
1>MainWindow.xaml.cpp
El mensaje de error es el siguiente:
#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."Lenguaje del código: PHP (php)
Actualizar a C++20
WinUI 3 y C++/WinRT se basan en corrutinas estándar, por lo que actualizar a C++20 simplifica el mantenimiento a largo plazo.
Ve a Propiedades del proyecto → C/C++ → Idioma → Estándar de lenguaje C++ y selecciona C++20.

Vuelve a compilar. El proceso tardará mucho tiempo y generará archivos intermedios de 1,3 GB en la ruta D:\Demos\WinuiDemo\WinuiDemo\x64\Debug, lo que explica la lentitud. El tiempo varía según el hardware del equipo. Si la compilación tiene éxito y ejecutas la app, aparecerá el número 100 en la ventana.
int32_t MainWindow::MyProperty()
{
return 100;
}Lenguaje del código: C++ (cpp)
La pantalla mostrará directamente el valor que devuelve esta propiedad.

Implementar contador incremental al pulsar el botón
Ahora añadimos un botón y le asociamos un manejador de evento de clic.
<?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>
Lenguaje del código: HTML, XML (xml)
Coloca el cursor sobre Button_Click dentro de Click=»Button_Click» y pulsa la tecla F12: Visual Studio generará automáticamente la firma de la función de evento en los archivos .h y .cpp.
void Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
La sintaxis es idéntica al ejemplo anterior. A continuación necesitamos una variable miembro privada de tipo int32_t para almacenar el número de clics.
Primero añadimos una propiedad entera en el archivo MainWindow.xaml.h para guardar el valor del contador.
Las propiedades definidas en archivos .idl solo son una interfaz para acceso externo; debemos crear nuestro propio campo privado para guardar los datos reales.
Cuando escribimos
Int32 MyPropertyen el IDL, la clase expone una propiedad Int32 de lectura y escritura para componentes externos.El compilador genera automáticamente los métodos virtuales Get/Set y el evento de cambio de propiedad
MyPropertyChanged
int32_t m_myPropValue = 0; // Variable privada que almacena el número de clics!Lenguaje del código: C++ (cpp)
#pragma once
#include "MainWindow.g.h"
namespace winrt::WinuiDemo::implementation
{
struct MainWindow : MainWindowT<MainWindow>
{
private:
int32_t m_myPropValue = 0; // Almacena el valor de MyProperty
public:
MainWindow()
{
// Los objetos Xaml no deben llamar a InitializeComponent dentro del constructor.
// Consulta https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
}
//funciones getter & setter
int32_t MyProperty();
void MyProperty(int32_t value);
//Función de clic
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>
{
};
}
Lenguaje del código: C++ (cpp)

Ahora modificamos las funciones getter y setter en el archivo .cpp. Dentro del manejador de clic obtenemos el valor actual mediante MyProperty(), le sumamos uno y lo volvemos a asignar. Hay un punto fundamental:
this->Bindings->Update(); No elimines esta línea bajo ningún concepto. Notifica a todos los elementos de UI enlazados a esta propiedad que se refresquen; sin ella la pantalla nunca actualizará sus 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 más sobre WinUI, estructura de proyectos y plantillas: http://aka.ms/winui-project-info.
namespace winrt::WinuiDemo::implementation
{
int32_t MainWindow::MyProperty()
{
return m_myPropValue; // Obtener valor de m_myPropValue
}
void MainWindow::MyProperty(int32_t value)
{
m_myPropValue = value; // Asignar valor a m_myPropValue
this->Bindings->Update(); // Forzar actualización de todos los enlaces x:Bind de la página para refrescar la UI
}
}
void winrt::WinuiDemo::implementation::MainWindow::Button_Click(winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
MyProperty(MyProperty() + 1);// Actualizar m_myPropValue, sumar 1
}
Lenguaje del código: C++ (cpp)

Vuelve a compilar y ejecutar la aplicación.
En mi equipo la compilación tarda muchísimo tiempo; la duración depende de las especificaciones del PC.
Build started at 15:29...
1>------ Build started: Project: WinuiDemo, Configuration: Debug x64 ------
1>WindowsAppSDKMLDeploymentMode=Framework
1>App.xaml.cpp
1>MainWindow.xaml.cpp
La compilación C++ genera una gran cantidad de archivos intermedios; en mi máquina el proceso duró más de diez minutos sin terminar al principio.

A las 15:40 hora local la compilación terminó por fin y se abrió la ventana de la aplicación; el proceso completo duró 11 minutos enteros. Varias veces pensé que el programa se había colgado y estuve a punto de cerrar Visual Studio.
Resultado final de ejecución

Esto concluye la lección. Hoy hemos aprendido dos conceptos clave: primero, cómo ejecutar lógica de backend y modificar el contenido de la interfaz al pulsar un botón; segundo, el mecanismo de enlace de propiedades, que hace que la UI se actualice automáticamente cuando cambia el valor de una propiedad del backend.