Fazer conversão boxing e unboxing de valores para IInspectable com C++/WinRT

Observação

É possível fazer conversão boxing e unboxing não apenas de valores escalares, mas também da maioria dos tipos de matrizes (exceto por matrizes de enumerações) usando as funções winrt::box_value e winrt::unbox_value. É possível fazer a conversão unboxing apenas de valores escalares usando a função winrt::unbox_value_or.

A interface IInspectable é a interface raiz de cada classe de tempo de execução no Windows Runtime (WinRT). Isso é uma ideia análoga a IUnknown estando na raiz de cada interface e classe COM, e System.Object estando na raiz de cada classe Common Type System.

Em outras palavras, uma função que espera IInspectable pode ser passada como uma instância de qualquer classe de runtime. Porém, não é possível passar diretamente um valor escalar (como um valor numérico ou de texto) para esse tipo de função, nem uma matriz. Em vez disso, um valor escalar ou de matriz precisa ser encapsulado dentro de um objeto de classe de referência. Esse processo de encapsulamento é conhecido como conversão do valor.

Importante

Você pode converter e desconverter qualquer tipo que você possa passar para uma API Windows Runtime. Em outras palavras, um tipo do Windows Runtime. Valores numéricos e de texto (cadeias de caracteres) são alguns dos exemplos fornecidos acima. Outro exemplo é um struct que você define em IDL. Se você tentar usar um struct C++ comum (um que não esteja definido em IDL), o compilador lembrará você de que é possível converter apenas um tipo de Windows Runtime. Uma classe de runtime é um tipo de Windows Runtime, mas é claro que você pode passar classes de runtime para APIs do Windows Runtime sem convertê-las.

O C++/WinRT fornece a função winrt::box_value, que pega um valor escalar ou de matriz e retorna o valor convertido por boxing em IInspectable. Para a conversão unboxing de um IInspectable em um valor escalar ou de matriz, existe a função winrt::unbox_value. Além disso, para a conversão unboxing de um IInspectable em um valor escalar, existe a função winrt::unbox_value_or.

Exemplos de conversão boxing de um valor

A função de acessador LaunchActivatedEventArgs::Arguments retorna uma winrt::hstring, que é um valor escalar. Podemos converter o valor hstring e passá-lo para uma função que espera IInspectable da seguinte maneira.

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    ...
    rootFrame.Navigate(winrt::xaml_typename<BlankApp1::MainPage>(), winrt::box_value(e.Arguments()));
    ...
}

Para definir a propriedade de conteúdo de um Button XAML, chame a função modificadora Button::Content. Para definir a propriedade de conteúdo como um valor de cadeia de caracteres, use esse código.

Button().Content(winrt::box_value(L"Clicked"));

Primeiro, o construtor de conversão hstring converte a cadeia de caracteres literal em uma hstring. Em seguida, chama-se a sobrecarga de winrt::box_value que usa uma hstring.

Exemplos de conversão unboxing de um IInspectable

Nas funções que esperam IInspectable, use winrt::unbox_value para fazer a conversão unboxing, e winrt::unbox_value_or para fazer a conversão unboxing com um valor padrão. Você também pode usar try_as para fazer a conversão unboxing para um std::optional.

void Unbox(winrt::Windows::Foundation::IInspectable const& object)
{
    hstring hstringValue = unbox_value<hstring>(object); // Throws if object is not a boxed string.
    hstringValue = unbox_value_or<hstring>(object, L"Default"); // Returns L"Default" if object is not a boxed string.
    float floatValue = unbox_value_or<float>(object, 0.f); // Returns 0.0 if object is not a boxed float.
    std::optional<int> optionalInt = object.try_as<int>(); // Returns std::nullopt if object is not a boxed int.
}

Determinar o tipo de um valor de conversão boxing

Se você receber um valor de conversão boxing e não tiver certeza de qual tipo ele contém (é preciso saber o tipo para convertê-lo), confira o valor de conversão boxing para a interface IPropertyValue e chame Type. Aqui está um exemplo de código.

WINRT_ASSERT é uma definição de macro e se expande para _ASSERTE.

float pi = 3.14f;
auto piInspectable = winrt::box_value(pi);
auto piPropertyValue = piInspectable.as<winrt::Windows::Foundation::IPropertyValue>();
WINRT_ASSERT(piPropertyValue.Type() == winrt::Windows::Foundation::PropertyType::Single);

APIs importantes