-
Notifications
You must be signed in to change notification settings - Fork 541
/
AdaptiveActionSetRenderer.cs
183 lines (150 loc) · 8.88 KB
/
AdaptiveActionSetRenderer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace AdaptiveCards.Rendering.Wpf
{
public static class AdaptiveActionSetRenderer
{
public static FrameworkElement Render(AdaptiveActionSet actionSet, AdaptiveRenderContext context)
{
var outerActionSet = new Grid();
if (!context.Config.SupportsInteractivity)
return outerActionSet;
outerActionSet.Style = context.GetStyle("Adaptive.Container");
// Keep track of ContainerStyle.ForegroundColors before Container is rendered
AdaptiveRenderArgs parentRenderArgs = context.RenderArgs;
AdaptiveRenderArgs elementRenderArgs = new AdaptiveRenderArgs(parentRenderArgs);
AddRenderedActions(outerActionSet, actionSet.Actions, context, actionSet.InternalID);
return outerActionSet;
}
public static void AddRenderedActions(Grid uiContainer, IList<AdaptiveAction> actions, AdaptiveRenderContext context, AdaptiveInternalID actionSetId)
{
if (!context.Config.SupportsInteractivity)
return;
ActionsConfig actionsConfig = context.Config.Actions;
int maxActions = actionsConfig.MaxActions;
List<AdaptiveAction> actionsToProcess = GetActionsToProcess(actions, maxActions, context);
if (actionsToProcess.Any())
{
var uiActionBar = new UniformGrid();
if (actionsConfig.ActionsOrientation == ActionsOrientation.Horizontal)
uiActionBar.Columns = actionsToProcess.Count();
else
uiActionBar.Rows = actionsToProcess.Count();
uiActionBar.HorizontalAlignment = (HorizontalAlignment)Enum.Parse(typeof(HorizontalAlignment), actionsConfig.ActionAlignment.ToString());
uiActionBar.VerticalAlignment = VerticalAlignment.Bottom;
uiActionBar.Style = context.GetStyle("Adaptive.Actions");
// For vertical, we want to subtract the top margin of the first button
int topMargin = actionsConfig.ActionsOrientation == ActionsOrientation.Horizontal
? context.Config.GetSpacing(actionsConfig.Spacing)
: context.Config.GetSpacing(actionsConfig.Spacing) - actionsConfig.ButtonSpacing;
uiActionBar.Margin = new Thickness(0, topMargin, 0, 0);
uiContainer.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
Grid.SetRow(uiActionBar, uiContainer.RowDefinitions.Count - 1);
uiContainer.Children.Add(uiActionBar);
bool isInline = (actionsConfig.ShowCard.ActionMode == ShowCardActionMode.Inline);
int iPos = 0;
// See if all actions have icons, otherwise force the icon placement to the left
IconPlacement oldConfigIconPlacement = actionsConfig.IconPlacement;
bool allActionsHaveIcons = true;
foreach (AdaptiveAction action in actionsToProcess)
{
if (string.IsNullOrEmpty(action.IconUrl))
{
allActionsHaveIcons = false;
break;
}
}
if (!allActionsHaveIcons)
{
actionsConfig.IconPlacement = IconPlacement.LeftOfTitle;
}
// indicates showcard has not been seen if it's set false; meaningful only if it's used
// when inline is supported
bool hasSeenInlineShowCard = false;
foreach (AdaptiveAction action in actionsToProcess)
{
// add actions
var uiAction = context.Render(action) as Button;
if (uiAction == null)
{
context.Warnings.Add(new AdaptiveWarning(-1, $"action failed to render" +
$"and valid fallback wasn't present"));
continue;
}
if (actionsConfig.ActionsOrientation == ActionsOrientation.Horizontal)
{
if (uiActionBar.Children.Count > 0) // don't apply left margin to the first item
uiAction.Margin = new Thickness(actionsConfig.ButtonSpacing, 0, 0, 0);
}
else
{
uiAction.Margin = new Thickness(0, actionsConfig.ButtonSpacing, 0, 0);
}
if (actionsConfig.ActionsOrientation == ActionsOrientation.Horizontal)
Grid.SetColumn(uiAction, iPos++);
uiActionBar.Children.Add(uiAction);
if (action is AdaptiveShowCardAction showCardAction && isInline)
{
if (actionSetId != null)
{
// the button's context is used as key for retrieving the corresponding showcard
uiAction.SetContext(actionSetId);
if (!hasSeenInlineShowCard)
{
// Define a new row to contain all the show cards
uiContainer.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
// it's first showcard of the peers, create a new list
context.PeerShowCardsInActionSet[actionSetId] = new List<FrameworkElement>();
}
hasSeenInlineShowCard = true;
Grid uiShowCardContainer = new Grid();
uiShowCardContainer.Style = context.GetStyle("Adaptive.Actions.ShowCard");
uiShowCardContainer.DataContext = showCardAction;
uiShowCardContainer.Visibility = Visibility.Collapsed;
var padding = context.Config.Spacing.Padding;
// set negative margin to expand the wrapper to the edge of outer most card
uiShowCardContainer.Margin = new Thickness(-padding, actionsConfig.ShowCard.InlineTopMargin, -padding, -padding);
var showCardStyleConfig = context.Config.ContainerStyles.GetContainerStyleConfig(actionsConfig.ShowCard.Style);
uiShowCardContainer.Background = context.GetColorBrush(showCardStyleConfig.BackgroundColor);
// render the card
var uiShowCardWrapper = (Grid)context.Render(showCardAction.Card);
uiShowCardWrapper.Background = context.GetColorBrush("Transparent");
uiShowCardWrapper.DataContext = showCardAction;
uiShowCardContainer.Children.Add(uiShowCardWrapper);
context.ActionShowCards.Add(uiAction, uiShowCardContainer);
// added the rendered show card as a peer
context.PeerShowCardsInActionSet[actionSetId].Add(uiShowCardContainer);
// define where in the rows of the parent Grid the show card will occupy
// and add it to the parent
Grid.SetRow(uiShowCardContainer, uiContainer.RowDefinitions.Count - 1);
uiContainer.Children.Add(uiShowCardContainer);
}
else
{
context.Warnings.Add(new AdaptiveWarning(-1, $"button's corresponding showCard" +
$" couldn't be added since the action set the button belongs to has null as internal id"));
}
}
}
// Restore the iconPlacement for the context.
actionsConfig.IconPlacement = oldConfigIconPlacement;
}
}
private static List<AdaptiveAction> GetActionsToProcess(IList<AdaptiveAction> actions, int maxActions, AdaptiveRenderContext context)
{
// If the number of actions is bigger than maxActions, then log warning for it
if (actions.Count > maxActions)
{
context.Warnings.Add(new AdaptiveWarning((int)AdaptiveWarning.WarningStatusCode.MaxActionsExceeded, "Some actions were not rendered due to exceeding the maximum number of actions allowed"));
}
// just take the first maxActions actions
return actions.Take(maxActions).ToList();
}
}
}