diff --git a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj
index f08fd189d9..ce995b255e 100644
--- a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj
+++ b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj
@@ -126,9 +126,12 @@
+
+
+
diff --git a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters
index 8ceff937a5..29c109ca98 100644
--- a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters
+++ b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters
@@ -112,6 +112,8 @@
+
+
@@ -231,8 +233,9 @@
+
-
\ No newline at end of file
+
diff --git a/source/uwp/Renderer/lib/ActionHelpers.cpp b/source/uwp/Renderer/lib/ActionHelpers.cpp
new file mode 100644
index 0000000000..d15202ca09
--- /dev/null
+++ b/source/uwp/Renderer/lib/ActionHelpers.cpp
@@ -0,0 +1,1014 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+#include "pch.h"
+
+#include "ActionHelpers.h"
+#include "AdaptiveImage.h"
+#include "AdaptiveRenderArgs.h"
+#include "AdaptiveShowCardActionRenderer.h"
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::AdaptiveNamespace;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::UI::Xaml;
+using namespace ABI::Windows::UI::Xaml::Automation;
+using namespace ABI::Windows::UI::Xaml::Controls;
+using namespace ABI::Windows::UI::Xaml::Controls::Primitives;
+using namespace ABI::Windows::UI::Xaml::Input;
+using namespace ABI::Windows::UI::Xaml::Media;
+
+namespace AdaptiveNamespace::ActionHelpers
+{
+ HRESULT GetButtonMargin(_In_ IAdaptiveActionsConfig* actionsConfig, Thickness& buttonMargin) noexcept
+ {
+ buttonMargin = {0, 0, 0, 0};
+ UINT32 buttonSpacing;
+ RETURN_IF_FAILED(actionsConfig->get_ButtonSpacing(&buttonSpacing));
+
+ ABI::AdaptiveNamespace::ActionsOrientation actionsOrientation;
+ RETURN_IF_FAILED(actionsConfig->get_ActionsOrientation(&actionsOrientation));
+
+ if (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal)
+ {
+ buttonMargin.Left = buttonMargin.Right = buttonSpacing / 2;
+ }
+ else
+ {
+ buttonMargin.Top = buttonMargin.Bottom = buttonSpacing / 2;
+ }
+
+ return S_OK;
+ }
+
+ void ArrangeButtonContent(_In_ IAdaptiveActionElement* action,
+ _In_ IAdaptiveActionsConfig* actionsConfig,
+ _In_ IAdaptiveRenderContext* renderContext,
+ ABI::AdaptiveNamespace::ContainerStyle containerStyle,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveHostConfig* hostConfig,
+ bool allActionsHaveIcons,
+ _In_ IButton* button)
+ {
+ HString title;
+ THROW_IF_FAILED(action->get_Title(title.GetAddressOf()));
+
+ HString iconUrl;
+ THROW_IF_FAILED(action->get_IconUrl(iconUrl.GetAddressOf()));
+
+ ComPtr localButton(button);
+
+ // Check if the button has an iconUrl
+ if (iconUrl != nullptr)
+ {
+ // Get icon configs
+ ABI::AdaptiveNamespace::IconPlacement iconPlacement;
+ UINT32 iconSize;
+
+ THROW_IF_FAILED(actionsConfig->get_IconPlacement(&iconPlacement));
+ THROW_IF_FAILED(actionsConfig->get_IconSize(&iconSize));
+
+ // Define the alignment for the button contents
+ ComPtr buttonContentsStackPanel =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel));
+
+ // Create image and add it to the button
+ ComPtr adaptiveImage;
+ THROW_IF_FAILED(MakeAndInitialize(&adaptiveImage));
+
+ THROW_IF_FAILED(adaptiveImage->put_Url(iconUrl.Get()));
+ THROW_IF_FAILED(adaptiveImage->put_HorizontalAlignment(ABI::AdaptiveNamespace::HAlignment::Center));
+
+ ComPtr adaptiveCardElement;
+ THROW_IF_FAILED(adaptiveImage.As(&adaptiveCardElement));
+ ComPtr childRenderArgs;
+ THROW_IF_FAILED(
+ MakeAndInitialize(&childRenderArgs, containerStyle, buttonContentsStackPanel.Get(), nullptr));
+
+ ComPtr elementRenderers;
+ THROW_IF_FAILED(renderContext->get_ElementRenderers(&elementRenderers));
+
+ ComPtr buttonIcon;
+ ComPtr elementRenderer;
+ THROW_IF_FAILED(elementRenderers->Get(HStringReference(L"Image").Get(), &elementRenderer));
+ if (elementRenderer != nullptr)
+ {
+ elementRenderer->Render(adaptiveCardElement.Get(), renderContext, childRenderArgs.Get(), &buttonIcon);
+ if (buttonIcon == nullptr)
+ {
+ XamlHelpers::SetContent(localButton.Get(), title.Get());
+ return;
+ }
+ }
+
+ // Create title text block
+ ComPtr buttonText =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock));
+ THROW_IF_FAILED(buttonText->put_Text(title.Get()));
+ THROW_IF_FAILED(buttonText->put_TextAlignment(TextAlignment::TextAlignment_Center));
+
+ // Handle different arrangements inside button
+ ComPtr buttonIconAsFrameworkElement;
+ THROW_IF_FAILED(buttonIcon.As(&buttonIconAsFrameworkElement));
+ ComPtr separator;
+ if (iconPlacement == ABI::AdaptiveNamespace::IconPlacement::AboveTitle && allActionsHaveIcons)
+ {
+ THROW_IF_FAILED(buttonContentsStackPanel->put_Orientation(Orientation::Orientation_Vertical));
+
+ // Set icon height to iconSize (aspect ratio is automatically maintained)
+ THROW_IF_FAILED(buttonIconAsFrameworkElement->put_Height(iconSize));
+ }
+ else
+ {
+ THROW_IF_FAILED(buttonContentsStackPanel->put_Orientation(Orientation::Orientation_Horizontal));
+
+ // Add event to the image to resize itself when the textblock is rendered
+ ComPtr buttonIconAsImage;
+ THROW_IF_FAILED(buttonIcon.As(&buttonIconAsImage));
+
+ EventRegistrationToken eventToken;
+ THROW_IF_FAILED(buttonIconAsImage->add_ImageOpened(
+ Callback([buttonIconAsFrameworkElement,
+ buttonText](IInspectable* /*sender*/, IRoutedEventArgs * /*args*/) -> HRESULT {
+ ComPtr buttonTextAsFrameworkElement;
+ RETURN_IF_FAILED(buttonText.As(&buttonTextAsFrameworkElement));
+
+ return SetMatchingHeight(buttonIconAsFrameworkElement.Get(), buttonTextAsFrameworkElement.Get());
+ }).Get(),
+ &eventToken));
+
+ // Only add spacing when the icon must be located at the left of the title
+ UINT spacingSize;
+ THROW_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig, ABI::AdaptiveNamespace::Spacing::Default, &spacingSize));
+
+ ABI::Windows::UI::Color color = {0};
+ separator = XamlHelpers::CreateSeparator(renderContext, spacingSize, spacingSize, color, false);
+ }
+
+ ComPtr buttonContentsPanel;
+ THROW_IF_FAILED(buttonContentsStackPanel.As(&buttonContentsPanel));
+
+ // Add image to stack panel
+ XamlHelpers::AppendXamlElementToPanel(buttonIcon.Get(), buttonContentsPanel.Get());
+
+ // Add separator to stack panel
+ if (separator != nullptr)
+ {
+ XamlHelpers::AppendXamlElementToPanel(separator.Get(), buttonContentsPanel.Get());
+ }
+
+ // Add text to stack panel
+ XamlHelpers::AppendXamlElementToPanel(buttonText.Get(), buttonContentsPanel.Get());
+
+ // Finally, put the stack panel inside the final button
+ ComPtr buttonContentControl;
+ THROW_IF_FAILED(localButton.As(&buttonContentControl));
+ THROW_IF_FAILED(buttonContentControl->put_Content(buttonContentsPanel.Get()));
+ }
+ else
+ {
+ XamlHelpers::SetContent(localButton.Get(), title.Get());
+ }
+ }
+
+ HRESULT HandleActionStyling(_In_ IAdaptiveActionElement* adaptiveActionElement,
+ _In_ IFrameworkElement* buttonFrameworkElement,
+ _In_ IAdaptiveRenderContext* renderContext)
+ {
+ HString actionSentiment;
+ RETURN_IF_FAILED(adaptiveActionElement->get_Style(actionSentiment.GetAddressOf()));
+
+ INT32 isSentimentPositive{}, isSentimentDestructive{}, isSentimentDefault{};
+
+ ComPtr resourceDictionary;
+ RETURN_IF_FAILED(renderContext->get_OverrideStyles(&resourceDictionary));
+ ComPtr styleToApply;
+
+ ComPtr contextImpl =
+ PeekInnards(renderContext);
+
+ if ((SUCCEEDED(WindowsCompareStringOrdinal(actionSentiment.Get(), HStringReference(L"default").Get(), &isSentimentDefault)) &&
+ (isSentimentDefault == 0)) ||
+ WindowsIsStringEmpty(actionSentiment.Get()))
+ {
+ RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.Action", buttonFrameworkElement));
+ }
+ else if (SUCCEEDED(WindowsCompareStringOrdinal(actionSentiment.Get(), HStringReference(L"positive").Get(), &isSentimentPositive)) &&
+ (isSentimentPositive == 0))
+ {
+ if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(resourceDictionary.Get(),
+ L"Adaptive.Action.Positive",
+ &styleToApply)))
+ {
+ RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get()));
+ }
+ else
+ {
+ // By default, set the action background color to accent color
+ ComPtr actionSentimentDictionary = contextImpl->GetDefaultActionSentimentDictionary();
+
+ if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(actionSentimentDictionary.Get(),
+ L"PositiveActionDefaultStyle",
+ styleToApply.GetAddressOf())))
+ {
+ RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get()));
+ }
+ }
+ }
+ else if (SUCCEEDED(WindowsCompareStringOrdinal(actionSentiment.Get(), HStringReference(L"destructive").Get(), &isSentimentDestructive)) &&
+ (isSentimentDestructive == 0))
+ {
+ if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(resourceDictionary.Get(),
+ L"Adaptive.Action.Destructive",
+ &styleToApply)))
+ {
+ RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get()));
+ }
+ else
+ {
+ // By default, set the action text color to attention color
+ ComPtr actionSentimentDictionary = contextImpl->GetDefaultActionSentimentDictionary();
+
+ if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(actionSentimentDictionary.Get(),
+ L"DestructiveActionDefaultStyle",
+ styleToApply.GetAddressOf())))
+ {
+ RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get()));
+ }
+ }
+ }
+ else
+ {
+ HString actionSentimentStyle;
+ RETURN_IF_FAILED(WindowsConcatString(HStringReference(L"Adaptive.Action.").Get(),
+ actionSentiment.Get(),
+ actionSentimentStyle.GetAddressOf()));
+ RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(
+ renderContext, StringToWstring(HStringToUTF8(actionSentimentStyle.Get())), buttonFrameworkElement));
+ }
+ return S_OK;
+ }
+
+ HRESULT SetMatchingHeight(_In_ IFrameworkElement* elementToChange, _In_ IFrameworkElement* elementToMatch)
+ {
+ DOUBLE actualHeight;
+ RETURN_IF_FAILED(elementToMatch->get_ActualHeight(&actualHeight));
+
+ ComPtr localElement(elementToChange);
+ RETURN_IF_FAILED(localElement->put_Height(actualHeight));
+
+ ComPtr frameworkElementAsUIElement;
+ RETURN_IF_FAILED(localElement.As(&frameworkElementAsUIElement));
+ RETURN_IF_FAILED(frameworkElementAsUIElement->put_Visibility(Visibility::Visibility_Visible));
+ return S_OK;
+ }
+
+ HRESULT BuildAction(_In_ IAdaptiveActionElement* adaptiveActionElement,
+ _In_ IAdaptiveRenderContext* renderContext,
+ _In_ IAdaptiveRenderArgs* renderArgs,
+ _Outptr_ IUIElement** actionControl)
+ {
+ // Render a button for the action
+ ComPtr action(adaptiveActionElement);
+ ComPtr button =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Button));
+
+ ComPtr buttonFrameworkElement;
+ RETURN_IF_FAILED(button.As(&buttonFrameworkElement));
+
+ ComPtr hostConfig;
+ RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig));
+ ComPtr actionsConfig;
+ RETURN_IF_FAILED(hostConfig->get_Actions(actionsConfig.GetAddressOf()));
+
+ Thickness buttonMargin;
+ RETURN_IF_FAILED(GetButtonMargin(actionsConfig.Get(), buttonMargin));
+ RETURN_IF_FAILED(buttonFrameworkElement->put_Margin(buttonMargin));
+
+ ABI::AdaptiveNamespace::ActionsOrientation actionsOrientation;
+ RETURN_IF_FAILED(actionsConfig->get_ActionsOrientation(&actionsOrientation));
+
+ ABI::AdaptiveNamespace::ActionAlignment actionAlignment;
+ RETURN_IF_FAILED(actionsConfig->get_ActionAlignment(&actionAlignment));
+
+ if (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal)
+ {
+ // For horizontal alignment, we always use stretch
+ RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(
+ ABI::Windows::UI::Xaml::HorizontalAlignment::HorizontalAlignment_Stretch));
+ }
+ else
+ {
+ switch (actionAlignment)
+ {
+ case ABI::AdaptiveNamespace::ActionAlignment::Center:
+ RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Center));
+ break;
+ case ABI::AdaptiveNamespace::ActionAlignment::Left:
+ RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Left));
+ break;
+ case ABI::AdaptiveNamespace::ActionAlignment::Right:
+ RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Right));
+ break;
+ case ABI::AdaptiveNamespace::ActionAlignment::Stretch:
+ RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Stretch));
+ break;
+ }
+ }
+
+ ABI::AdaptiveNamespace::ContainerStyle containerStyle;
+ RETURN_IF_FAILED(renderArgs->get_ContainerStyle(&containerStyle));
+
+ boolean allowAboveTitleIconPlacement;
+ RETURN_IF_FAILED(renderArgs->get_AllowAboveTitleIconPlacement(&allowAboveTitleIconPlacement));
+
+ ArrangeButtonContent(action.Get(),
+ actionsConfig.Get(),
+ renderContext,
+ containerStyle,
+ hostConfig.Get(),
+ allowAboveTitleIconPlacement,
+ button.Get());
+
+ ABI::AdaptiveNamespace::ActionType actionType;
+ RETURN_IF_FAILED(action->get_ActionType(&actionType));
+
+ ComPtr showCardActionConfig;
+ RETURN_IF_FAILED(actionsConfig->get_ShowCard(&showCardActionConfig));
+ ABI::AdaptiveNamespace::ActionMode showCardActionMode;
+ RETURN_IF_FAILED(showCardActionConfig->get_ActionMode(&showCardActionMode));
+ std::shared_ptr>> allShowCards = std::make_shared>>();
+
+ // Add click handler which calls IAdaptiveActionInvoker::SendActionEvent
+ ComPtr buttonBase;
+ RETURN_IF_FAILED(button.As(&buttonBase));
+
+ ComPtr actionInvoker;
+ RETURN_IF_FAILED(renderContext->get_ActionInvoker(&actionInvoker));
+ EventRegistrationToken clickToken;
+ RETURN_IF_FAILED(buttonBase->add_Click(Callback([action, actionInvoker](IInspectable* /*sender*/, IRoutedEventArgs *
+ /*args*/) -> HRESULT {
+ return actionInvoker->SendActionEvent(action.Get());
+ }).Get(),
+ &clickToken));
+
+ RETURN_IF_FAILED(HandleActionStyling(adaptiveActionElement, buttonFrameworkElement.Get(), renderContext));
+
+ ComPtr buttonAsUIElement;
+ RETURN_IF_FAILED(button.As(&buttonAsUIElement));
+ *actionControl = buttonAsUIElement.Detach();
+ return S_OK;
+ }
+
+ bool WarnForInlineShowCard(_In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveActionElement* action, const std::wstring& warning)
+ {
+ if (action != nullptr)
+ {
+ ABI::AdaptiveNamespace::ActionType actionType;
+ THROW_IF_FAILED(action->get_ActionType(&actionType));
+
+ if (actionType == ABI::AdaptiveNamespace::ActionType::ShowCard)
+ {
+ THROW_IF_FAILED(renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::UnsupportedValue,
+ HStringReference(warning.c_str()).Get()));
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static HRESULT HandleKeydownForInlineAction(_In_ IKeyRoutedEventArgs* args,
+ _In_ IAdaptiveActionInvoker* actionInvoker,
+ _In_ IAdaptiveActionElement* inlineAction)
+ {
+ ABI::Windows::System::VirtualKey key;
+ RETURN_IF_FAILED(args->get_Key(&key));
+
+ if (key == ABI::Windows::System::VirtualKey::VirtualKey_Enter)
+ {
+ ComPtr coreWindowStatics;
+ RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreWindow).Get(), &coreWindowStatics));
+
+ ComPtr coreWindow;
+ RETURN_IF_FAILED(coreWindowStatics->GetForCurrentThread(&coreWindow));
+
+ ABI::Windows::UI::Core::CoreVirtualKeyStates shiftKeyState;
+ RETURN_IF_FAILED(coreWindow->GetKeyState(ABI::Windows::System::VirtualKey_Shift, &shiftKeyState));
+
+ ABI::Windows::UI::Core::CoreVirtualKeyStates ctrlKeyState;
+ RETURN_IF_FAILED(coreWindow->GetKeyState(ABI::Windows::System::VirtualKey_Control, &ctrlKeyState));
+
+ if (shiftKeyState == ABI::Windows::UI::Core::CoreVirtualKeyStates_None &&
+ ctrlKeyState == ABI::Windows::UI::Core::CoreVirtualKeyStates_None)
+ {
+ RETURN_IF_FAILED(actionInvoker->SendActionEvent(inlineAction));
+ RETURN_IF_FAILED(args->put_Handled(true));
+ }
+ }
+
+ return S_OK;
+ }
+
+ void HandleInlineAction(_In_ IAdaptiveRenderContext* renderContext,
+ _In_ IAdaptiveRenderArgs* renderArgs,
+ _In_ ITextBox* textBox,
+ _In_ IAdaptiveActionElement* inlineAction,
+ _COM_Outptr_ IUIElement** textBoxWithInlineAction)
+ {
+ ComPtr localTextBox(textBox);
+ ComPtr localInlineAction(inlineAction);
+
+ ABI::AdaptiveNamespace::ActionType actionType;
+ THROW_IF_FAILED(localInlineAction->get_ActionType(&actionType));
+
+ ComPtr hostConfig;
+ THROW_IF_FAILED(renderContext->get_HostConfig(&hostConfig));
+
+ // Inline ShowCards are not supported for inline actions
+ if (WarnForInlineShowCard(renderContext, localInlineAction.Get(), L"Inline ShowCard not supported for InlineAction"))
+ {
+ THROW_IF_FAILED(localTextBox.CopyTo(textBoxWithInlineAction));
+ return;
+ }
+
+ // Create a grid to hold the text box and the action button
+ ComPtr gridStatics;
+ THROW_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid).Get(), &gridStatics));
+
+ ComPtr xamlGrid =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid));
+ ComPtr> columnDefinitions;
+ THROW_IF_FAILED(xamlGrid->get_ColumnDefinitions(&columnDefinitions));
+ ComPtr gridAsPanel;
+ THROW_IF_FAILED(xamlGrid.As(&gridAsPanel));
+
+ // Create the first column and add the text box to it
+ ComPtr textBoxColumnDefinition = XamlHelpers::CreateXamlClass(
+ HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition));
+ THROW_IF_FAILED(textBoxColumnDefinition->put_Width({1, GridUnitType::GridUnitType_Star}));
+ THROW_IF_FAILED(columnDefinitions->Append(textBoxColumnDefinition.Get()));
+
+ ComPtr textBoxAsFrameworkElement;
+ THROW_IF_FAILED(localTextBox.As(&textBoxAsFrameworkElement));
+
+ THROW_IF_FAILED(gridStatics->SetColumn(textBoxAsFrameworkElement.Get(), 0));
+ XamlHelpers::AppendXamlElementToPanel(textBox, gridAsPanel.Get());
+
+ // Create a separator column
+ ComPtr separatorColumnDefinition = XamlHelpers::CreateXamlClass(
+ HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition));
+ THROW_IF_FAILED(separatorColumnDefinition->put_Width({1.0, GridUnitType::GridUnitType_Auto}));
+ THROW_IF_FAILED(columnDefinitions->Append(separatorColumnDefinition.Get()));
+
+ UINT spacingSize;
+ THROW_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig.Get(), ABI::AdaptiveNamespace::Spacing::Default, &spacingSize));
+
+ auto separator = XamlHelpers::CreateSeparator(renderContext, spacingSize, 0, {0}, false);
+
+ ComPtr separatorAsFrameworkElement;
+ THROW_IF_FAILED(separator.As(&separatorAsFrameworkElement));
+
+ THROW_IF_FAILED(gridStatics->SetColumn(separatorAsFrameworkElement.Get(), 1));
+ XamlHelpers::AppendXamlElementToPanel(separator.Get(), gridAsPanel.Get());
+
+ // Create a column for the button
+ ComPtr inlineActionColumnDefinition = XamlHelpers::CreateXamlClass(
+ HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition));
+ THROW_IF_FAILED(inlineActionColumnDefinition->put_Width({0, GridUnitType::GridUnitType_Auto}));
+ THROW_IF_FAILED(columnDefinitions->Append(inlineActionColumnDefinition.Get()));
+
+ // Create a text box with the action title. This will be the tool tip if there's an icon
+ // or the content of the button otherwise
+ ComPtr titleTextBlock =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock));
+ HString title;
+ THROW_IF_FAILED(localInlineAction->get_Title(title.GetAddressOf()));
+ THROW_IF_FAILED(titleTextBlock->put_Text(title.Get()));
+
+ HString iconUrl;
+ THROW_IF_FAILED(localInlineAction->get_IconUrl(iconUrl.GetAddressOf()));
+ ComPtr actionUIElement;
+ if (iconUrl != nullptr)
+ {
+ // Render the icon using the adaptive image renderer
+ ComPtr elementRenderers;
+ THROW_IF_FAILED(renderContext->get_ElementRenderers(&elementRenderers));
+ ComPtr imageRenderer;
+ THROW_IF_FAILED(elementRenderers->Get(HStringReference(L"Image").Get(), &imageRenderer));
+
+ ComPtr adaptiveImage;
+ THROW_IF_FAILED(MakeAndInitialize(&adaptiveImage));
+
+ THROW_IF_FAILED(adaptiveImage->put_Url(iconUrl.Get()));
+
+ ComPtr adaptiveImageAsElement;
+ THROW_IF_FAILED(adaptiveImage.As(&adaptiveImageAsElement));
+
+ THROW_IF_FAILED(imageRenderer->Render(adaptiveImageAsElement.Get(), renderContext, renderArgs, &actionUIElement));
+
+ // Add the tool tip
+ ComPtr toolTip =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ToolTip));
+ ComPtr toolTipAsContentControl;
+ THROW_IF_FAILED(toolTip.As(&toolTipAsContentControl));
+ THROW_IF_FAILED(toolTipAsContentControl->put_Content(titleTextBlock.Get()));
+
+ ComPtr toolTipService;
+ THROW_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ToolTipService).Get(),
+ &toolTipService));
+
+ ComPtr actionAsDependencyObject;
+ THROW_IF_FAILED(actionUIElement.As(&actionAsDependencyObject));
+
+ THROW_IF_FAILED(toolTipService->SetToolTip(actionAsDependencyObject.Get(), toolTip.Get()));
+ }
+ else
+ {
+ // If there's no icon, just use the title text. Put it centered in a grid so it is
+ // centered relative to the text box.
+ ComPtr textBlockAsFrameworkElement;
+ THROW_IF_FAILED(titleTextBlock.As(&textBlockAsFrameworkElement));
+ THROW_IF_FAILED(textBlockAsFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Center));
+
+ ComPtr titleGrid =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid));
+ ComPtr panel;
+ THROW_IF_FAILED(titleGrid.As(&panel));
+ XamlHelpers::AppendXamlElementToPanel(titleTextBlock.Get(), panel.Get());
+
+ THROW_IF_FAILED(panel.As(&actionUIElement));
+ }
+
+ // Make the action the same size as the text box
+ EventRegistrationToken eventToken;
+ THROW_IF_FAILED(textBoxAsFrameworkElement->add_Loaded(
+ Callback([actionUIElement, textBoxAsFrameworkElement](IInspectable* /*sender*/, IRoutedEventArgs *
+ /*args*/) -> HRESULT {
+ ComPtr actionFrameworkElement;
+ RETURN_IF_FAILED(actionUIElement.As(&actionFrameworkElement));
+
+ return ActionHelpers::SetMatchingHeight(actionFrameworkElement.Get(), textBoxAsFrameworkElement.Get());
+ }).Get(),
+ &eventToken));
+
+ // Wrap the action in a button
+ ComPtr touchTargetUIElement;
+ WrapInTouchTarget(nullptr, actionUIElement.Get(), localInlineAction.Get(), renderContext, false, L"Adaptive.Input.Text.InlineAction", &touchTargetUIElement);
+
+ ComPtr touchTargetFrameworkElement;
+ THROW_IF_FAILED(touchTargetUIElement.As(&touchTargetFrameworkElement));
+
+ // Align to bottom so the icon stays with the bottom of the text box as it grows in the multiline case
+ THROW_IF_FAILED(touchTargetFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Bottom));
+
+ // Add the action to the column
+ THROW_IF_FAILED(gridStatics->SetColumn(touchTargetFrameworkElement.Get(), 2));
+ XamlHelpers::AppendXamlElementToPanel(touchTargetFrameworkElement.Get(), gridAsPanel.Get());
+
+ // If this isn't a multiline input, enter should invoke the action
+ ComPtr actionInvoker;
+ THROW_IF_FAILED(renderContext->get_ActionInvoker(&actionInvoker));
+
+ boolean isMultiLine;
+ THROW_IF_FAILED(textBox->get_AcceptsReturn(&isMultiLine));
+
+ if (!isMultiLine)
+ {
+ ComPtr textBoxAsUIElement;
+ THROW_IF_FAILED(localTextBox.As(&textBoxAsUIElement));
+
+ EventRegistrationToken keyDownEventToken;
+ THROW_IF_FAILED(textBoxAsUIElement->add_KeyDown(
+ Callback([actionInvoker, localInlineAction](IInspectable* /*sender*/, IKeyRoutedEventArgs* args) -> HRESULT {
+ return HandleKeydownForInlineAction(args, actionInvoker.Get(), localInlineAction.Get());
+ }).Get(),
+ &keyDownEventToken));
+ }
+
+ THROW_IF_FAILED(xamlGrid.CopyTo(textBoxWithInlineAction));
+ }
+
+ void WrapInTouchTarget(_In_ IAdaptiveCardElement* adaptiveCardElement,
+ _In_ IUIElement* elementToWrap,
+ _In_ IAdaptiveActionElement* action,
+ _In_ IAdaptiveRenderContext* renderContext,
+ bool fullWidth,
+ const std::wstring& style,
+ _COM_Outptr_ IUIElement** finalElement)
+ {
+ ComPtr hostConfig;
+ THROW_IF_FAILED(renderContext->get_HostConfig(&hostConfig));
+
+ if (ActionHelpers::WarnForInlineShowCard(renderContext, action, L"Inline ShowCard not supported for SelectAction"))
+ {
+ // Was inline show card, so don't wrap the element and just return
+ ComPtr localElementToWrap(elementToWrap);
+ localElementToWrap.CopyTo(finalElement);
+ return;
+ }
+
+ ComPtr button =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Button));
+
+ ComPtr buttonAsContentControl;
+ THROW_IF_FAILED(button.As(&buttonAsContentControl));
+ THROW_IF_FAILED(buttonAsContentControl->put_Content(elementToWrap));
+
+ ComPtr spacingConfig;
+ THROW_IF_FAILED(hostConfig->get_Spacing(&spacingConfig));
+
+ UINT32 cardPadding = 0;
+ if (fullWidth)
+ {
+ THROW_IF_FAILED(spacingConfig->get_Padding(&cardPadding));
+ }
+
+ ComPtr buttonAsFrameworkElement;
+ THROW_IF_FAILED(button.As(&buttonAsFrameworkElement));
+
+ // We want the hit target to equally split the vertical space above and below the current item.
+ // However, all we know is the spacing of the current item, which only applies to the spacing above.
+ // We don't know what the spacing of the NEXT element will be, so we can't calculate the correct spacing
+ // below. For now, we'll simply assume the bottom spacing is the same as the top. NOTE: Only apply spacings
+ // (padding, margin) for adaptive card elements to avoid adding spacings to card-level selectAction.
+ if (adaptiveCardElement != nullptr)
+ {
+ ABI::AdaptiveNamespace::Spacing elementSpacing;
+ THROW_IF_FAILED(adaptiveCardElement->get_Spacing(&elementSpacing));
+ UINT spacingSize;
+ THROW_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig.Get(), elementSpacing, &spacingSize));
+ double topBottomPadding = spacingSize / 2.0;
+
+ // For button padding, we apply the cardPadding and topBottomPadding (and then we negate these in the margin)
+ ComPtr buttonAsControl;
+ THROW_IF_FAILED(button.As(&buttonAsControl));
+ THROW_IF_FAILED(buttonAsControl->put_Padding({(double)cardPadding, topBottomPadding, (double)cardPadding, topBottomPadding}));
+
+ double negativeCardMargin = cardPadding * -1.0;
+ double negativeTopBottomMargin = topBottomPadding * -1.0;
+
+ THROW_IF_FAILED(buttonAsFrameworkElement->put_Margin(
+ {negativeCardMargin, negativeTopBottomMargin, negativeCardMargin, negativeTopBottomMargin}));
+ }
+
+ // Style the hit target button
+ THROW_IF_FAILED(
+ XamlHelpers::SetStyleFromResourceDictionary(renderContext, style.c_str(), buttonAsFrameworkElement.Get()));
+
+ if (action != nullptr)
+ {
+ // If we have an action, use the title for the AutomationProperties.Name
+ HString title;
+ THROW_IF_FAILED(action->get_Title(title.GetAddressOf()));
+
+ ComPtr buttonAsDependencyObject;
+ THROW_IF_FAILED(button.As(&buttonAsDependencyObject));
+
+ ComPtr automationPropertiesStatics;
+ THROW_IF_FAILED(
+ GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Automation_AutomationProperties).Get(),
+ &automationPropertiesStatics));
+
+ THROW_IF_FAILED(automationPropertiesStatics->SetName(buttonAsDependencyObject.Get(), title.Get()));
+
+ WireButtonClickToAction(button.Get(), action, renderContext);
+ }
+
+ THROW_IF_FAILED(button.CopyTo(finalElement));
+ }
+
+ void WireButtonClickToAction(_In_ IButton* button, _In_ IAdaptiveActionElement* action, _In_ IAdaptiveRenderContext* renderContext)
+ {
+ // Note that this method currently doesn't support inline show card actions, it
+ // assumes the caller won't call this method if inline show card is specified.
+ ComPtr localButton(button);
+ ComPtr actionInvoker;
+ THROW_IF_FAILED(renderContext->get_ActionInvoker(&actionInvoker));
+ ComPtr strongAction(action);
+
+ // Add click handler
+ ComPtr buttonBase;
+ THROW_IF_FAILED(localButton.As(&buttonBase));
+
+ EventRegistrationToken clickToken;
+ THROW_IF_FAILED(buttonBase->add_Click(Callback([strongAction, actionInvoker](IInspectable* /*sender*/, IRoutedEventArgs *
+ /*args*/) -> HRESULT {
+ THROW_IF_FAILED(actionInvoker->SendActionEvent(strongAction.Get()));
+ return S_OK;
+ }).Get(),
+ &clickToken));
+ }
+
+ void HandleSelectAction(_In_ IAdaptiveCardElement* adaptiveCardElement,
+ _In_ IAdaptiveActionElement* selectAction,
+ _In_ IAdaptiveRenderContext* renderContext,
+ _In_ IUIElement* uiElement,
+ bool supportsInteractivity,
+ bool fullWidthTouchTarget,
+ _COM_Outptr_ IUIElement** outUiElement)
+ {
+ if (selectAction != nullptr && supportsInteractivity)
+ {
+ WrapInTouchTarget(adaptiveCardElement, uiElement, selectAction, renderContext, fullWidthTouchTarget, L"Adaptive.SelectAction", outUiElement);
+ }
+ else
+ {
+ if (selectAction != nullptr)
+ {
+ renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported,
+ HStringReference(L"SelectAction present, but Interactivity is not supported").Get());
+ }
+
+ ComPtr localUiElement(uiElement);
+ THROW_IF_FAILED(localUiElement.CopyTo(outUiElement));
+ }
+ }
+
+ HRESULT BuildActions(_In_ IAdaptiveCard* adaptiveCard,
+ _In_ IVector* children,
+ _In_ IPanel* bodyPanel,
+ bool insertSeparator,
+ _In_ IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs)
+ {
+ ComPtr hostConfig;
+ RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig));
+ ComPtr actionsConfig;
+ RETURN_IF_FAILED(hostConfig->get_Actions(actionsConfig.GetAddressOf()));
+
+ // Create a separator between the body and the actions
+ if (insertSeparator)
+ {
+ ABI::AdaptiveNamespace::Spacing spacing;
+ RETURN_IF_FAILED(actionsConfig->get_Spacing(&spacing));
+
+ UINT spacingSize;
+ RETURN_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig.Get(), spacing, &spacingSize));
+
+ ABI::Windows::UI::Color color = {0};
+ auto separator = XamlHelpers::CreateSeparator(renderContext, spacingSize, 0, color);
+ XamlHelpers::AppendXamlElementToPanel(separator.Get(), bodyPanel);
+ }
+
+ ComPtr actionSetControl;
+ RETURN_IF_FAILED(BuildActionSetHelper(adaptiveCard, nullptr, children, renderContext, renderArgs, &actionSetControl));
+
+ XamlHelpers::AppendXamlElementToPanel(actionSetControl.Get(), bodyPanel);
+ return S_OK;
+ }
+
+ HRESULT BuildActionSetHelper(_In_opt_ ABI::AdaptiveNamespace::IAdaptiveCard* adaptiveCard,
+ _In_opt_ IAdaptiveActionSet* adaptiveActionSet,
+ _In_ IVector* children,
+ _In_ IAdaptiveRenderContext* renderContext,
+ _In_ IAdaptiveRenderArgs* renderArgs,
+ _Outptr_ IUIElement** actionSetControl)
+ {
+ ComPtr hostConfig;
+ RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig));
+ ComPtr actionsConfig;
+ RETURN_IF_FAILED(hostConfig->get_Actions(actionsConfig.GetAddressOf()));
+
+ ABI::AdaptiveNamespace::ActionAlignment actionAlignment;
+ RETURN_IF_FAILED(actionsConfig->get_ActionAlignment(&actionAlignment));
+
+ ABI::AdaptiveNamespace::ActionsOrientation actionsOrientation;
+ RETURN_IF_FAILED(actionsConfig->get_ActionsOrientation(&actionsOrientation));
+
+ // Declare the panel that will host the buttons
+ ComPtr actionsPanel;
+ ComPtr> columnDefinitions;
+
+ if (actionAlignment == ABI::AdaptiveNamespace::ActionAlignment::Stretch &&
+ actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal)
+ {
+ // If stretch alignment and orientation is horizontal, we use a grid with equal column widths to achieve
+ // stretch behavior. For vertical orientation, we'll still just use a stack panel since the concept of
+ // stretching buttons height isn't really valid, especially when the height of cards are typically dynamic.
+ ComPtr actionsGrid =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid));
+ RETURN_IF_FAILED(actionsGrid->get_ColumnDefinitions(&columnDefinitions));
+ RETURN_IF_FAILED(actionsGrid.As(&actionsPanel));
+ }
+ else
+ {
+ // Create a stack panel for the action buttons
+ ComPtr actionStackPanel =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel));
+
+ auto uiOrientation = (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal) ?
+ Orientation::Orientation_Horizontal :
+ Orientation::Orientation_Vertical;
+
+ RETURN_IF_FAILED(actionStackPanel->put_Orientation(uiOrientation));
+
+ ComPtr actionsFrameworkElement;
+ RETURN_IF_FAILED(actionStackPanel.As(&actionsFrameworkElement));
+
+ switch (actionAlignment)
+ {
+ case ABI::AdaptiveNamespace::ActionAlignment::Center:
+ RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Center));
+ break;
+ case ABI::AdaptiveNamespace::ActionAlignment::Left:
+ RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Left));
+ break;
+ case ABI::AdaptiveNamespace::ActionAlignment::Right:
+ RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Right));
+ break;
+ case ABI::AdaptiveNamespace::ActionAlignment::Stretch:
+ RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Stretch));
+ break;
+ }
+
+ // Add the action buttons to the stack panel
+ RETURN_IF_FAILED(actionStackPanel.As(&actionsPanel));
+ }
+
+ Thickness buttonMargin;
+ RETURN_IF_FAILED(ActionHelpers::GetButtonMargin(actionsConfig.Get(), buttonMargin));
+ if (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal)
+ {
+ // Negate the spacing on the sides so the left and right buttons are flush on the side.
+ // We do NOT remove the margin from the individual button itself, since that would cause
+ // the equal columns stretch behavior to not have equal columns (since the first and last
+ // button would be narrower without the same margins as its peers).
+ ComPtr actionsPanelAsFrameworkElement;
+ RETURN_IF_FAILED(actionsPanel.As(&actionsPanelAsFrameworkElement));
+ RETURN_IF_FAILED(actionsPanelAsFrameworkElement->put_Margin({buttonMargin.Left * -1, 0, buttonMargin.Right * -1, 0}));
+ }
+ else
+ {
+ // Negate the spacing on the top and bottom so the first and last buttons don't have extra padding
+ ComPtr actionsPanelAsFrameworkElement;
+ RETURN_IF_FAILED(actionsPanel.As(&actionsPanelAsFrameworkElement));
+ RETURN_IF_FAILED(actionsPanelAsFrameworkElement->put_Margin({0, buttonMargin.Top * -1, 0, buttonMargin.Bottom * -1}));
+ }
+
+ UINT32 maxActions;
+ RETURN_IF_FAILED(actionsConfig->get_MaxActions(&maxActions));
+
+ bool allActionsHaveIcons{true};
+ XamlHelpers::IterateOverVector(children, [&](IAdaptiveActionElement* child) {
+ HString iconUrl;
+ RETURN_IF_FAILED(child->get_IconUrl(iconUrl.GetAddressOf()));
+
+ if (WindowsIsStringEmpty(iconUrl.Get()))
+ {
+ allActionsHaveIcons = false;
+ }
+ return S_OK;
+ });
+
+ UINT currentAction = 0;
+
+ RETURN_IF_FAILED(renderArgs->put_AllowAboveTitleIconPlacement(allActionsHaveIcons));
+
+ std::shared_ptr>> allShowCards = std::make_shared>>();
+ ComPtr showCardsStackPanel =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel));
+ ComPtr gridStatics;
+ RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid).Get(), &gridStatics));
+ XamlHelpers::IterateOverVector(children, [&](IAdaptiveActionElement* child) {
+ if (currentAction < maxActions)
+ {
+ // Render each action using the registered renderer
+ ComPtr action(child);
+ ComPtr actionRegistration;
+ RETURN_IF_FAILED(renderContext->get_ActionRenderers(&actionRegistration));
+
+ ComPtr renderer;
+ while (!renderer)
+ {
+ HString actionTypeString;
+ RETURN_IF_FAILED(action->get_ActionTypeString(actionTypeString.GetAddressOf()));
+ RETURN_IF_FAILED(actionRegistration->Get(actionTypeString.Get(), &renderer));
+ if (!renderer)
+ {
+ ABI::AdaptiveNamespace::FallbackType actionFallbackType;
+ action->get_FallbackType(&actionFallbackType);
+ switch (actionFallbackType)
+ {
+ case ABI::AdaptiveNamespace::FallbackType::Drop:
+ {
+ RETURN_IF_FAILED(XamlHelpers::WarnForFallbackDrop(renderContext, actionTypeString.Get()));
+ return S_OK;
+ }
+
+ case ABI::AdaptiveNamespace::FallbackType::Content:
+ {
+ ComPtr actionFallback;
+ RETURN_IF_FAILED(action->get_FallbackContent(&actionFallback));
+
+ HString fallbackTypeString;
+ RETURN_IF_FAILED(actionFallback->get_ActionTypeString(fallbackTypeString.GetAddressOf()));
+ RETURN_IF_FAILED(XamlHelpers::WarnForFallbackContentElement(renderContext,
+ actionTypeString.Get(),
+ fallbackTypeString.Get()));
+
+ action = actionFallback;
+ break;
+ }
+
+ case ABI::AdaptiveNamespace::FallbackType::None:
+ default:
+ return E_FAIL;
+ }
+ }
+ }
+
+ ComPtr actionControl;
+ RETURN_IF_FAILED(renderer->Render(action.Get(), renderContext, renderArgs, &actionControl));
+
+ XamlHelpers::AppendXamlElementToPanel(actionControl.Get(), actionsPanel.Get());
+
+ ABI::AdaptiveNamespace::ActionType actionType;
+ RETURN_IF_FAILED(action->get_ActionType(&actionType));
+
+ // Build inline show cards if needed
+ if (actionType == ABI::AdaptiveNamespace::ActionType_ShowCard)
+ {
+ ComPtr uiShowCard;
+
+ ComPtr showCardActionConfig;
+ RETURN_IF_FAILED(actionsConfig->get_ShowCard(&showCardActionConfig));
+
+ ABI::AdaptiveNamespace::ActionMode showCardActionMode;
+ RETURN_IF_FAILED(showCardActionConfig->get_ActionMode(&showCardActionMode));
+
+ if (showCardActionMode == ABI::AdaptiveNamespace::ActionMode::Inline)
+ {
+ ComPtr showCardAction;
+ RETURN_IF_FAILED(action.As(&showCardAction));
+
+ ComPtr showCard;
+ RETURN_IF_FAILED(showCardAction->get_Card(&showCard));
+
+ RETURN_IF_FAILED(AdaptiveShowCardActionRenderer::BuildShowCard(
+ showCard.Get(), renderContext, renderArgs, (adaptiveActionSet == nullptr), uiShowCard.GetAddressOf()));
+
+ ComPtr showCardsPanel;
+ RETURN_IF_FAILED(showCardsStackPanel.As(&showCardsPanel));
+ XamlHelpers::AppendXamlElementToPanel(uiShowCard.Get(), showCardsPanel.Get());
+
+ if (adaptiveActionSet)
+ {
+ RETURN_IF_FAILED(
+ renderContext->AddInlineShowCard(adaptiveActionSet, showCardAction.Get(), uiShowCard.Get()));
+ }
+ else
+ {
+ ComPtr contextImpl =
+ PeekInnards(renderContext);
+
+ RETURN_IF_FAILED(
+ contextImpl->AddInlineShowCard(adaptiveCard, showCardAction.Get(), uiShowCard.Get()));
+ }
+ }
+ }
+
+ if (columnDefinitions != nullptr)
+ {
+ // If using the equal width columns, we'll add a column and assign the column
+ ComPtr columnDefinition = XamlHelpers::CreateXamlClass(
+ HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition));
+ RETURN_IF_FAILED(columnDefinition->put_Width({1.0, GridUnitType::GridUnitType_Star}));
+ RETURN_IF_FAILED(columnDefinitions->Append(columnDefinition.Get()));
+
+ ComPtr actionFrameworkElement;
+ THROW_IF_FAILED(actionControl.As(&actionFrameworkElement));
+ THROW_IF_FAILED(gridStatics->SetColumn(actionFrameworkElement.Get(), currentAction));
+ }
+ }
+ else
+ {
+ renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::MaxActionsExceeded,
+ HStringReference(L"Some actions were not rendered due to exceeding the maximum number of actions allowed")
+ .Get());
+ }
+ currentAction++;
+ return S_OK;
+ });
+
+ // Reset icon placement value
+ RETURN_IF_FAILED(renderArgs->put_AllowAboveTitleIconPlacement(false));
+
+ ComPtr actionsPanelAsFrameworkElement;
+ RETURN_IF_FAILED(actionsPanel.As(&actionsPanelAsFrameworkElement));
+ RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext,
+ L"Adaptive.Actions",
+ actionsPanelAsFrameworkElement.Get()));
+
+ ComPtr actionSet =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel));
+ ComPtr actionSetAsPanel;
+ actionSet.As(&actionSetAsPanel);
+
+ // Add buttons and show cards to panel
+ XamlHelpers::AppendXamlElementToPanel(actionsPanel.Get(), actionSetAsPanel.Get());
+ XamlHelpers::AppendXamlElementToPanel(showCardsStackPanel.Get(), actionSetAsPanel.Get());
+
+ return actionSetAsPanel.CopyTo(actionSetControl);
+ }
+}
diff --git a/source/uwp/Renderer/lib/ActionHelpers.h b/source/uwp/Renderer/lib/ActionHelpers.h
new file mode 100644
index 0000000000..ae87299f48
--- /dev/null
+++ b/source/uwp/Renderer/lib/ActionHelpers.h
@@ -0,0 +1,73 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+#pragma once
+
+namespace AdaptiveNamespace::ActionHelpers
+{
+ HRESULT BuildAction(_In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* adaptiveActionElement,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs,
+ _Outptr_ ABI::Windows::UI::Xaml::IUIElement** actionControl);
+
+ HRESULT GetButtonMargin(_In_ ABI::AdaptiveNamespace::IAdaptiveActionsConfig* actionsConfig,
+ ABI::Windows::UI::Xaml::Thickness& buttonMargin) noexcept;
+
+ void ArrangeButtonContent(_In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveActionsConfig* actionsConfig,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ ABI::AdaptiveNamespace::ContainerStyle containerStyle,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveHostConfig* hostConfig,
+ bool allActionsHaveIcons,
+ _In_ ABI::Windows::UI::Xaml::Controls::IButton* button);
+
+ HRESULT SetMatchingHeight(_In_ ABI::Windows::UI::Xaml::IFrameworkElement* elementToChange,
+ _In_ ABI::Windows::UI::Xaml::IFrameworkElement* elementToMatch);
+
+ HRESULT HandleActionStyling(_In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* adaptiveActionElement,
+ _In_ ABI::Windows::UI::Xaml::IFrameworkElement* buttonFrameworkElement,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext);
+
+ bool WarnForInlineShowCard(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action,
+ const std::wstring& warning);
+
+ void HandleInlineAction(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs,
+ _In_ ABI::Windows::UI::Xaml::Controls::ITextBox* textBox,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* inlineAction,
+ _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** textBoxWithInlineAction);
+
+ void WireButtonClickToAction(_In_ ABI::Windows::UI::Xaml::Controls::IButton* button,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext);
+
+ void WrapInTouchTarget(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement* adaptiveCardElement,
+ _In_ ABI::Windows::UI::Xaml::IUIElement* elementToWrap,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ bool fullWidth,
+ const std::wstring& style,
+ _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** finalElement);
+
+ void HandleSelectAction(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement* adaptiveCardElement,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* selectAction,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::Windows::UI::Xaml::IUIElement* uiElement,
+ bool supportsInteractivity,
+ bool fullWidthTouchTarget,
+ _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** outUiElement);
+
+ HRESULT BuildActions(_In_ ABI::AdaptiveNamespace::IAdaptiveCard* adaptiveCard,
+ _In_ ABI::Windows::Foundation::Collections::IVector* children,
+ _In_ ABI::Windows::UI::Xaml::Controls::IPanel* bodyPanel,
+ bool insertSeparator,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs);
+
+ HRESULT BuildActionSetHelper(_In_opt_ ABI::AdaptiveNamespace::IAdaptiveCard* adaptiveCard,
+ _In_opt_ ABI::AdaptiveNamespace::IAdaptiveActionSet* adaptiveActionSet,
+ _In_ ABI::Windows::Foundation::Collections::IVector* children,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs,
+ _Outptr_ ABI::Windows::UI::Xaml::IUIElement** actionSetControl);
+}
diff --git a/source/uwp/Renderer/lib/AdaptiveActionElement.cpp b/source/uwp/Renderer/lib/AdaptiveActionElement.cpp
index 311ad7801c..fc41757084 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionElement.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveActionElement.cpp
@@ -2,7 +2,6 @@
// Licensed under the MIT License.
#include "pch.h"
#include "AdaptiveActionElement.h"
-#include "Util.h"
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
@@ -79,15 +78,9 @@ namespace AdaptiveNamespace
HRESULT AdaptiveActionElementBase::put_IconUrl(_In_ HSTRING iconUrl) { return m_iconUrl.Set(iconUrl); }
- IFACEMETHODIMP AdaptiveActionElementBase::get_Style(_Outptr_ HSTRING* style)
- {
- return m_style.CopyTo(style);
- }
+ IFACEMETHODIMP AdaptiveActionElementBase::get_Style(_Outptr_ HSTRING* style) { return m_style.CopyTo(style); }
- IFACEMETHODIMP AdaptiveActionElementBase::put_Style(_In_ HSTRING style)
- {
- return m_style.Set(style);
- }
+ IFACEMETHODIMP AdaptiveActionElementBase::put_Style(_In_ HSTRING style) { return m_style.Set(style); }
IFACEMETHODIMP AdaptiveActionElementBase::get_AdditionalProperties(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result)
{
diff --git a/source/uwp/Renderer/lib/AdaptiveActionElement.h b/source/uwp/Renderer/lib/AdaptiveActionElement.h
index a488e72628..2dcbf08e0c 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionElement.h
+++ b/source/uwp/Renderer/lib/AdaptiveActionElement.h
@@ -2,10 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include
-#include "Enums.h"
-
namespace AdaptiveNamespace
{
class DECLSPEC_UUID("CDCCC115-7C53-4A04-9F5B-754BBC00C80E") AdaptiveActionElementBase : public IUnknown
diff --git a/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp b/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp
index c98d39c2fc..53589cd586 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp
@@ -15,7 +15,8 @@ namespace AdaptiveNamespace
{
HRESULT AdaptiveActionInvoker::RuntimeClassInitialize() noexcept { return S_OK; }
- HRESULT AdaptiveActionInvoker::RuntimeClassInitialize(_In_ RenderedAdaptiveCard* renderResult) noexcept try
+ HRESULT AdaptiveActionInvoker::RuntimeClassInitialize(_In_ RenderedAdaptiveCard* renderResult) noexcept
+ try
{
ComPtr strongRenderResult = renderResult;
return strongRenderResult.AsWeak(&m_weakRenderResult);
diff --git a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp
index 8b17c39448..20dad1186d 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp
@@ -20,7 +20,8 @@ namespace AdaptiveNamespace
{
AdaptiveActionParserRegistration::AdaptiveActionParserRegistration() {}
- HRESULT AdaptiveActionParserRegistration::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveActionParserRegistration::RuntimeClassInitialize() noexcept
+ try
{
m_registration = std::make_shared();
m_sharedParserRegistration = std::make_shared();
@@ -38,7 +39,8 @@ namespace AdaptiveNamespace
}
CATCH_RETURN;
- HRESULT AdaptiveActionParserRegistration::Set(_In_ HSTRING type, _In_ IAdaptiveActionParser* Parser) noexcept try
+ HRESULT AdaptiveActionParserRegistration::Set(_In_ HSTRING type, _In_ IAdaptiveActionParser* Parser) noexcept
+ try
{
std::string typeString = HStringToUTF8(type);
@@ -56,7 +58,8 @@ namespace AdaptiveNamespace
}
CATCH_RETURN;
- HRESULT AdaptiveActionParserRegistration::Get(_In_ HSTRING type, _COM_Outptr_ IAdaptiveActionParser** result) noexcept try
+ HRESULT AdaptiveActionParserRegistration::Get(_In_ HSTRING type, _COM_Outptr_ IAdaptiveActionParser** result) noexcept
+ try
{
*result = nullptr;
@@ -69,7 +72,8 @@ namespace AdaptiveNamespace
}
CATCH_RETURN;
- HRESULT AdaptiveActionParserRegistration::Remove(_In_ HSTRING type) noexcept try
+ HRESULT AdaptiveActionParserRegistration::Remove(_In_ HSTRING type) noexcept
+ try
{
std::string typeString = HStringToUTF8(type);
diff --git a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h
index d2d5f34865..0a7527bce4 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h
+++ b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h
@@ -3,7 +3,7 @@
#pragma once
#include "AdaptiveCards.Rendering.Uwp.h"
-
+
namespace AdaptiveNamespace
{
constexpr char* c_upwActionParserRegistration = "AB3CC8B0-FF27-4859-A2AA-BCE2E729805";
diff --git a/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp b/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp
index e60a991411..daae972226 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp
@@ -12,7 +12,8 @@ namespace AdaptiveNamespace
{
AdaptiveActionRendererRegistration::AdaptiveActionRendererRegistration() {}
- HRESULT AdaptiveActionRendererRegistration::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveActionRendererRegistration::RuntimeClassInitialize() noexcept
+ try
{
m_registration = std::make_shared();
return S_OK;
diff --git a/source/uwp/Renderer/lib/AdaptiveActionSet.cpp b/source/uwp/Renderer/lib/AdaptiveActionSet.cpp
index 291c330f97..d2d0241c60 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionSet.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveActionSet.cpp
@@ -3,10 +3,6 @@
#include "pch.h"
#include "AdaptiveActionSet.h"
-#include "Util.h"
-#include "Vector.h"
-#include
-
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::AdaptiveNamespace;
@@ -14,21 +10,20 @@ using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::UI::Xaml;
using namespace ABI::Windows::UI::Xaml::Controls;
-namespace AdaptiveCards { namespace Rendering { namespace Uwp
+namespace AdaptiveNamespace
{
- AdaptiveActionSet::AdaptiveActionSet()
- {
- m_actions = Microsoft::WRL::Make>();
- }
+ AdaptiveActionSet::AdaptiveActionSet() { m_actions = Microsoft::WRL::Make>(); }
- HRESULT AdaptiveActionSet::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveActionSet::RuntimeClassInitialize() noexcept
+ try
{
std::shared_ptr ActionSet = std::make_shared();
return RuntimeClassInitialize(ActionSet);
- } CATCH_RETURN;
+ }
+ CATCH_RETURN;
- _Use_decl_annotations_
- HRESULT AdaptiveActionSet::RuntimeClassInitialize(const std::shared_ptr& sharedActionSet) try
+ HRESULT AdaptiveActionSet::RuntimeClassInitialize(const std::shared_ptr& sharedActionSet)
+ try
{
if (sharedActionSet == nullptr)
{
@@ -38,22 +33,22 @@ namespace AdaptiveCards { namespace Rendering { namespace Uwp
RETURN_IF_FAILED(GenerateActionsProjection(sharedActionSet->GetActions(), m_actions.Get()));
InitializeBaseElement(std::static_pointer_cast(sharedActionSet));
return S_OK;
- } CATCH_RETURN;
+ }
+ CATCH_RETURN;
- _Use_decl_annotations_
- HRESULT AdaptiveActionSet::get_Actions(IVector** items)
+ HRESULT AdaptiveActionSet::get_Actions(_COM_Outptr_ IVector** items)
{
return m_actions.CopyTo(items);
}
- _Use_decl_annotations_
- HRESULT AdaptiveActionSet::get_ElementType(ElementType* elementType)
+ HRESULT AdaptiveActionSet::get_ElementType(_Out_ ElementType* elementType)
{
*elementType = ElementType::ActionSet;
return S_OK;
}
- HRESULT AdaptiveActionSet::GetSharedModel(std::shared_ptr& sharedModel) try
+ HRESULT AdaptiveActionSet::GetSharedModel(std::shared_ptr& sharedModel)
+ try
{
std::shared_ptr actionSet = std::make_shared();
RETURN_IF_FAILED(SetSharedElementProperties(std::static_pointer_cast(actionSet)));
@@ -62,5 +57,6 @@ namespace AdaptiveCards { namespace Rendering { namespace Uwp
sharedModel = actionSet;
return S_OK;
- }CATCH_RETURN;
-}}}
+ }
+ CATCH_RETURN;
+}
diff --git a/source/uwp/Renderer/lib/AdaptiveActionSet.h b/source/uwp/Renderer/lib/AdaptiveActionSet.h
index c56d53d3fe..c130987536 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionSet.h
+++ b/source/uwp/Renderer/lib/AdaptiveActionSet.h
@@ -2,11 +2,7 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
#include "ActionSet.h"
-#include
-#include "AdaptiveCardElement.h"
namespace AdaptiveNamespace
{
@@ -17,11 +13,12 @@ namespace AdaptiveNamespace
Microsoft::WRL::CloakedIid,
Microsoft::WRL::CloakedIid>
{
- InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSet, BaseTrust)
+ InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSet, BaseTrust);
- public : AdaptiveActionSet();
+ public:
+ AdaptiveActionSet();
HRESULT RuntimeClassInitialize() noexcept;
- HRESULT RuntimeClassInitialize(_In_ const std::shared_ptr& sharedActionSet);
+ HRESULT RuntimeClassInitialize(const std::shared_ptr& sharedActionSet);
// IAdaptiveActionSet
IFACEMETHODIMP get_Actions(
@@ -108,7 +105,6 @@ namespace AdaptiveNamespace
return AdaptiveCardElementBase::get_Requirements(requirements);
}
-
IFACEMETHODIMP ToJson(_Out_ ABI::Windows::Data::Json::IJsonObject** result)
{
return AdaptiveCardElementBase::ToJson(result);
diff --git a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp
index 48fd18580a..f019ee57b8 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp
@@ -2,44 +2,64 @@
// Licensed under the MIT License.
#include "pch.h"
-#include "AdaptiveActionSet.h"
#include "AdaptiveActionSetRenderer.h"
+
+#include "ActionHelpers.h"
+#include "AdaptiveActionSet.h"
#include "AdaptiveElementParserRegistration.h"
-#include "enums.h"
-#include "Util.h"
-#include "XamlBuilder.h"
+#include "AdaptiveRenderArgs.h"
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::AdaptiveNamespace;
using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::UI::Xaml;
+using namespace ABI::Windows::UI::Xaml::Controls;
+using namespace ABI::Windows::UI::Xaml::Controls::Primitives;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveActionSetRenderer::RuntimeClassInitialize() noexcept try
- {
- return S_OK;
- }
- CATCH_RETURN;
-
- HRESULT AdaptiveActionSetRenderer::Render(_In_ IAdaptiveCardElement* cardElement,
- _In_ IAdaptiveRenderContext* renderContext,
- _In_ IAdaptiveRenderArgs* renderArgs,
- _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try
- {
- return XamlBuilder::BuildActionSet(cardElement, renderContext, renderArgs, result);
- }
- CATCH_RETURN;
+ HRESULT AdaptiveActionSetRenderer::RuntimeClassInitialize() noexcept { return S_OK; }
HRESULT AdaptiveActionSetRenderer::FromJson(
_In_ ABI::Windows::Data::Json::IJsonObject* jsonObject,
_In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration,
_In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration,
_In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings,
- _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try
+ _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept
+ try
{
return AdaptiveNamespace::FromJson(
jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element);
}
CATCH_RETURN;
+
+ HRESULT AdaptiveActionSetRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement,
+ _In_ IAdaptiveRenderContext* renderContext,
+ _In_ IAdaptiveRenderArgs* renderArgs,
+ _COM_Outptr_ IUIElement** actionSetControl) noexcept
+ try
+ {
+ ComPtr hostConfig;
+ RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig));
+
+ if (!XamlHelpers::SupportsInteractivity(hostConfig.Get()))
+ {
+ renderContext->AddWarning(
+ ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported,
+ HStringReference(L"ActionSet was stripped from card because interactivity is not supported").Get());
+ return S_OK;
+ }
+
+ ComPtr cardElement(adaptiveCardElement);
+ ComPtr adaptiveActionSet;
+ RETURN_IF_FAILED(cardElement.As(&adaptiveActionSet));
+
+ ComPtr> actions;
+ RETURN_IF_FAILED(adaptiveActionSet->get_Actions(&actions));
+
+ return ActionHelpers::BuildActionSetHelper(nullptr, adaptiveActionSet.Get(), actions.Get(), renderContext, renderArgs, actionSetControl);
+ }
+ CATCH_RETURN;
}
diff --git a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h
index 7ab0816f05..6e20f53f37 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h
+++ b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h
@@ -2,8 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
#include "ActionSet.h"
namespace AdaptiveNamespace
@@ -13,9 +11,10 @@ namespace AdaptiveNamespace
ABI::AdaptiveNamespace::IAdaptiveElementRenderer,
ABI::AdaptiveNamespace::IAdaptiveElementParser>
{
- InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSetRenderer, BaseTrust)
+ InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSetRenderer, BaseTrust);
- public : HRESULT RuntimeClassInitialize() noexcept;
+ public:
+ HRESULT RuntimeClassInitialize() noexcept;
IFACEMETHODIMP Render(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement* cardElement,
_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
diff --git a/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp b/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp
index 7477c811e5..69329cccc1 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp
@@ -3,7 +3,6 @@
#include "pch.h"
#include "AdaptiveActionsConfig.h"
#include "AdaptiveShowCardActionConfig.h"
-#include "Util.h"
using namespace Microsoft::WRL;
using namespace ABI::AdaptiveNamespace;
@@ -11,7 +10,8 @@ using namespace ABI::Windows::UI;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveActionsConfig::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveActionsConfig::RuntimeClassInitialize() noexcept
+ try
{
ActionsConfig actionsConfig;
return RuntimeClassInitialize(actionsConfig);
diff --git a/source/uwp/Renderer/lib/AdaptiveActionsConfig.h b/source/uwp/Renderer/lib/AdaptiveActionsConfig.h
index 2694b33521..fb600ed5df 100644
--- a/source/uwp/Renderer/lib/AdaptiveActionsConfig.h
+++ b/source/uwp/Renderer/lib/AdaptiveActionsConfig.h
@@ -2,10 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
-#include "HostConfig.h"
-
namespace AdaptiveNamespace
{
class AdaptiveActionsConfig
diff --git a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp
index 8d113a3855..3b96b4b471 100644
--- a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp
@@ -16,7 +16,8 @@ namespace AdaptiveNamespace
{
AdaptiveBackgroundImage::AdaptiveBackgroundImage() {}
- HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize() noexcept
+ try
{
std::shared_ptr image =
std::make_shared();
@@ -24,8 +25,8 @@ namespace AdaptiveNamespace
}
CATCH_RETURN;
- HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize(
- const std::shared_ptr& sharedImage) try
+ HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize(const std::shared_ptr& sharedImage)
+ try
{
if (sharedImage == nullptr)
{
@@ -85,7 +86,8 @@ namespace AdaptiveNamespace
return S_OK;
}
- HRESULT AdaptiveBackgroundImage::GetSharedModel(std::shared_ptr& sharedImage) try
+ HRESULT AdaptiveBackgroundImage::GetSharedModel(std::shared_ptr& sharedImage)
+ try
{
std::shared_ptr image =
std::make_shared();
diff --git a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h
index d5a1ccda4f..a877d81621 100644
--- a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h
+++ b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h
@@ -2,10 +2,7 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
#include "BackgroundImage.h"
-#include
namespace AdaptiveNamespace
{
diff --git a/source/uwp/Renderer/lib/AdaptiveCard.cpp b/source/uwp/Renderer/lib/AdaptiveCard.cpp
index 15956f3ec0..7985b54a0a 100644
--- a/source/uwp/Renderer/lib/AdaptiveCard.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveCard.cpp
@@ -25,8 +25,8 @@ using namespace Microsoft::WRL::Wrappers;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveCardStaticsImpl::FromJsonString(_In_ HSTRING adaptiveJson,
- _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try
+ HRESULT AdaptiveCardStaticsImpl::FromJsonString(_In_ HSTRING adaptiveJson, _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept
+ try
{
return FromJsonStringWithParserRegistration(adaptiveJson, nullptr, nullptr, parseResult);
}
@@ -35,7 +35,8 @@ namespace AdaptiveNamespace
HRESULT AdaptiveCardStaticsImpl::FromJsonStringWithParserRegistration(_In_ HSTRING adaptiveJson,
_In_ IAdaptiveElementParserRegistration* elementParserRegistration,
_In_ IAdaptiveActionParserRegistration* actionParserRegistration,
- _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try
+ _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept
+ try
{
*parseResult = nullptr;
@@ -46,8 +47,8 @@ namespace AdaptiveNamespace
}
CATCH_RETURN;
- HRESULT AdaptiveCardStaticsImpl::FromJson(_In_ IJsonObject* adaptiveJson,
- _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try
+ HRESULT AdaptiveCardStaticsImpl::FromJson(_In_ IJsonObject* adaptiveJson, _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept
+ try
{
return FromJsonWithParserRegistration(adaptiveJson, nullptr, nullptr, parseResult);
}
@@ -56,7 +57,8 @@ namespace AdaptiveNamespace
HRESULT AdaptiveCardStaticsImpl::FromJsonWithParserRegistration(_In_ IJsonObject* adaptiveJson,
_In_ IAdaptiveElementParserRegistration* elementParserRegistration,
_In_ IAdaptiveActionParserRegistration* actionParserRegistration,
- _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try
+ _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept
+ try
{
*parseResult = nullptr;
diff --git a/source/uwp/Renderer/lib/AdaptiveCard.h b/source/uwp/Renderer/lib/AdaptiveCard.h
index 602c058e89..adab26cb37 100644
--- a/source/uwp/Renderer/lib/AdaptiveCard.h
+++ b/source/uwp/Renderer/lib/AdaptiveCard.h
@@ -2,7 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
#include "SharedAdaptiveCard.h"
#include "AdaptiveBackgroundImage.h"
diff --git a/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp b/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp
index be46cf9486..2cbe57176a 100644
--- a/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp
@@ -10,7 +10,8 @@ using namespace ABI::Windows::UI;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveCardConfig::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveCardConfig::RuntimeClassInitialize() noexcept
+ try
{
AdaptiveSharedNamespace::AdaptiveCardConfig cardConfig;
return RuntimeClassInitialize(cardConfig);
diff --git a/source/uwp/Renderer/lib/AdaptiveCardConfig.h b/source/uwp/Renderer/lib/AdaptiveCardConfig.h
index b0b9704c6a..361f030536 100644
--- a/source/uwp/Renderer/lib/AdaptiveCardConfig.h
+++ b/source/uwp/Renderer/lib/AdaptiveCardConfig.h
@@ -2,10 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
-#include "HostConfig.h"
-
namespace AdaptiveNamespace
{
class AdaptiveCardConfig
diff --git a/source/uwp/Renderer/lib/AdaptiveCardElement.h b/source/uwp/Renderer/lib/AdaptiveCardElement.h
index 7a96538b8d..15c2fecb87 100644
--- a/source/uwp/Renderer/lib/AdaptiveCardElement.h
+++ b/source/uwp/Renderer/lib/AdaptiveCardElement.h
@@ -2,9 +2,8 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
#include "SemanticVersion.h"
-#include "Enums.h"
+#include "BaseElement.h"
namespace AdaptiveNamespace
{
@@ -41,7 +40,8 @@ namespace AdaptiveNamespace
IFACEMETHODIMP get_Height(_Out_ ABI::AdaptiveNamespace::HeightType* height);
IFACEMETHODIMP put_Height(ABI::AdaptiveNamespace::HeightType height);
- IFACEMETHODIMP get_Requirements(_COM_Outptr_ ABI::Windows::Foundation::Collections::IVector** requirements);
+ IFACEMETHODIMP get_Requirements(
+ _COM_Outptr_ ABI::Windows::Foundation::Collections::IVector** requirements);
IFACEMETHODIMP ToJson(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result);
diff --git a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp
index a0594d681d..e5d536bd53 100644
--- a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp
@@ -34,10 +34,6 @@
#include "DefaultResourceDictionary.h"
#include "InputValue.h"
#include "RenderedAdaptiveCard.h"
-#include "XamlHelpers.h"
-#include
-#include
-#include
using namespace concurrency;
using namespace Microsoft::WRL;
@@ -57,7 +53,8 @@ using namespace ABI::Windows::UI::Xaml::Media::Imaging;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveCardRenderer::RuntimeClassInitialize()
+ HRESULT AdaptiveCardRenderer::RuntimeClassInitialize() noexcept
+ try
{
RETURN_IF_FAILED(MakeAndInitialize(&m_xamlBuilder));
RETURN_IF_FAILED(MakeAndInitialize(&m_elementRendererRegistration));
@@ -70,6 +67,7 @@ namespace AdaptiveNamespace
UpdateActionSentimentResourceDictionary();
return MakeAndInitialize(&m_resourceResolvers);
}
+ CATCH_RETURN;
HRESULT AdaptiveCardRenderer::put_OverrideStyles(_In_ ABI::Windows::UI::Xaml::IResourceDictionary* overrideDictionary)
{
@@ -138,7 +136,7 @@ namespace AdaptiveNamespace
if (m_explicitDimensions)
{
- RETURN_IF_FAILED(m_xamlBuilder->SetFixedDimensions(m_desiredWidth, m_desiredHeight));
+ m_xamlBuilder->SetFixedDimensions(m_desiredWidth, m_desiredHeight);
}
ComPtr renderContext;
@@ -300,6 +298,24 @@ namespace AdaptiveNamespace
m_actionSentimentResourceDictionary = actionSentimentResourceDictionary;
}
+ HRESULT AdaptiveCardRenderer::TryInsertResourceToSentimentResourceDictionary(const std::wstring& resourceName,
+ _In_ IInspectable* value)
+ {
+ ComPtr propertyValueStatics;
+ RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(),
+ &propertyValueStatics));
+
+ ComPtr resourceKey;
+ RETURN_IF_FAILED(propertyValueStatics->CreateString(HStringReference(resourceName.c_str()).Get(), resourceKey.GetAddressOf()));
+
+ ComPtr> resourceDictionaryMap;
+ RETURN_IF_FAILED(m_actionSentimentResourceDictionary.As(&resourceDictionaryMap));
+
+ boolean replaced{};
+ RETURN_IF_FAILED(resourceDictionaryMap->Insert(resourceKey.Get(), value, &replaced));
+ return S_OK;
+ }
+
void AdaptiveCardRenderer::UpdateActionSentimentResourceDictionary()
{
ABI::Windows::UI::Color accentColor;
@@ -322,24 +338,20 @@ namespace AdaptiveNamespace
ABI::Windows::UI::Color lighterAttentionColor = GenerateLighterColor(attentionColor);
ComPtr accentColorBrush = XamlHelpers::GetSolidColorBrush(accentColor);
- THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(),
- L"Adaptive.Action.Positive.Button.Static.Background",
- accentColorBrush.Get()));
+ THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Positive.Button.Static.Background",
+ accentColorBrush.Get()));
ComPtr lightAccentColorBrush = XamlHelpers::GetSolidColorBrush(lighterAccentColor);
- THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(),
- L"Adaptive.Action.Positive.Button.MouseOver.Background",
- lightAccentColorBrush.Get()));
+ THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Positive.Button.MouseOver.Background",
+ lightAccentColorBrush.Get()));
ComPtr attentionColorBrush = XamlHelpers::GetSolidColorBrush(attentionColor);
- THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(),
- L"Adaptive.Action.Destructive.Button.Foreground",
- attentionColorBrush.Get()));
+ THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Destructive.Button.Foreground",
+ attentionColorBrush.Get()));
ComPtr lightAttentionColorBrush = XamlHelpers::GetSolidColorBrush(lighterAttentionColor);
- THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(),
- L"Adaptive.Action.Destructive.Button.MouseOver.Foreground",
- lightAttentionColorBrush.Get()));
+ THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Destructive.Button.MouseOver.Foreground",
+ lightAttentionColorBrush.Get()));
}
HRESULT AdaptiveCardRenderer::SetMergedDictionary()
diff --git a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h
index 4f82fcd2f5..1cea156e0a 100644
--- a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h
+++ b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h
@@ -18,7 +18,7 @@ namespace AdaptiveNamespace
AdaptiveRuntime(AdaptiveCardRenderer);
public:
- HRESULT RuntimeClassInitialize();
+ HRESULT RuntimeClassInitialize() noexcept;
// IAdaptiveCardRenderer
IFACEMETHODIMP put_OverrideStyles(_In_ ABI::Windows::UI::Xaml::IResourceDictionary* overrideDictionary);
@@ -62,6 +62,13 @@ namespace AdaptiveNamespace
IFACEMETHODIMP get_ResourceResolvers(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardResourceResolvers** value);
private:
+ HRESULT CreateAdaptiveCardFromJsonString(_In_ HSTRING adaptiveJson,
+ _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardParseResult** adaptiveCard);
+ void InitializeDefaultResourceDictionary();
+ void UpdateActionSentimentResourceDictionary();
+ HRESULT TryInsertResourceToSentimentResourceDictionary(const std::wstring& resourceName, _In_ IInspectable* value);
+ HRESULT SetMergedDictionary();
+
Microsoft::WRL::ComPtr m_overrideDictionary;
Microsoft::WRL::ComPtr m_defaultResourceDictionary;
Microsoft::WRL::ComPtr m_mergedResourceDictionary;
@@ -76,12 +83,6 @@ namespace AdaptiveNamespace
bool m_explicitDimensions = false;
UINT32 m_desiredWidth = 0;
UINT32 m_desiredHeight = 0;
-
- HRESULT CreateAdaptiveCardFromJsonString(_In_ HSTRING adaptiveJson,
- _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardParseResult** adaptiveCard);
- void InitializeDefaultResourceDictionary();
- void UpdateActionSentimentResourceDictionary();
- HRESULT SetMergedDictionary();
};
ActivatableClass(AdaptiveCardRenderer);
diff --git a/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp b/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp
index 3ae7b66045..1ef1cf1b26 100644
--- a/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp
@@ -9,7 +9,8 @@ using namespace ABI::Windows::Foundation;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveCardResourceResolvers::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveCardResourceResolvers::RuntimeClassInitialize() noexcept
+ try
{
return S_OK;
}
diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp b/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp
index 3cba8f7608..ab7a42df3c 100644
--- a/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp
@@ -14,7 +14,8 @@ using namespace ABI::Windows::UI::Xaml::Controls;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveChoiceInput::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveChoiceInput::RuntimeClassInitialize() noexcept
+ try
{
m_sharedChoiceInput = std::make_shared();
return S_OK;
diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceInput.h b/source/uwp/Renderer/lib/AdaptiveChoiceInput.h
index 889fc0fcef..d64834e90a 100644
--- a/source/uwp/Renderer/lib/AdaptiveChoiceInput.h
+++ b/source/uwp/Renderer/lib/AdaptiveChoiceInput.h
@@ -2,8 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
#include "ChoiceInput.h"
namespace AdaptiveNamespace
diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp
index edb996cad8..8e2afc9809 100644
--- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp
@@ -21,7 +21,8 @@ namespace AdaptiveNamespace
m_choices = Microsoft::WRL::Make>();
}
- HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize() noexcept
+ try
{
std::shared_ptr choiceSet =
std::make_shared();
@@ -29,7 +30,8 @@ namespace AdaptiveNamespace
}
CATCH_RETURN;
- HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize(const std::shared_ptr& sharedChoiceSetInput) try
+ HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize(const std::shared_ptr& sharedChoiceSetInput)
+ try
{
if (sharedChoiceSetInput == nullptr)
{
@@ -107,7 +109,8 @@ namespace AdaptiveNamespace
return S_OK;
}
- HRESULT AdaptiveChoiceSetInput::GetSharedModel(std::shared_ptr& sharedModel) try
+ HRESULT AdaptiveChoiceSetInput::GetSharedModel(std::shared_ptr& sharedModel)
+ try
{
std::shared_ptr choiceSet =
std::make_shared();
diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h
index 38220c38d0..71eb9f1359 100644
--- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h
+++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h
@@ -2,10 +2,7 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
#include "ChoiceSetInput.h"
-#include "Enums.h"
-#include
#include "AdaptiveInputElement.h"
namespace AdaptiveNamespace
diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp
index ec95ed970e..e092ba463d 100644
--- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp
@@ -5,29 +5,57 @@
#include "AdaptiveChoiceSetInput.h"
#include "AdaptiveChoiceSetInputRenderer.h"
#include "AdaptiveElementParserRegistration.h"
-#include "enums.h"
-#include "Util.h"
-#include "XamlBuilder.h"
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::AdaptiveNamespace;
using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::UI::Xaml;
+using namespace ABI::Windows::UI::Xaml::Controls;
+using namespace ABI::Windows::UI::Xaml::Controls::Primitives;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveChoiceSetInputRenderer::RuntimeClassInitialize() noexcept try
- {
- return S_OK;
- }
- CATCH_RETURN;
+ HRESULT AdaptiveChoiceSetInputRenderer::RuntimeClassInitialize() noexcept { return S_OK; }
- HRESULT AdaptiveChoiceSetInputRenderer::Render(_In_ IAdaptiveCardElement* cardElement,
+ HRESULT AdaptiveChoiceSetInputRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement,
_In_ IAdaptiveRenderContext* renderContext,
- _In_ IAdaptiveRenderArgs* renderArgs,
- _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try
+ _In_ IAdaptiveRenderArgs* /*renderArgs*/,
+ _COM_Outptr_ IUIElement** choiceInputSet) noexcept
+ try
{
- return XamlBuilder::BuildChoiceSetInput(cardElement, renderContext, renderArgs, result);
+ ComPtr hostConfig;
+ RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig));
+ if (!XamlHelpers::SupportsInteractivity(hostConfig.Get()))
+ {
+ renderContext->AddWarning(
+ ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported,
+ HStringReference(L"ChoiceSet was stripped from card because interactivity is not supported").Get());
+ return S_OK;
+ }
+
+ ComPtr cardElement(adaptiveCardElement);
+ ComPtr adaptiveChoiceSetInput;
+ RETURN_IF_FAILED(cardElement.As(&adaptiveChoiceSetInput));
+
+ ABI::AdaptiveNamespace::ChoiceSetStyle choiceSetStyle;
+ RETURN_IF_FAILED(adaptiveChoiceSetInput->get_ChoiceSetStyle(&choiceSetStyle));
+
+ boolean isMultiSelect;
+ RETURN_IF_FAILED(adaptiveChoiceSetInput->get_IsMultiSelect(&isMultiSelect));
+
+ if (choiceSetStyle == ABI::AdaptiveNamespace::ChoiceSetStyle_Compact && !isMultiSelect)
+ {
+ BuildCompactChoiceSetInput(renderContext, adaptiveChoiceSetInput.Get(), choiceInputSet);
+ }
+ else
+ {
+ BuildExpandedChoiceSetInput(renderContext, adaptiveChoiceSetInput.Get(), isMultiSelect, choiceInputSet);
+ }
+
+ XamlHelpers::AddInputValueToContext(renderContext, adaptiveCardElement, *choiceInputSet);
+ return S_OK;
}
CATCH_RETURN;
@@ -36,10 +64,183 @@ namespace AdaptiveNamespace
_In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration,
_In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration,
_In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings,
- _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try
+ _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept
+ try
{
return AdaptiveNamespace::FromJson(
jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element);
}
CATCH_RETURN;
+
+ std::vector AdaptiveChoiceSetInputRenderer::GetChoiceSetValueVector(_In_ IAdaptiveChoiceSetInput* adaptiveChoiceSetInput)
+ {
+ HString value;
+ THROW_IF_FAILED(adaptiveChoiceSetInput->get_Value(value.GetAddressOf()));
+
+ std::vector values;
+ std::string stdValue = HStringToUTF8(value.Get());
+ std::stringstream streamValue(stdValue);
+
+ while (streamValue.good())
+ {
+ std::string subString;
+ std::getline(streamValue, subString, ',');
+ values.push_back(std::move(subString));
+ }
+
+ return values;
+ }
+
+ bool AdaptiveChoiceSetInputRenderer::IsChoiceSelected(std::vector selectedValues, _In_ IAdaptiveChoiceInput* choice)
+ {
+ HString value;
+ THROW_IF_FAILED(choice->get_Value(value.GetAddressOf()));
+ std::string stdValue = HStringToUTF8(value.Get());
+ return std::find(selectedValues.begin(), selectedValues.end(), stdValue) != selectedValues.end();
+ }
+
+ HRESULT AdaptiveChoiceSetInputRenderer::BuildCompactChoiceSetInput(_In_ IAdaptiveRenderContext* renderContext,
+ _In_ IAdaptiveChoiceSetInput* adaptiveChoiceSetInput,
+ _COM_Outptr_ IUIElement** choiceInputSet)
+ {
+ ComPtr comboBox =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ComboBox));
+
+ // Set HorizontalAlignment to Stretch (defaults to Left for combo boxes)
+ ComPtr comboBoxAsFrameworkElement;
+ RETURN_IF_FAILED(comboBox.As(&comboBoxAsFrameworkElement));
+ RETURN_IF_FAILED(comboBoxAsFrameworkElement->put_HorizontalAlignment(HorizontalAlignment_Stretch));
+
+ ComPtr itemsControl;
+ RETURN_IF_FAILED(comboBox.As(&itemsControl));
+
+ ComPtr> items;
+ RETURN_IF_FAILED(itemsControl->get_Items(items.GetAddressOf()));
+
+ ComPtr> itemsVector;
+ RETURN_IF_FAILED(items.As(&itemsVector));
+
+ ComPtr> choices;
+ RETURN_IF_FAILED(adaptiveChoiceSetInput->get_Choices(&choices));
+
+ std::vector values = GetChoiceSetValueVector(adaptiveChoiceSetInput);
+ boolean wrap;
+ adaptiveChoiceSetInput->get_Wrap(&wrap);
+
+ int currentIndex = 0;
+ int selectedIndex = -1;
+ XamlHelpers::IterateOverVector(
+ choices.Get(), [¤tIndex, &selectedIndex, itemsVector, values, wrap](IAdaptiveChoiceInput* adaptiveChoiceInput) {
+ HString title;
+ RETURN_IF_FAILED(adaptiveChoiceInput->get_Title(title.GetAddressOf()));
+
+ ComPtr comboBoxItem = XamlHelpers::CreateXamlClass(
+ HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ComboBoxItem));
+
+ XamlHelpers::SetContent(comboBoxItem.Get(), title.Get(), wrap);
+
+ // If multiple values are specified, no option is selected
+ if (values.size() == 1 && IsChoiceSelected(values, adaptiveChoiceInput))
+ {
+ selectedIndex = currentIndex;
+ }
+
+ ComPtr inspectable;
+ RETURN_IF_FAILED(comboBoxItem.As(&inspectable));
+
+ RETURN_IF_FAILED(itemsVector->Append(inspectable.Get()));
+ currentIndex++;
+ return S_OK;
+ });
+
+ ComPtr selector;
+ RETURN_IF_FAILED(comboBox.As(&selector));
+ RETURN_IF_FAILED(selector->put_SelectedIndex(selectedIndex));
+
+ ComPtr comboBoxAsUIElement;
+ RETURN_IF_FAILED(comboBox.As(&comboBoxAsUIElement));
+ RETURN_IF_FAILED(XamlHelpers::AddHandledTappedEvent(comboBoxAsUIElement.Get()));
+
+ XamlHelpers::SetStyleFromResourceDictionary(renderContext,
+ L"Adaptive.Input.ChoiceSet.Compact",
+ comboBoxAsFrameworkElement.Get());
+
+ return comboBoxAsUIElement.CopyTo(choiceInputSet);
+ }
+
+ HRESULT AdaptiveChoiceSetInputRenderer::BuildExpandedChoiceSetInput(_In_ IAdaptiveRenderContext* renderContext,
+ _In_ IAdaptiveChoiceSetInput* adaptiveChoiceSetInput,
+ boolean isMultiSelect,
+ _COM_Outptr_ IUIElement** choiceInputSet)
+ {
+ ComPtr> choices;
+ RETURN_IF_FAILED(adaptiveChoiceSetInput->get_Choices(&choices));
+
+ ComPtr stackPanel =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel));
+ stackPanel->put_Orientation(Orientation::Orientation_Vertical);
+
+ ComPtr panel;
+ RETURN_IF_FAILED(stackPanel.As(&panel));
+
+ std::vector values = GetChoiceSetValueVector(adaptiveChoiceSetInput);
+
+ boolean wrap;
+ adaptiveChoiceSetInput->get_Wrap(&wrap);
+
+ XamlHelpers::IterateOverVector(
+ choices.Get(), [panel, isMultiSelect, renderContext, values, wrap](IAdaptiveChoiceInput* adaptiveChoiceInput) {
+ ComPtr choiceItem;
+ if (isMultiSelect)
+ {
+ ComPtr checkBox =
+ XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_CheckBox));
+ RETURN_IF_FAILED(checkBox.As(&choiceItem));
+
+ ComPtr frameworkElement;
+ RETURN_IF_FAILED(checkBox.As(&frameworkElement));
+ XamlHelpers::SetStyleFromResourceDictionary(renderContext,
+ L"Adaptive.Input.Choice.Multiselect",
+ frameworkElement.Get());
+
+ XamlHelpers::SetToggleValue(choiceItem.Get(), IsChoiceSelected(values, adaptiveChoiceInput));
+ }
+ else
+ {
+ ComPtr radioButton = XamlHelpers::CreateXamlClass(
+ HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_RadioButton));
+ RETURN_IF_FAILED(radioButton.As(&choiceItem));
+
+ ComPtr frameworkElement;
+ RETURN_IF_FAILED(radioButton.As(&frameworkElement));
+ XamlHelpers::SetStyleFromResourceDictionary(renderContext,
+ L"Adaptive.Input.Choice.SingleSelect",
+ frameworkElement.Get());
+
+ if (values.size() == 1)
+ {
+ // When isMultiSelect is false, only 1 specified value is accepted.
+ // Otherwise, leave all options unset
+ XamlHelpers::SetToggleValue(choiceItem.Get(), IsChoiceSelected(values, adaptiveChoiceInput));
+ }
+ }
+
+ HString title;
+ RETURN_IF_FAILED(adaptiveChoiceInput->get_Title(title.GetAddressOf()));
+ XamlHelpers::SetContent(choiceItem.Get(), title.Get(), wrap);
+
+ RETURN_IF_FAILED(XamlHelpers::AddHandledTappedEvent(choiceItem.Get()));
+
+ XamlHelpers::AppendXamlElementToPanel(choiceItem.Get(), panel.Get());
+ return S_OK;
+ });
+
+ ComPtr choiceSetAsFrameworkElement;
+ RETURN_IF_FAILED(stackPanel.As(&choiceSetAsFrameworkElement));
+ RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext,
+ L"Adaptive.Input.ChoiceSet.Expanded",
+ choiceSetAsFrameworkElement.Get()));
+
+ return stackPanel.CopyTo(choiceInputSet);
+ }
}
diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h
index af94926e9c..81785cd869 100644
--- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h
+++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h
@@ -2,8 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
#include "ChoiceSetInput.h"
namespace AdaptiveNamespace
@@ -28,6 +26,20 @@ namespace AdaptiveNamespace
_In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParsers,
_In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings,
_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept override;
+
+ private:
+ static std::vector GetChoiceSetValueVector(_In_ ABI::AdaptiveNamespace::IAdaptiveChoiceSetInput* adaptiveChoiceSetInput);
+ static bool IsChoiceSelected(std::vector selectedValues,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveChoiceInput* choice);
+
+ HRESULT BuildExpandedChoiceSetInput(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveChoiceSetInput* adaptiveChoiceSetInput,
+ boolean isMultiSelect,
+ _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** choiceInputSet);
+
+ HRESULT BuildCompactChoiceSetInput(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext,
+ _In_ ABI::AdaptiveNamespace::IAdaptiveChoiceSetInput* adaptiveChoiceSetInput,
+ _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** choiceInputSet);
};
ActivatableClass(AdaptiveChoiceSetInputRenderer);
diff --git a/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp b/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp
index 9a8609182b..4fb9dc2aed 100644
--- a/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp
@@ -11,7 +11,8 @@ using namespace ABI::Windows::UI;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveColorConfig::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveColorConfig::RuntimeClassInitialize() noexcept
+ try
{
ColorConfig colorConfig;
return RuntimeClassInitialize(colorConfig);
@@ -57,7 +58,6 @@ namespace AdaptiveNamespace
return m_highlightColors.CopyTo(highlightColors);
}
-
HRESULT AdaptiveColorConfig::put_HighlightColors(_In_ IAdaptiveHighlightColorConfig* highlightColors)
{
m_highlightColors = highlightColors;
diff --git a/source/uwp/Renderer/lib/AdaptiveColorConfig.h b/source/uwp/Renderer/lib/AdaptiveColorConfig.h
index fad0fa37e4..50bc759321 100644
--- a/source/uwp/Renderer/lib/AdaptiveColorConfig.h
+++ b/source/uwp/Renderer/lib/AdaptiveColorConfig.h
@@ -2,10 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
-#include "HostConfig.h"
-
namespace AdaptiveNamespace
{
class AdaptiveColorConfig
diff --git a/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp b/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp
index 966996f8fa..e1f8db2f78 100644
--- a/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp
@@ -9,7 +9,8 @@ using namespace ABI::AdaptiveNamespace;
namespace AdaptiveNamespace
{
- HRESULT AdaptiveColorsConfig::RuntimeClassInitialize() noexcept try
+ HRESULT AdaptiveColorsConfig::RuntimeClassInitialize() noexcept
+ try
{
ColorsConfig colorsConfig;
return RuntimeClassInitialize(colorsConfig);
diff --git a/source/uwp/Renderer/lib/AdaptiveColorsConfig.h b/source/uwp/Renderer/lib/AdaptiveColorsConfig.h
index b6d7643573..1fdcf9ba71 100644
--- a/source/uwp/Renderer/lib/AdaptiveColorsConfig.h
+++ b/source/uwp/Renderer/lib/AdaptiveColorsConfig.h
@@ -2,10 +2,6 @@
// Licensed under the MIT License.
#pragma once
-#include "AdaptiveCards.Rendering.Uwp.h"
-#include "Enums.h"
-#include "HostConfig.h"
-
namespace AdaptiveNamespace
{
class AdaptiveColorsConfig
diff --git a/source/uwp/Renderer/lib/AdaptiveColumn.cpp b/source/uwp/Renderer/lib/AdaptiveColumn.cpp
index 3b2c458170..562e2fb8ab 100644
--- a/source/uwp/Renderer/lib/AdaptiveColumn.cpp
+++ b/source/uwp/Renderer/lib/AdaptiveColumn.cpp
@@ -21,14 +21,16 @@ namespace AdaptiveNamespace
m_items = Microsoft::WRL::Make