private async void OnRenderAdaptiveCard(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); json = await client.GetStringAsync(new Uri("https://adaptivecard.azurewebsites.net/api/AppConsultAdaptiveCards?code=AzSEpdNE/P0c9OFIBjro2vSKwGIlLdBWdc53/jmR7Y9PX2l1Ks0/nQ==")); AdaptiveCardParseResult card = AdaptiveCard.FromJsonString(json); AdaptiveCardRenderer renderer = new AdaptiveCardRenderer(); var renderResult = renderer.RenderAdaptiveCard(card.AdaptiveCard); renderResult.Action += RenderResult_OnAction; if (renderResult != null) { MainPanel.Children.Add(renderResult.FrameworkElement); } }
private async static Task RenderAdaptiveCard(Attachment attachment) { // This is entirely optional, just shows how to render an adaptive card which in a console app isn't really very practical! try { AdaptiveCardParseResult result = AdaptiveCard.FromJson(attachment.Content.ToString()); var adaptiveCard = AdaptiveCard.FromJson(attachment.Content.ToString()); if (adaptiveCard != null) { // Create a host config with no interactivity // (buttons in images would be deceiving) AdaptiveHostConfig hostConfig = new AdaptiveHostConfig() { SupportsInteractivity = false }; // Create a renderer AdaptiveCardRenderer renderer = new AdaptiveCardRenderer(hostConfig); // Render the card to png RenderedAdaptiveCardImage renderedCard = await renderer.RenderCardToImageAsync(adaptiveCard.Card, createStaThread : true, cancellationToken : default(CancellationToken)); string fileName = $"{Guid.NewGuid()}.png"; using (var fileStream = File.Create(fileName)) { renderedCard.ImageStream.Seek(0, SeekOrigin.Begin); renderedCard.ImageStream.CopyTo(fileStream); } Console.WriteLine($"Adaptive Card rendered to {fileName} for debug purposes."); Process.Start(fileName); } Console.WriteLine($"Adaptive Card Speak Property: {adaptiveCard.Card.Speak}"); } catch (Exception) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Adaptive card not parsed"); Console.ForegroundColor = ConsoleColor.Gray; } }
protected async override Task OnTeamsMessagingExtensionCardButtonClickedAsync(ITurnContext <IInvokeActivity> turnContext, JObject cardData, CancellationToken cancellationToken) { //var reply = MessageFactory.Text("OnTeamsMessagingExtensionCardButtonClickedAsync Value: " + JsonConvert.SerializeObject(turnContext.Activity.Value)); var reply = Activity.CreateMessageActivity(); string card = "{\r\n \"type\": \"AdaptiveCard\",\r\n \"version\": \"1.0\",\r\n \"body\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/Firstresponsecolor.png\",\r\n \"width\": \"\"\r\n },\r\n {\r\n \"type\": \"ColumnSet\",\r\n \"columns\": [\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref1.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref2.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"1\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref3.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref4.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref5.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\"\r\n}"; AdaptiveCardParseResult result = AdaptiveCard.FromJson(card); Attachment attachment = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = result.Card }; reply.Attachments.Add(attachment); await turnContext.SendActivityAsync(reply, cancellationToken); //return base.OnTeamsMessagingExtensionCardButtonClickedAsync(turnContext, cardData, cancellationToken); }
private Attachment GetAdaptiveCardAttachment(string fileName, object cardData) { var templateJson = File.ReadAllText("./Cards/" + fileName); AdaptiveCardTemplate template = new AdaptiveCardTemplate(templateJson); string cardJson = template.Expand(cardData); AdaptiveCardParseResult result = AdaptiveCard.FromJson(cardJson); // Get card from result AdaptiveCard card = result.Card; var adaptiveCardAttachment = new Attachment { ContentType = AdaptiveCard.ContentType, Content = card, }; return(adaptiveCardAttachment); }
private void RenderCard() { cardError.Children.Clear(); cardGrid.Children.Clear(); try { AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(textBox.Text); AdaptiveCard card = parseResult.Card; RenderedAdaptiveCard renderedCard = Renderer.RenderCard(card); // TODO: should we have an option to render fallback card instead of exception? // Wire up click handler renderedCard.OnAction += OnAction; renderedCard.OnMediaClicked += OnMediaClick; cardGrid.Children.Add(renderedCard.FrameworkElement); // Report any warnings var allWarnings = parseResult.Warnings.Union(renderedCard.Warnings); foreach (var warning in allWarnings) { ShowWarning(warning.Message); } } catch (AdaptiveRenderException ex) { var fallbackCard = new TextBlock { Text = ex.CardFallbackText ?? "Sorry, we couldn't render the card" }; cardGrid.Children.Add(fallbackCard); } catch (Exception ex) { ShowError(ex); } }
public AdaptiveCard CreateCard(TModel startingData, ITurnContext context, CancellationToken cancellationToken = default) { var contextJSON = JsonConvert.SerializeObject(startingData); //Transform our template with the data model specified var transformedJSON = Transformer.Transform(JSON, contextJSON); //And then create the card from it AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(transformedJSON); //Print any warnings //TODO: This should tap into app insights stream somewhere if (parseResult.Warnings.Any()) { foreach (var warning in parseResult.Warnings) { Console.WriteLine($"[WARN] {warning.Code} - {warning.Message}"); } } return(parseResult.Card); }
public async static Task <MessagingExtensionActionResponse> ShowResponseCard(ITurnContext <IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken, string Data) { string card = "{\r\n \"type\": \"AdaptiveCard\",\r\n \"version\": \"1.0\",\r\n \"body\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/Firstresponsecolor.png\",\r\n \"width\": \"\"\r\n },\r\n {\r\n \"type\": \"ColumnSet\",\r\n \"columns\": [\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref1.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref2.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"1\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref3.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref4.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n },\r\n {\r\n \"type\": \"Column\",\r\n \"items\": [\r\n {\r\n \"type\": \"Image\",\r\n \"altText\": \"\",\r\n \"url\": \"https://1f0bd229.ngrok.io/images/ref5.png\"\r\n },\r\n {\r\n \"type\": \"TextBlock\",\r\n \"text\": \"1\"\r\n }\r\n ],\r\n \"width\": \"stretch\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\"\r\n}"; AdaptiveCardParseResult result = AdaptiveCard.FromJson(card); var attachment = new MessagingExtensionAttachment { ContentType = AdaptiveCard.ContentType, Content = result.Card, }; return(await Task.FromResult(new MessagingExtensionActionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = "list", Attachments = new List <MessagingExtensionAttachment> { attachment } } })); }
private async Task <Stream> ConvertAsync(Attachment attachment, CancellationToken cancellationToken) { if (attachment.ContentType == AdaptiveCard.ContentType) { // https://docs.microsoft.com/en-us/adaptive-cards/sdk/rendering-cards/net-image/render-a-card AdaptiveCard card = null; if (attachment.Content is AdaptiveCard adaptiveCard) { card = adaptiveCard; } else if (attachment.Content is JToken jtoken) { AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(jtoken.ToString()); card = parseResult.Card; } else { throw new NotImplementedException($"{attachment.Content.GetType().Name} is not supported yet!"); } // TODO don't know if it is thread safe or not var adaptiveRenderer = new AdaptiveCardRenderer(_adaptiveHostConfig); // Set any XAML resource Dictionary if you have one //renderer.ResourcesPath = <path-to-your-resourcedictionary.xaml>; // Render the card to png // Set createStaThread to true if running from a server var renderedCard = await adaptiveRenderer.RenderCardToImageAsync(card, createStaThread : true, cancellationToken : cancellationToken); return(renderedCard.ImageStream); } else { throw new NotSupportedException($"{attachment.ContentType} is not supported yet!"); } }
private static async Task RenderCard(string file, AdaptiveCardRenderer renderer, string outPath) { try { var watch = new Stopwatch(); watch.Start(); AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(File.ReadAllText(file, Encoding.UTF8)); AdaptiveCard card = parseResult.Card; // Timeout after 30 seconds var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); // Render the card to an image RenderedAdaptiveCardImage renderedCard = await renderer.RenderCardToImageAsync(card, true, 400, cts.Token); // Report any warnings foreach (var warning in parseResult.Warnings.Union(renderedCard.Warnings)) { Console.WriteLine($"[{Path.GetFileName(file)}] WARNING: {warning.Message}"); } // Write to a png file with the same name as the json file var outputFile = Path.Combine(outPath, Path.ChangeExtension(Path.GetFileName(file), ".png")); using (var fileStream = new FileStream(outputFile, FileMode.Create)) { renderedCard.ImageStream.CopyTo(fileStream); Console.WriteLine($"[{watch.ElapsedMilliseconds}ms T{Thread.CurrentThread.ManagedThreadId}]\t{Path.GetFileName(file)} => {Path.GetFileName(outputFile)}"); } } catch (Exception ex) { Console.Error.WriteLine($"[FAILED]\t{Path.GetFileName(file)} => {ex.Message}"); } }
private static async Task GetMainOptions(IMessageActivity reply) { HttpClient client = new HttpClient(); HttpResponseMessage response; AdaptiveCard card = new AdaptiveCard(); response = await client.GetAsync(String.Format("https://surastorage.blob.core.windows.net/cardstemplates/servicios.json")); var json = await response.Content.ReadAsStringAsync(); AdaptiveCardParseResult resultString = AdaptiveCard.FromJson(json); card = resultString.Card; IList <AdaptiveWarning> warnings = resultString.Warnings; Attachment attachment = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = card }; reply.Attachments.Add(attachment); }
public PromptOptions GeneratePersonDetailsAttachment(PersonDetails personDetails, PersonKnownFor[] knownFor) { var paths = new[] { ".", "Cards", "personDetails.json" }; var adaptiveCardJson = File.ReadAllText(Path.Combine(paths)); AdaptiveCardParseResult result = AdaptiveCard.FromJson(adaptiveCardJson); AdaptiveCard card = result.Card; ((AdaptiveTextBlock)card.Body.First()).Text = "Person details"; ((AdaptiveImage)((AdaptiveColumnSet)card.Body[1]).Columns.First().Items.First()).Url = new Uri($"https://image.tmdb.org/t/p/w500/{personDetails.profile_path}"); ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items.First()).Text = personDetails.name; ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items[1]).Text = $"Born: {personDetails.birthday}"; ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items[2]).Text = $"Role: {personDetails.known_for_department}"; ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items[1]).Text = $"Born: {personDetails.birthday}"; ((AdaptiveTextBlock)card.Body[2]).Text = personDetails.biography; ((AdaptiveFactSet)card.Body[4]).Facts .AddRange(knownFor.Select(x => new AdaptiveFact { Title = x.Title, Value = $"({x.ReleaseDate.Split("-")[0]}) - {TMDBGenres.MovieGenres.Where(y => y.Value == x.GenreIds[0]).FirstOrDefault().Key}" })); ((AdaptiveOpenUrlAction)card.Actions.First()).Url = new Uri($"https://www.imdb.com/name/{personDetails.imdb_id}"); return(new PromptOptions { Prompt = (Activity)MessageFactory.Attachment(new Attachment() { ContentType = "application/vnd.microsoft.card.adaptive", Content = JObject.FromObject(card) }) }); }
public PromptOptions GenerateTVDetailsAttachment(TVDetails tvDetails) { var paths = new[] { ".", "Cards", "movieDetails.json" }; var adaptiveCardJson = File.ReadAllText(Path.Combine(paths)); AdaptiveCardParseResult result = AdaptiveCard.FromJson(adaptiveCardJson); AdaptiveCard card = result.Card; ((AdaptiveTextBlock)card.Body.First()).Text = "Movie details"; ((AdaptiveImage)((AdaptiveColumnSet)card.Body[1]).Columns.First().Items.First()).Url = new Uri($"https://image.tmdb.org/t/p/w500/{tvDetails.PosterPath}"); ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items.First()).Text = tvDetails.Name; ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items[1]).Text = $"Released: {tvDetails.FirstAirDate}"; ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items[2]).Text = $"Genres: {string.Join(", ", tvDetails.Genres.Select(x => x.Name))}"; ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items[3]).Text = $"Status: {tvDetails.Status}"; ((AdaptiveTextBlock)((AdaptiveColumnSet)card.Body[1]).Columns[1].Items[4]).Text = $"Rating: {tvDetails.VoteAverage}"; ((AdaptiveTextBlock)card.Body[2]).Text = tvDetails.Overview; card.Actions = null; ((AdaptiveFactSet)card.Body[3]).Facts .AddRange(tvDetails.Seasons.OrderBy(x => x.SeasonNumber).Select(x => new AdaptiveFact { Title = x.Name, Value = $"- ({x.AirDate?.Split("-")[0]}) - {x.EpisodeCount} episodes" })); return(new PromptOptions { Prompt = (Activity)MessageFactory.Attachment(new Attachment() { ContentType = "application/vnd.microsoft.card.adaptive", Content = JObject.FromObject(card) }) }); }
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> argument) { AdaptiveCard card = new AdaptiveCard(); card.Body.Add(new AdaptiveTextBlock() { Text = "Adaptive Card rendering test", Size = AdaptiveTextSize.Large, Weight = AdaptiveTextWeight.Bolder }); var choiceSet = new AdaptiveChoiceSetInput(); choiceSet.Choices.Add( new AdaptiveChoice() { Title = "Zuko", Value = "zuko" }); choiceSet.Choices.Add(new AdaptiveChoice() { Title = "Buko", Value = "buko" }); card.Body.Add(choiceSet); Attachment attachment = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = card }; var replyToConversation = context.MakeMessage(); replyToConversation.Attachments.Add(attachment); //return our reply to the user await context.PostAsync(replyToConversation); string json = @"{ ""$schema"": ""http://adaptivecards.io/schemas/adaptive-card.json"", ""type"": ""AdaptiveCard"", ""version"": ""1.0"", ""body"": [ { ""type"": ""TextBlock"", ""text"": ""title"", ""weight"": ""bolder"", ""size"": ""large"" }, { ""type"": ""TextBlock"", ""text"": ""shortText"", ""wrap"": ""true"" }, { ""type"": ""TextBlock"", ""text"": ""Date: date"", ""separator"": ""true"", ""weight"": ""bolder"" } ], ""actions"": [ { ""type"": ""Action.OpenUrl"", ""title"": ""More information"", ""url"": ""Url"" }, { ""type"": ""Action.Submit"", ""title"": ""Subscribe"", ""data"": ""subscribesentence"" } ] }"; AdaptiveCardParseResult result = AdaptiveCard.FromJson(json); AdaptiveCard card2 = result.Card; Attachment attachment2 = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = card2 }; var replyToConversation2 = context.MakeMessage(); replyToConversation2.Attachments.Add(attachment2); await context.PostAsync(replyToConversation2); context.Wait(MessageReceivedAsync); }
protected override async void LoadPayload(string payload) { var newErrors = await PayloadValidator.ValidateAsync(payload); if (newErrors.Any(i => i.Type == ErrorViewModelType.Error)) { MakeErrorsLike(newErrors); return; } try { if (_renderer == null) { InitializeRenderer(MainPageViewModel.HostConfigEditor.HostConfig); } } catch (Exception ex) { newErrors.Add(new ErrorViewModel() { Message = "Initializing renderer error: " + ex.ToString(), Type = ErrorViewModelType.Error }); MakeErrorsLike(newErrors); return; } try { JsonObject jsonObject; if (JsonObject.TryParse(payload, out jsonObject)) { AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(jsonObject); RenderedAdaptiveCard renderResult = _renderer.RenderAdaptiveCard(parseResult.AdaptiveCard); if (renderResult.FrameworkElement != null) { RenderedCard = renderResult.FrameworkElement; renderResult.Action += async(sender, e) => { var m_actionDialog = new ContentDialog(); if (e.Action.ActionType == ActionType.ShowCard) { AdaptiveShowCardAction showCardAction = (AdaptiveShowCardAction)e.Action; RenderedAdaptiveCard renderedShowCard = _renderer.RenderAdaptiveCard(showCardAction.Card); if (renderedShowCard.FrameworkElement != null) { m_actionDialog.Content = renderedShowCard.FrameworkElement; } } else { m_actionDialog.Content = SerializeActionEventArgsToString(e); } m_actionDialog.PrimaryButtonText = "Close"; await m_actionDialog.ShowAsync(); }; if (!MainPageViewModel.HostConfigEditor.HostConfig.Media.AllowInlinePlayback) { renderResult.MediaPlay += async(sender, e) => { var onPlayDialog = new ContentDialog(); onPlayDialog.Content = "MediaPlayEvent:"; foreach (var source in e.Media.Sources) { onPlayDialog.Content += "\n" + source.Url + " (" + source.MimeType + ")"; } onPlayDialog.PrimaryButtonText = "Close"; await onPlayDialog.ShowAsync(); }; } else { renderResult.MediaEnded += async(sender, e) => { var mediaEndedDialog = new ContentDialog(); mediaEndedDialog.Content = "Media Ended Event:"; foreach (var source in e.Media.Sources) { mediaEndedDialog.Content += "\n" + source.Url + " (" + source.MimeType + ")"; } mediaEndedDialog.PrimaryButtonText = "Close"; await mediaEndedDialog.ShowAsync(); }; } } else { newErrors.Add(new ErrorViewModel() { Message = "There was an error Rendering this card", Type = ErrorViewModelType.Error }); } foreach (var error in parseResult.Errors) { newErrors.Add(new ErrorViewModel() { Message = error.Message, Type = ErrorViewModelType.Error }); } foreach (var error in renderResult.Errors) { newErrors.Add(new ErrorViewModel() { Message = error.Message, Type = ErrorViewModelType.Error }); } foreach (var error in parseResult.Warnings) { newErrors.Add(new ErrorViewModel() { Message = error.Message, Type = ErrorViewModelType.Warning }); } foreach (var error in renderResult.Warnings) { newErrors.Add(new ErrorViewModel() { Message = error.Message, Type = ErrorViewModelType.Warning }); } } else { newErrors.Add(new ErrorViewModel() { Message = "There was an error creating a JsonObject from the card", Type = ErrorViewModelType.Error }); } if (RenderedCard is FrameworkElement) { (RenderedCard as FrameworkElement).VerticalAlignment = VerticalAlignment.Top; } MakeErrorsLike(newErrors); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); newErrors.Add(new ErrorViewModel() { Message = "Rendering failed", Type = ErrorViewModelType.Error }); MakeErrorsLike(newErrors); } }
static void Main(string[] args) { bool supportsInteractivity = false; const string supportsInteractivityFlag = "/supportsInteractivity"; if (args.Contains(supportsInteractivityFlag)) { supportsInteractivity = true; args = args.Except(new string[] { supportsInteractivityFlag }).ToArray(); } Console.WriteLine(@"<html><head>"); Console.WriteLine(@"<style>"); Console.WriteLine(@".cardcontainer { "); Console.WriteLine(@" width: 400px;"); Console.WriteLine(@" border-width: 1px;"); Console.WriteLine(@" border-color: #808080;"); Console.WriteLine(@" border-style: solid;"); Console.WriteLine(@" padding: 8px;"); Console.WriteLine(@"}"); Console.WriteLine(@"</style>"); Console.WriteLine(@"</head>"); Console.WriteLine(@"<body>"); List <string> files = new List <string>(); if (File.Exists(args[0])) { files.Add(args[0]); } else { files = Directory.GetFiles(args[0]).ToList(); } foreach (var file in files) { try { Console.WriteLine("<hr/>"); Console.WriteLine($"<h1>{file}</h1>"); AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(File.ReadAllText(file)); if (parseResult.Card != null) { AdaptiveCard card = parseResult.Card; AdaptiveCardRenderer renderer = new AdaptiveCardRenderer(new HostConfig() { SupportsInteractivity = supportsInteractivity }); Console.WriteLine($"<h3>Renderer schema version: {renderer.SupportedSchemaVersion}</h3>"); RenderedAdaptiveCard renderedCard = renderer.RenderCard(card); if (renderedCard.HtmlTag != null) { Console.WriteLine($"<div class='cardcontainer'>{renderedCard.HtmlTag.ToString()}</div>"); } else { Console.WriteLine($"<p>Rendering failed</p>"); } } } catch (Exception err) { Console.WriteLine($"{file} failed: {err.Message}<br/>"); } } #if DEBUG // Leave the console up while debugging if (System.Diagnostics.Debugger.IsAttached) { Console.ReadLine(); } #endif }
private void RenderCard() { cardError.Children.Clear(); cardGrid.Opacity = 0.65; if (templateData != null && templateData.Length == 0) { templateData = null; } string expandedPayload = ""; try { // don't throw error, but should affect work flow and performance. // transformer -> has to have errors var template = new AdaptiveCardTemplate(CardPayload); var context = new EvaluationContext { Root = templateData }; // Create a data binding context, and set its $root property to the // data object to bind the template to // var context = new ACData.EvaluationContext(); // context.$root = { // "name": "Mickey Mouse" // }; expandedPayload = template.Expand(context); } catch (Exception e) { // if an exception thrown, we parse and render cards as it is ShowError(e); expandedPayload = CardPayload; } try { AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(expandedPayload); AdaptiveCard card = parseResult.Card; /* * if (!_stylesAdded) * { * // Example on how to override the Action Positive and Destructive styles * Style positiveStyle = new Style(typeof(Button)); * positiveStyle.Setters.Add(new Setter(Button.BackgroundProperty, Brushes.Green)); * Style otherStyle = new Style(typeof(Button)); * otherStyle.Setters.Add(new Setter(Button.BackgroundProperty, Brushes.Yellow)); * otherStyle.Setters.Add(new Setter(Button.ForegroundProperty, Brushes.Red)); * * Renderer.Resources.Add("Adaptive.Action.positive", positiveStyle); * Renderer.Resources.Add("Adaptive.Action.other", otherStyle); * * _stylesAdded = true; * } */ RenderedAdaptiveCard renderedCard = Renderer.RenderCard(card); // TODO: should we have an option to render fallback card instead of exception? // Wire up click handler renderedCard.OnAction += OnAction; renderedCard.OnMediaClicked += OnMediaClick; cardGrid.Opacity = 1; cardGrid.Children.Clear(); cardGrid.Children.Add(renderedCard.FrameworkElement); // Report any warnings var allWarnings = parseResult.Warnings.Union(renderedCard.Warnings); foreach (var warning in allWarnings) { ShowWarning(warning.Message); } } catch (AdaptiveRenderException ex) { var fallbackCard = new TextBlock { Text = ex.CardFallbackText ?? "Sorry, we couldn't render the card" }; cardGrid.Children.Add(fallbackCard); } catch (Exception ex) { ShowError(ex); } }
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable <object> result) { var activity = await result as Activity; if (activity.Value != null) { JToken valueToken = JObject.Parse(activity.Value.ToString()); string actionValue = valueToken.SelectToken("property") != null?valueToken.SelectToken("property").ToString() : string.Empty; var reply = context.MakeMessage(); string json = ""; switch (actionValue) { case "1": json = await GetCardText("card1"); break; case "2": json = await GetCardText("card2"); break; case "3": json = await GetCardText("card3"); break; default: break; } AdaptiveCardParseResult cardParseResult = AdaptiveCard.FromJson(json); reply.Attachments.Add(new Attachment { ContentType = AdaptiveCard.ContentType, Content = cardParseResult.Card }); await context.PostAsync(reply); } else { if (activity.Text.ToLower().Contains("card")) { var replyMessage = context.MakeMessage(); var json = await GetCardText("maincard"); AdaptiveCardParseResult cardParseResult = AdaptiveCard.FromJson(json); replyMessage.Attachments.Add(new Attachment() { Content = cardParseResult.Card, ContentType = AdaptiveCard.ContentType, Name = "Card" }); await context.PostAsync(replyMessage); } else { await context.PostAsync($"You sent {activity.Text}"); } } context.Wait(MessageReceivedAsync); }
static int Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; var app = new CommandLineApplication(); app.HelpOption("-h|--help"); var pathArg = app.Argument("path", "The path that contains JSON card payloads"); var optionRecurse = app.Option("-r|--recursive", "Recurse the directory for all JSON files", CommandOptionType.NoValue); var optionOutput = app.Option("-o|--out", "The file to output the HTML to", CommandOptionType.SingleValue); var optionSupportsInteracitivty = app.Option("-i|--supports-interactivity", "Include actions and inputs in the output", CommandOptionType.NoValue); var hostConfigOption = app.Option("--host-config", "Specify a host config file", CommandOptionType.SingleValue); app.OnExecute(() => { FileStream outputFile = null; var writer = Console.Out; // Output to file instead of console if (optionOutput.HasValue()) { outputFile = File.Open(optionOutput.Value(), FileMode.Create); writer = new StreamWriter(outputFile); } // Get payload search path var payloadPath = pathArg.Value ?? "..\\..\\..\\..\\samples\\v1.0\\Scenarios"; if (pathArg.Value == null) { Console.WriteLine($"No path argument specified, trying {payloadPath}..."); } var files = new List <string>(); if (File.Exists(payloadPath)) { files.Add(payloadPath); } else if (Directory.Exists(payloadPath)) { var recurse = optionRecurse.HasValue() ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; files = Directory.GetFiles(payloadPath, "*.json", recurse).ToList(); Console.WriteLine($"Found {files.Count} card payloads..."); } else { Console.WriteLine($"{payloadPath} does not contain any JSON files. Nothing to do."); return; } writer.WriteLine(@"<!DOCTYPE html> <html> <head> <title>Adaptive Cards HTML Renderer Test Bed</title> <meta charset=""UTF-8""> <style type""text/css""> * { box-sizing: border-box; font-family: 'Segoe UI' } .cardcontainer { width: 400px; border-width: 1px; border-color: #808080; border-style: solid; } .error { border: solid 1px maroon; color: white; background: maroon; padding: 5px; width: 400px; } .warning { border: solid 1px orange; color: white; background: orange; padding: 5px; width: 400px; } </style> </head> <body>"); AdaptiveHostConfig hostConfig = new AdaptiveHostConfig() { SupportsInteractivity = optionSupportsInteracitivty.HasValue() }; if (hostConfigOption.HasValue()) { hostConfig = AdaptiveHostConfig.FromJson(File.ReadAllText(hostConfigOption.Value())); } AdaptiveCardRenderer renderer = new AdaptiveCardRenderer(hostConfig); writer.WriteLine($"<h3>Renderer schema version: {renderer.SupportedSchemaVersion}</h3>"); writer.WriteLine($"<h4>Interactivty Enabled: {hostConfig.SupportsInteractivity}</h4>"); writer.WriteLine($"<h4>Generated at: {DateTime.Now:G}</h4>"); foreach (var file in files) { try { writer.WriteLine("<hr/>"); writer.WriteLine($"<h2>{Path.GetFileName(file)}</h2>"); AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(File.ReadAllText(file, Encoding.UTF8)); AdaptiveCard card = parseResult.Card; RenderedAdaptiveCard renderedCard = renderer.RenderCard(card); // Report any warnings foreach (var warning in parseResult.Warnings.Union(renderedCard.Warnings)) { writer.WriteLine($"<p class='warning'>WARNING: {warning.Message}</p>"); } writer.WriteLine($"<div class='cardcontainer'>{renderedCard.Html}</div>"); } catch (Exception err) { Debugger.Break(); writer.WriteLine($"<p class='error'>ERROR: {err.Message}</p>"); } } bool allowInlinePlayback = hostConfig.Media.AllowInlinePlayback; // Convert to JavaScript boolean values (False -> false, True -> true) string jsAllowInlinePlayback = allowInlinePlayback.ToString().ToLower(); writer.WriteLine("</body>"); writer.WriteLine($@" <script> // Sample JavaScript code to make media elements work const mediaPosterButtons = document.getElementsByClassName('ac-media-poster'); const allowInlinePlayback = false; for (var i = 0; i < mediaPosterButtons.length; i++) {{ const button = mediaPosterButtons[i]; button.addEventListener('click', function() {{ if ({jsAllowInlinePlayback}) {{ const mediaId = button.dataset.acMediaid; const mediaPlayerContainer = document.getElementById(mediaId); if (mediaPlayerContainer) {{ // Hide the poster button.style.display = 'none'; // Show the media player container mediaPlayerContainer.style.display = ''; // Play the media const mediaPlayer = document.getElementById(`${{mediaId}}-player`); mediaPlayer.play(); }} }} else {{ const mediaSources = button.dataset.acMediaSources; alert(mediaSources); }} }}); }} </script>"); writer.WriteLine("</html>"); if (outputFile != null) { writer.Flush(); outputFile.Flush(); outputFile.Dispose(); Console.WriteLine($"All cards were written to {outputFile.Name}"); } // if output, launch the file if (Debugger.IsAttached) { Console.ReadLine(); } }); return(app.Execute(args)); }
static int Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; var app = new CommandLineApplication(); app.HelpOption("-h|--help"); var pathArg = app.Argument("path", "The path that contains JSON card payloads"); var optionRecurse = app.Option("-r|--recursive", "Recurse the directory for all JSON files", CommandOptionType.NoValue); var optionOutput = app.Option("-o|--out", "The file to output the HTML to", CommandOptionType.SingleValue); var optionSupportsInteracitivty = app.Option("-i|--supports-interactivity", "Include actions and inputs in the output", CommandOptionType.NoValue); var hostConfigOption = app.Option("--host-config", "Specify a host config file", CommandOptionType.SingleValue); app.OnExecute(() => { FileStream outputFile = null; var writer = Console.Out; // Output to file instead of console if (optionOutput.HasValue()) { outputFile = File.Open(optionOutput.Value(), FileMode.Create); writer = new StreamWriter(outputFile); } // Get payload search path var payloadPath = pathArg.Value ?? "..\\..\\..\\..\\samples\\v1.0\\Scenarios"; if (pathArg.Value == null) { Console.WriteLine($"No path argument specified, trying {payloadPath}..."); } var files = new List <string>(); if (File.Exists(payloadPath)) { files.Add(payloadPath); } else if (Directory.Exists(payloadPath)) { var recurse = optionRecurse.HasValue() ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; files = Directory.GetFiles(payloadPath, "*.json", recurse).ToList(); Console.WriteLine($"Found {files.Count} card payloads..."); } else { Console.WriteLine($"{payloadPath} does not contain any JSON files. Nothing to do."); return; } writer.WriteLine(@"<!DOCTYPE html> <html> <head> <title>Adaptive Cards HTML Renderer Test Bed</title> <meta charset=""UTF-8""> <style type""text/css""> * { box-sizing: border-box; font-family: 'Segoe UI' } .cardcontainer { width: 400px; border-width: 1px; border-color: #808080; border-style: solid; } .error { border: solid 1px maroon; color: white; background: maroon; padding: 5px; width: 400px; } .warning { border: solid 1px orange; color: white; background: orange; padding: 5px; width: 400px; } </style> </head> <body>"); AdaptiveHostConfig hostConfig = new AdaptiveHostConfig() { SupportsInteractivity = optionSupportsInteracitivty.HasValue() }; if (hostConfigOption.HasValue()) { hostConfig = AdaptiveHostConfig.FromJson(File.ReadAllText(hostConfigOption.Value())); } AdaptiveCardRenderer renderer = new AdaptiveCardRenderer(hostConfig); writer.WriteLine($"<h3>Renderer schema version: {renderer.SupportedSchemaVersion}</h3>"); writer.WriteLine($"<h4>Interactivty Enabled: {hostConfig.SupportsInteractivity}</h4>"); writer.WriteLine($"<h4>Generated at: {DateTime.Now:G}</h4>"); foreach (var file in files) { try { writer.WriteLine("<hr/>"); writer.WriteLine($"<h2>{Path.GetFileName(file)}</h2>"); AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(File.ReadAllText(file, Encoding.UTF8)); AdaptiveCard card = parseResult.Card; RenderedAdaptiveCard renderedCard = renderer.RenderCard(card); // Report any warnings foreach (var warning in parseResult.Warnings.Union(renderedCard.Warnings)) { writer.WriteLine($"<p class='warning'>WARNING: {warning.Message}</p>"); } writer.WriteLine($"<div class='cardcontainer'>{renderedCard.Html}</div>"); } catch (Exception err) { Debugger.Break(); writer.WriteLine($"<p class='error'>ERROR: {err.Message}</p>"); } } bool allowInlinePlayback = hostConfig.Media.AllowInlinePlayback; // Convert to JavaScript boolean values (False -> false, True -> true) string jsAllowInlinePlayback = allowInlinePlayback.ToString().ToLower(); writer.WriteLine("</body>"); writer.WriteLine($@" <script> // Sample JavaScript code to make media elements work const mediaPosterButtons = document.getElementsByClassName('ac-media-poster'); const allowInlinePlayback = false; function activateMedia(button) {{ const mediaId = button.dataset.acMediaid; const mediaPlayerContainer = document.getElementById(mediaId); if (mediaPlayerContainer) {{ // Hide the poster button.style.display = 'none'; // Show the media player container mediaPlayerContainer.style.display = ''; // Play the media const mediaPlayer = document.getElementById(`${{mediaId}}-player`); mediaPlayer.play(); }} }} for (var i = 0; i < mediaPosterButtons.length; i++) {{ const button = mediaPosterButtons[i]; button.addEventListener('click', function() {{ if ({jsAllowInlinePlayback}) {{ activateMedia(button); }} else {{ const mediaSources = button.dataset.acMediaSources; alert(mediaSources); }} }}); button.addEventListener('keydown', function(e) {{ if (e.key == "" "") {{ if ({jsAllowInlinePlayback}) {{ activateMedia(button); }} else {{ const mediaSources = button.dataset.acMediaSources; alert(mediaSources); }} }} }}); }} // Sample JavaScript code to test showCard action const showCardActions = document.getElementsByClassName('ac-action-showCard'); for (var i = 0; i < showCardActions.length; i++) {{ const showCardAction = showCardActions[i]; showCardAction.addEventListener('click', function() {{ if (true) {{ const showCardId = showCardAction.dataset.acShowcardid; const showCard = document.getElementById(showCardId); if(showCard.style.display == 'none') {{ showCard.style.display = 'inline'; }} else {{ showCard.style.display = 'none' }} }} else {{ const showCardId = showCardAction.dataset.acShowCardId; alert(showCardId); }} }}); }} // Sample JavaScript code to test inlienaction's keyboard event handler const textinputWithInlineAction = document.getElementsByClassName('ac-textinput-inlineaction'); for (var i = 0; i < textinputWithInlineAction.length; i++) {{ const container = textinputWithInlineAction[i]; const textinputId = container.dataset.acTextinputId; const textinput = document.getElementById(textinputId); textinput.addEventListener('keydown', function (e) {{ if (e.key == ""Enter"") {{ const inlineactionId = container.dataset.acInlineactionId; const inlineaction = document.getElementById(inlineactionId); if (inlineaction) {{ var actionAttribute = inlineaction.getAttribute('data-ac-url'); if (actionAttribute != null) {{ window.open(actionAttribute); }} else {{ actionAttribute = inlineaction.getAttribute('data-ac-submitData') if (actionAttribute != null) {{ alert(textinput.value); }} }} }} }} }}); }} // Sample JavaScript code to test toggleVisibility action const toggleVisibilityActions = document.getElementsByClassName('ac-action-toggleVisibility'); for (var i = 0; i < toggleVisibilityActions.length; i++) {{ const toggleVisibilityAction = toggleVisibilityActions[i]; toggleVisibilityAction.addEventListener('click', function() {{ if ({jsAllowInlinePlayback}) {{ // Read list of targets with defined behaviour // List will be in format id-targets='id1:True,id2:Toggle,id3:False' const targetElementsString = toggleVisibilityAction.dataset.acTargetelements; var targetElements = targetElementsString.split(','); // For each target in list of targets for(var j = 0; j < targetElements.length; j++) {{ /// Do a split for commas and for each element, find the : to divide both strings const targetElementIdWithAction = targetElements[j].split(':'); const targetElementId = targetElementIdWithAction[0]; const targetElementAction = targetElementIdWithAction[1]; var targetElementsInDocument = document.getElementsByName(targetElementId); // There is no singular version of getElementByName so just take the first element var targetElement = targetElementsInDocument[0]; // The way to discern between checkbox elements and inline-actions is that inline-actions contain a textinput var isCheckBoxElement = ((targetElementsInDocument.length > 1) && !(targetElement.className.includes('ac-textinput'))); const targetSeparatorId = targetElement.dataset.acSeparatorid; const separator = document.getElementById(targetSeparatorId); if(targetElementAction == 'True' || (targetElementAction == 'Toggle' && targetElement.style.display == 'none')) {{ if( isCheckBoxElement ) {{ targetElement.style.display = 'inline-block'; }} else {{ targetElement.style.display = 'flex'; }} if(targetElement.className.includes('ac-container')){{ targetElement.style.display = 'block'; }} if(separator != null) {{ separator.style.display = 'block'; }} }} else if(targetElementAction == 'False' || (targetElementAction == 'Toggle' && targetElement.style.display != 'none')) {{ targetElement.style.display = 'none'; if(separator != null) {{ separator.style.display = 'none'; }} }} const parent = targetElement.parentNode; var isFirstElement = true; for(var k = 0; k < parent.childNodes.length; k++){{ var child = parent.childNodes[k]; <!-- if element is separator -> skip (As we don't care of this one) --> if(child.className.includes('ac-separator') || child.className.includes('ac-columnseparator')){{ continue; }} <!-- if element is not visible -> skip (The separator was hidden in the previous step) --> if(child.style.display == 'none'){{ continue; }} const childSeparatorId = child.dataset.acSeparatorid; var childSeparator = document.getElementById(childSeparatorId); if(isFirstElement){{ <!-- if element is visible -> hide separator --> if(childSeparator != null){{ childSeparator.style.display = 'none'; }} isFirstElement = false; }} else{{ <!-- if element is visible -> show separator --> if(childSeparator != null){{ childSeparator.style.display = 'block'; }} }} }} }} }} else {{ const targetElementsString = toggleVisibilityAction.dataset.acTargetelements; alert(targetElementsString); }} }}); }} </script>"); writer.WriteLine("</html>"); if (outputFile != null) { writer.Flush(); outputFile.Flush(); outputFile.Dispose(); Console.WriteLine($"All cards were written to {outputFile.Name}"); } // if output, launch the file if (Debugger.IsAttached) { Console.ReadLine(); } }); return(app.Execute(args)); }
private void TestParsingInvalidCard(string cardPayload) { AdaptiveCardParseResult result = AdaptiveCard.FromJson(cardPayload); Assert.IsNull(result.Card); }
static int Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; var app = new CommandLineApplication(); app.HelpOption("-h|--help"); var pathArg = app.Argument("path", "The path that contains JSON card payloads"); var optionRecurse = app.Option("-r|--recursive", "Recurse the directory for all JSON files", CommandOptionType.NoValue); var optionOutput = app.Option("-o|--out", "The file to output the HTML to", CommandOptionType.SingleValue); var optionSupportsInteracitivty = app.Option("-i|--supports-interactivity", "Include actions and inputs in the output", CommandOptionType.NoValue); var hostConfigOption = app.Option("--host-config", "Specify a host config file", CommandOptionType.SingleValue); app.OnExecute(() => { FileStream outputFile = null; var writer = Console.Out; // Output to file instead of console if (optionOutput.HasValue()) { outputFile = File.Open(optionOutput.Value(), FileMode.Create); writer = new StreamWriter(outputFile); } // Get payload search path var payloadPath = pathArg.Value ?? "..\\..\\..\\..\\samples\\v1.0\\Scenarios"; if (pathArg.Value == null) { Console.WriteLine($"No path argument specified, trying {payloadPath}..."); } var files = new List <string>(); if (File.Exists(payloadPath)) { files.Add(payloadPath); } else if (Directory.Exists(payloadPath)) { var recurse = optionRecurse.HasValue() ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; files = Directory.GetFiles(payloadPath, "*.json", recurse).ToList(); Console.WriteLine($"Found {files.Count} card payloads..."); } else { Console.WriteLine($"{payloadPath} does not contain any JSON files/. Nothing to do."); return; } writer.WriteLine(@"<!DOCTYPE html>"); writer.WriteLine(@"<html>"); writer.WriteLine(@"<head>"); writer.WriteLine(@" <title>Adaptive Cards HTML Renderer Test Bed</title>"); writer.WriteLine(@" <meta charset=""UTF-8"">"); writer.WriteLine(@" <link rel='stylesheet' type='text/css' href='AdaptiveCards.css' />"); writer.WriteLine(@"</head>"); writer.WriteLine(@"<body>"); AdaptiveHostConfig hostConfig = new AdaptiveHostConfig() { SupportsInteractivity = optionSupportsInteracitivty.HasValue() }; if (hostConfigOption.HasValue()) { hostConfig = AdaptiveHostConfig.FromJson(File.ReadAllText(hostConfigOption.Value())); } AdaptiveCardRenderer renderer = new AdaptiveCardRenderer(hostConfig); writer.WriteLine($"<h3>Renderer schema version: {renderer.SupportedSchemaVersion}</h3>"); writer.WriteLine($"<h4>Interactivty Enabled: {hostConfig.SupportsInteractivity}</h4>"); writer.WriteLine($"<h4>Generated at: {DateTime.Now:G}</h4>"); foreach (var file in files) { try { writer.WriteLine("<hr/>"); writer.WriteLine($"<h2>{Path.GetFileName(file)}</h2>"); AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(File.ReadAllText(file, Encoding.UTF8)); AdaptiveCard card = parseResult.Card; RenderedAdaptiveCard renderedCard = renderer.RenderCard(card); // Report any warnings foreach (var warning in parseResult.Warnings.Union(renderedCard.Warnings)) { writer.WriteLine($"<p class='warning'>WARNING: {warning.Message}</p>"); } writer.WriteLine($"<div class='cardcontainer'>{renderedCard.Html}</div>"); } catch (Exception err) { Debugger.Break(); writer.WriteLine($"<p class='error'>ERROR: {err.Message}</p>"); } } writer.WriteLine("</body>"); writer.WriteLine("</html>"); if (outputFile != null) { writer.Flush(); outputFile.Flush(); outputFile.Dispose(); Console.WriteLine($"All cards were written to {outputFile.Name}"); } // if output, launch the file if (Debugger.IsAttached) { Console.ReadLine(); } }); return(app.Execute(args)); }
private void RenderCard() { cardError.Children.Clear(); cardGrid.Opacity = 0.65; try { AdaptiveCardParseResult parseResult = AdaptiveCard.FromJson(CardPayload); AdaptiveCard card = parseResult.Card; /* * if (!_stylesAdded) * { * // Example on how to override the Action Positive and Destructive styles * Style positiveStyle = new Style(typeof(Button)); * positiveStyle.Setters.Add(new Setter(Button.BackgroundProperty, Brushes.Green)); * Style otherStyle = new Style(typeof(Button)); * otherStyle.Setters.Add(new Setter(Button.BackgroundProperty, Brushes.Yellow)); * otherStyle.Setters.Add(new Setter(Button.ForegroundProperty, Brushes.Red)); * * Renderer.Resources.Add("Adaptive.Action.positive", positiveStyle); * Renderer.Resources.Add("Adaptive.Action.other", otherStyle); * * _stylesAdded = true; * } */ RenderedAdaptiveCard renderedCard = Renderer.RenderCard(card); // TODO: should we have an option to render fallback card instead of exception? // Wire up click handler renderedCard.OnAction += OnAction; renderedCard.OnMediaClicked += OnMediaClick; cardGrid.Opacity = 1; cardGrid.Children.Clear(); cardGrid.Children.Add(renderedCard.FrameworkElement); // Report any warnings var allWarnings = parseResult.Warnings.Union(renderedCard.Warnings); foreach (var warning in allWarnings) { ShowWarning(warning.Message); } } catch (AdaptiveRenderException ex) { var fallbackCard = new TextBlock { Text = ex.CardFallbackText ?? "Sorry, we couldn't render the card" }; cardGrid.Children.Add(fallbackCard); } catch (Exception ex) { ShowError(ex); } }