/// <summary> /// Called when the object should parse it's goods out of the markdown. The markdown, start, and stop are given. /// The start and stop are what is returned from the FindNext function below. The object should do it's parsing and /// return up to the last pos it used. This can be shorter than what is given to the function in endingPos. /// </summary> /// <param name="markdown">The markdown</param> /// <param name="startingPos">Where the parse should start</param> /// <param name="endingPos">Where the parse should end</param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int endingPos) { int italicStart = Common.IndexOf(ref markdown, '*', startingPos, endingPos); // These should always be = if (italicStart != startingPos) { DebuggingReporter.ReportCriticalError("italic parse didn't find * in at the starting pos"); } italicStart++; // Find the ending int italicEnd = Common.IndexOf(ref markdown, '*', italicStart, endingPos, true); if (italicEnd + 1 != endingPos) { DebuggingReporter.ReportCriticalError("italic parse didn't find * in at the end pos"); } // Make sure there is something to parse, and not just dead space if (italicEnd > italicStart) { // Parse any children of this bold element ParseInlineChildren(ref markdown, italicStart, italicEnd); } // Return the point after the * return(italicEnd + 1); }
/// <summary> /// Called when the object should parse it's goods out of the markdown. The markdown, start, and stop are given. /// The start and stop are what is returned from the FindNext function below. The object should do it's parsing and /// return up to the last pos it used. This can be shorter than what is given to the function in endingPos. /// </summary> /// <param name="markdown">The markdown</param> /// <param name="startingPos">Where the parse should start</param> /// <param name="endingPos">Where the parse should end</param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int endingPos) { int boldStart = Common.IndexOf(ref markdown, "**", startingPos, endingPos); // These should always be = if (boldStart != startingPos) { DebuggingReporter.ReportCriticalError("bold parse didn't find ** in at the starting pos"); } boldStart += 2; // Find the ending int boldEnding = Common.IndexOf(ref markdown, "**", boldStart, endingPos, true); if (boldEnding + 2 != endingPos) { DebuggingReporter.ReportCriticalError("bold parse didn't find ** in at the end pos"); } // Make sure there is something to parse, and not just dead space if (boldEnding > boldStart) { // Parse any children of this bold element ParseInlineChildren(ref markdown, boldStart, boldEnding); } // Return the point after the ** return(boldEnding + 2); }
/// <summary> /// Fired when the markdown is changed. /// </summary> /// <param name="newMarkdown"></param> private void OnMarkdownChanged(string newMarkdown) { OnMarkdownReadyArgs args = new OnMarkdownReadyArgs(); // Clear the current content CleanUpTextBlock(); // Make sure we have something to parse. if (!String.IsNullOrWhiteSpace(newMarkdown)) { try { // Try to parse the markdown. Markdown markdown = new Markdown(); markdown.Parse(newMarkdown); // Now try to display it RenderToRichTextBlock rendner = new RenderToRichTextBlock(ui_richTextBox, this); rendner.Render(markdown); } catch (Exception e) { DebuggingReporter.ReportCriticalError("Error while parsing and rendering: " + e.Message); args.WasError = true; args.Exception = e; } } // #todo indicate if ready m_onMarkdownReady.Raise(this, args); }
/// <summary> /// Called when the object should parse it's goods out of the markdown. The markdown, start, and stop are given. /// The start and stop are what is returned from the FindNext function below. The object should do it's parsing and /// return up to the last pos it used. This can be shorter than what is given to the function in endingPos. /// </summary> /// <param name="markdown">The markdown</param> /// <param name="startingPos">Where the parse should start</param> /// <param name="endingPos">Where the parse should end</param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int endingPos) { int httpStart = Common.IndexOf(ref markdown, "http://", startingPos, endingPos); int httpsStart = Common.IndexOf(ref markdown, "https://", startingPos, endingPos); // Make -1 huge. httpStart = httpStart == -1 ? int.MaxValue : httpStart; httpsStart = httpsStart == -1 ? int.MaxValue : httpsStart; // Figure out the pos of the link int linkStart = Math.Min(httpStart, httpsStart); int linkEnd = Common.FindNextWhiteSpace(ref markdown, linkStart, endingPos, true); // These should always be = if (linkStart != startingPos) { DebuggingReporter.ReportCriticalError("raw link parse didn't find http in at the starting pos"); } if (linkEnd != endingPos) { DebuggingReporter.ReportCriticalError("raw link parse didn't find the same ending pos"); } // Special cases for links, they can't end in a special char like . ? or ! if (Char.IsPunctuation(markdown[linkEnd - 1])) { linkEnd--; } // Grab the link text Url = markdown.Substring(linkStart, linkEnd - linkStart); // Return the point after the end return(linkEnd); }
/// <summary> /// Called when this block type should parse out the goods. Given the markdown, a starting point, and a max ending point /// the block should find the start of the block, find the end and parse out the middle. The end most of the time will not be /// the max ending pos, but it sometimes can be. The function will return where it ended parsing the block in the markdown. /// </summary> /// <param name="markdown"></param> /// <param name="startingPos"></param> /// <param name="maxEndingPos"></param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int maxEndingPos) { // Figure out what char we are processing. int horzStart = startingPos; char ruleChar = '*'; if (markdown[horzStart] == '*') { ruleChar = '*'; } else if (markdown[horzStart] == '-') { ruleChar = '-'; } else if (markdown[horzStart] == '=') { ruleChar = '='; } else if (markdown[horzStart] == '_') { ruleChar = '_'; } else { DebuggingReporter.ReportCriticalError("Tried parse horizontal rule but didn't find a * or -"); return(maxEndingPos); } // Find the end of the line int horzEnd = horzStart; while (horzEnd < markdown.Length && horzEnd < maxEndingPos) { if (markdown[horzEnd] != ruleChar) { break; } horzEnd++; } // Trim off any extra line endings, except ' ' otherwise we can't do code blocks while (horzEnd < markdown.Length && horzEnd < maxEndingPos && Char.IsWhiteSpace(markdown[horzEnd]) && markdown[horzEnd] != ' ') { horzEnd++; } // Return where we ended. return(horzEnd); }
/// <summary> /// Called when this block type should parse out the goods. Given the markdown, a starting point, and a max ending point /// the block should find the start of the block, find the end and parse out the middle. The end most of the time will not be /// the max ending pos, but it sometimes can be. The function will return where it ended parsing the block in the markdown. /// </summary> /// <param name="markdown"></param> /// <param name="startingPos"></param> /// <param name="maxEndingPos"></param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int maxEndingPos) { // Do a quick check int headerStart = startingPos; if (markdown[headerStart] != '#') { DebuggingReporter.ReportCriticalError("Tried to parse a header but # wasn't found"); } // Find the end of header, note that headers break with a single new line no matter what. int headerEnd = Common.FindNextSingleNewLine(ref markdown, headerStart, maxEndingPos); if (headerEnd == -1) { DebuggingReporter.ReportCriticalError("Tried to parse header that didn't have an end"); headerEnd = maxEndingPos; } // Find how many are in a row while (headerStart < markdown.Length && headerStart < maxEndingPos && markdown[headerStart] == '#') { HeaderLevel++; headerStart++; // To match reddit's formatting if there are more than 6 we should start showing them. if (HeaderLevel > 5) { break; } } // Make sure there is something to parse, and not just dead space if (headerEnd > headerStart) { // Parse the children of this quote ParseInlineChildren(ref markdown, headerStart, headerEnd); } // Trim off any extra line endings, except ' ' otherwise we can't do code blocks while (headerEnd < markdown.Length && headerEnd < maxEndingPos && Char.IsWhiteSpace(markdown[headerEnd]) && markdown[headerEnd] != ' ') { headerEnd++; } // Return where we ended. return(headerEnd); }
/// <summary> /// Called when this block type should parse out the goods. Given the markdown, a starting point, and a max ending point /// the block should find the start of the block, find the end and parse out the middle. The end most of the time will not be /// the max ending pos, but it sometimes can be. The function will return where it ended parsing the block in the markdown. /// </summary> /// <param name="markdown"></param> /// <param name="startingPos"></param> /// <param name="maxEndingPos"></param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int maxEndingPos) { // Do a quick check. int quoteStart = startingPos + 1; if (markdown[startingPos] != '>') { DebuggingReporter.ReportCriticalError("Tried to parse quote that didn't exist"); } // Find the end of quote, we always break on a double return no matter what. int quoteEnd = Common.FindNextDoubleNewLine(ref markdown, quoteStart, maxEndingPos); if (quoteEnd == -1) { DebuggingReporter.ReportCriticalError("Tried to parse quote that didn't have an end"); quoteEnd = maxEndingPos; } // Find how many indents we have, we have to count backwards from the starting pos. Start with one // so if we have no spaces we at least get that. QuoteIndent = 1; int currentBackCount = startingPos - 1; while (currentBackCount >= 0 && markdown[currentBackCount] != '\n' && markdown[currentBackCount] != '\r') { QuoteIndent++; currentBackCount--; } // Make sure there is something to parse, and not just dead space if (quoteEnd > quoteStart) { // Parse the children of this quote ParseInlineChildren(ref markdown, quoteStart, quoteEnd); } // Trim off any extra line endings, except ' ' otherwise we can't do code blocks while (quoteEnd < markdown.Length && quoteEnd < maxEndingPos && Char.IsWhiteSpace(markdown[quoteEnd]) && markdown[quoteEnd] != ' ') { quoteEnd++; } // Return where we ended. return(quoteEnd); }
/// <summary> /// Called when this block type should parse out the goods. Given the markdown, a starting point, and a max ending point /// the block should find the start of the block, find the end and parse out the middle. The end most of the time will not be /// the max ending pos, but it sometimes can be. The function will return where it ended parsing the block in the markdown. /// </summary> /// <param name="markdown"></param> /// <param name="startingPos"></param> /// <param name="maxEndingPos"></param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int maxEndingPos) { // Get the end. int nbspEnd = TryToFindNbsp(ref markdown, startingPos, maxEndingPos); // Sanity check if (nbspEnd == -1) { DebuggingReporter.ReportCriticalError("Tried parse line break find a &nbps;"); return(maxEndingPos); } // Trim off any extra line endings, except ' ' otherwise we can't do code blocks while (nbspEnd < markdown.Length && nbspEnd < maxEndingPos && Char.IsWhiteSpace(markdown[nbspEnd]) && markdown[nbspEnd] != ' ') { nbspEnd++; } // Return where we ended. return(nbspEnd); }
/// <summary> /// Called when the object should parse it's goods out of the markdown. The markdown, start, and stop are given. /// The start and stop are what is returned from the FindNext function below. The object should do it's parsing and /// return up to the last pos it used. This can be shorter than what is given to the function in endingPos. /// </summary> /// <param name="markdown">The markdown</param> /// <param name="startingPos">Where the parse should start</param> /// <param name="endingPos">Where the parse should end</param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int endingPos) { // Do a sanity check. if ((Char.ToLower(markdown[startingPos]) != 'r' || markdown[startingPos + 1] != '/') && (markdown[startingPos] != '/' || Char.ToLower(markdown[startingPos + 1]) != 'r' || markdown[startingPos + 2] != '/')) { DebuggingReporter.ReportCriticalError("Trying to parse a subreddit link but didn't find a subreddit"); return(endingPos); } int subredditStart = startingPos; // Grab where to begin looking for the end. int subredditEnd = subredditStart + 2; int subredditTextStart = subredditStart + 2; // If we start with a / we need to +1 to the end. if (markdown[subredditStart] == '/') { subredditEnd++; } // While we didn't hit the end && (it is a char or digit or _ ) subredditEnd = Common.FindNextNonLetterDigitOrUnderscore(ref markdown, subredditEnd, endingPos, true); // Validate if (subredditEnd != endingPos) { DebuggingReporter.ReportCriticalError("Raw subreddit ending didn't match endingPos"); } // Grab the text Text = markdown.Substring(subredditStart, subredditEnd - subredditStart); // Return what we consumed return(subredditEnd); }
/// <summary> /// Called to preform a render of the current Markdown. /// </summary> private void RenderMarkdown() { // Make sure we have something to parse. if (string.IsNullOrWhiteSpace(Text)) { return; } // Leave if we don't have our root yet. if (_rootElement == null) { return; } // Disconnect from OnClick handlers. UnhookListeners(); MarkdownRenderedEventArgs markdownRenderedArgs = new MarkdownRenderedEventArgs(null); try { // Try to parse the markdown. MarkdownDocument markdown = new MarkdownDocument(); markdown.Parse(Text); // Now try to display it var renderer = new XamlRenderer(markdown, this, this) { Background = Background, BorderBrush = BorderBrush, BorderThickness = BorderThickness, CharacterSpacing = CharacterSpacing, FontFamily = FontFamily, FontSize = FontSize, FontStretch = FontStretch, FontStyle = FontStyle, FontWeight = FontWeight, Foreground = Foreground, IsTextSelectionEnabled = IsTextSelectionEnabled, Padding = Padding, CodeBackground = CodeBackground, CodeBorderBrush = CodeBorderBrush, CodeBorderThickness = CodeBorderThickness, CodeForeground = CodeForeground, CodeFontFamily = CodeFontFamily, CodePadding = CodePadding, CodeMargin = CodeMargin, Header1FontSize = Header1FontSize, Header1FontWeight = Header1FontWeight, Header1Margin = Header1Margin, Header1Foreground = Header1Foreground, Header2FontSize = Header2FontSize, Header2FontWeight = Header2FontWeight, Header2Margin = Header2Margin, Header2Foreground = Header2Foreground, Header3FontSize = Header3FontSize, Header3FontWeight = Header3FontWeight, Header3Margin = Header3Margin, Header3Foreground = Header3Foreground, Header4FontSize = Header4FontSize, Header4FontWeight = Header4FontWeight, Header4Margin = Header4Margin, Header4Foreground = Header4Foreground, Header5FontSize = Header5FontSize, Header5FontWeight = Header5FontWeight, Header5Margin = Header5Margin, Header5Foreground = Header5Foreground, Header6FontSize = Header6FontSize, Header6FontWeight = Header6FontWeight, Header6Margin = Header6Margin, Header6Foreground = Header6Foreground, HorizontalRuleBrush = HorizontalRuleBrush, HorizontalRuleMargin = HorizontalRuleMargin, HorizontalRuleThickness = HorizontalRuleThickness, ListMargin = ListMargin, ListGutterWidth = ListGutterWidth, ListBulletSpacing = ListBulletSpacing, ParagraphMargin = ParagraphMargin, QuoteBackground = QuoteBackground, QuoteBorderBrush = QuoteBorderBrush, QuoteBorderThickness = QuoteBorderThickness, QuoteForeground = QuoteForeground, QuoteMargin = QuoteMargin, QuotePadding = QuotePadding, TableBorderBrush = TableBorderBrush, TableBorderThickness = TableBorderThickness, TableCellPadding = TableCellPadding, TableMargin = TableMargin, TextWrapping = TextWrapping, LinkForeground = LinkForeground, ImageStretch = ImageStretch }; _rootElement.Child = renderer.Render(); } catch (Exception ex) { DebuggingReporter.ReportCriticalError("Error while parsing and rendering: " + ex.Message); markdownRenderedArgs = new MarkdownRenderedEventArgs(ex); } // Indicate that the parse is done. MarkdownRendered?.Invoke(this, markdownRenderedArgs); }
/// <summary> /// Called when this block type should parse out the goods. Given the markdown, a starting point, and a max ending point /// the block should find the start of the block, find the end and parse out the middle. The end most of the time will not be /// the max ending pos, but it sometimes can be. The function will return where it ended parsing the block in the markdown. /// </summary> /// <param name="markdown"></param> /// <param name="startingPos"></param> /// <param name="maxEndingPos"></param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int maxEndingPos) { // Find where the code begins, since we are given the line after the last space we actually need // to go backwards. int spaceCountStart = startingPos - 1; int spaceCount = 0; while (spaceCountStart >= 0) { // If we found a space count it if (markdown[spaceCountStart] == ' ') { spaceCount++; } else { if (spaceCount > 3) { // We found the next char after the code begin break; } else { // We found a char that broke the space count spaceCount = 0; } } spaceCountStart--; } if (spaceCount == 0) { DebuggingReporter.ReportCriticalError("Tried to code but found no space row > 3"); } // Find the end of code, note code breaks with a single new line no matter what. int codeEnd = Common.FindNextSingleNewLine(ref markdown, startingPos, maxEndingPos); if (codeEnd == -1) { DebuggingReporter.ReportCriticalError("Tried to code quote that didn't have an end"); codeEnd = maxEndingPos; } // For every 4 spaces we want to add an indent CodeIndent = (int)Math.Floor(spaceCount / 4.0); // Make sure there is something to parse, and not just dead space if (codeEnd > startingPos) { // Parse the children of this quote ParseInlineChildren(ref markdown, startingPos, codeEnd); } // Trim off any extra line endings, except ' ' otherwise we can't do code blocks while (codeEnd < markdown.Length && codeEnd < maxEndingPos && Char.IsWhiteSpace(markdown[codeEnd]) && markdown[codeEnd] != ' ') { codeEnd++; } // Return where we ended. return(codeEnd); }
/// <summary> /// Called when this block type should parse out the goods. Given the markdown, a starting point, and a max ending point /// the block should find the start of the block, find the end and parse out the middle. The end most of the time will not be /// the max ending pos, but it sometimes can be. The function will return where it ended parsing the block in the markdown. /// </summary> /// <param name="markdown"></param> /// <param name="startingPos"></param> /// <param name="maxEndingPos"></param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int maxEndingPos) { // Find out what the list is and where it begins. int listStart = startingPos; while (listStart < markdown.Length && listStart < maxEndingPos) { // We have a bullet list if (markdown[listStart] == '*' || markdown[listStart] == '-') { ListBullet = "•"; // +1 to move past the ' ' listStart++; break; } // We have a letter or digit list, start grabbing the bullet else if (Char.IsLetterOrDigit(markdown[listStart])) { // Grab the list letter, but keep going to get the rest. ListBullet += markdown[listStart]; } // We finished the letter list. else if (markdown[listStart] == '.') { ListBullet += '.'; break; } listStart++; } // Now figure out how many spaces come before this list, we have to count backwards from the starting pos. ListIndent = 0; int currentBackCount = startingPos - 1; while (currentBackCount >= 0 && markdown[currentBackCount] != '\n' && markdown[currentBackCount] != '\r') { ListIndent++; currentBackCount--; } // A list should only single newline break if it is that start of another element in the list. // So we need to loop to check for them. // This is hard becasue of all of our list types. For * and - we just check if the next two chars // are * or and a ' ' if so we matched. For letters and digits, once we find one we keep looping until // we find a '.'. If we find a . we get a match, if anything else we fail. int nextDoubleBreak = Common.FindNextDoubleNewLine(ref markdown, listStart, maxEndingPos); int nextSingleBreak = Common.FindNextSingleNewLine(ref markdown, listStart, maxEndingPos); int potentialListStart = -1; int listEnd = nextDoubleBreak; while (nextSingleBreak < nextDoubleBreak && nextSingleBreak + 2 < maxEndingPos) { // Ignore spaces unless we are tracking a potential list start if (potentialListStart == -1 && markdown[nextSingleBreak + 1] == ' ') { nextSingleBreak++; } // Check for a * or a - followed by a space else if ((markdown[nextSingleBreak + 1] == '*' || markdown[nextSingleBreak + 1] == '-') && markdown[nextSingleBreak + 2] == ' ') { // This is our line break listEnd = nextSingleBreak; break; } // If this is a char we might have a new list start. Note the position and loop. else if (Char.IsLetterOrDigit(markdown[nextSingleBreak + 1])) { if (potentialListStart == -1) { potentialListStart = nextSingleBreak; } nextSingleBreak++; } // If we find a . and we have a potential list start then we matched. else if (potentialListStart != -1 && markdown[nextSingleBreak + 1] == '.') { // This is our line break listEnd = potentialListStart; break; } else { // We failed with this new line, try to get the next one. nextSingleBreak = Common.FindNextSingleNewLine(ref markdown, nextSingleBreak + 1, maxEndingPos); potentialListStart = -1; } } if (listEnd == -1) { DebuggingReporter.ReportCriticalError("Tried to parse list that didn't have an end"); listEnd = maxEndingPos; } // Remove one indent from the list. This doesn't work exactly like reddit's // but it is close enough ListIndent = Math.Max(1, ListIndent - 1); // Jump past the * listStart++; // Make sure there is something to parse, and not just dead space if (listEnd > listStart) { // Parse the children of this list ParseInlineChildren(ref markdown, listStart, listEnd); } // Trim off any extra line endings, except ' ' otherwise we can't do code blocks while (listEnd < markdown.Length && listEnd < maxEndingPos && Char.IsWhiteSpace(markdown[listEnd]) && markdown[listEnd] != ' ') { listEnd++; } // Return where we ended. return(listEnd); }
/// <summary> /// Called when the object should parse it's goods out of the markdown. The markdown, start, and stop are given. /// The start and stop are what is returned from the FindNext function below. The object should do it's parsing and /// return up to the last pos it used. This can be shorter than what is given to the function in endingPos. /// </summary> /// <param name="markdown">The markdown</param> /// <param name="startingPos">Where the parse should start</param> /// <param name="endingPos">Where the parse should end</param> /// <returns></returns> internal override int Parse(ref string markdown, int startingPos, int endingPos) { // Find all of the link parts int linkTextOpen = Common.IndexOf(ref markdown, '[', startingPos, endingPos); int linkTextClose = Common.IndexOf(ref markdown, ']', linkTextOpen, endingPos); int linkOpen = Common.IndexOf(ref markdown, '(', linkTextClose, endingPos); int linkClose = Common.IndexOf(ref markdown, ')', linkOpen, endingPos); // These should always be = if (linkTextOpen != startingPos) { DebuggingReporter.ReportCriticalError("link parse didn't find [ in at the starting pos"); } if (linkClose + 1 != endingPos) { DebuggingReporter.ReportCriticalError("link parse didn't find ] in at the end pos"); } // Make sure there is something to parse, and not just dead space linkTextOpen++; if (linkTextClose > linkTextOpen) { // Parse any children of this link element ParseInlineChildren(ref markdown, linkTextOpen, linkTextClose); } // We can't render links in links. So if anything in the children of this is a link // we have to remove it for (int count = 0; count < Children.Count; count++) { // Look through the children for a link, if found grab the text MarkdownInlineType type = ((MarkdownInline)Children[count]).Type; string replaceText = null; if (type == MarkdownInlineType.MarkdownLink) { // If it is a link just grab the URL. Ideally we would grab the text // but that is too hard and this will never happen. replaceText = ((MarkdownLinkInline)Children[count]).Url; } else if (type == MarkdownInlineType.RawHyperlink) { replaceText = ((RawHyperlinkInline)Children[count]).Url; } else if (type == MarkdownInlineType.RawSubreddit) { replaceText = ((RawSubredditInline)Children[count]).Text; } // If we found text to replace add a new text element as the text. if (replaceText != null) { TextRunInline textRun = new TextRunInline(); textRun.Text = replaceText; Children[count] = textRun; } } // Grab the link linkOpen++; Url = markdown.Substring(linkOpen, linkClose - linkOpen); // Return the point after the ) return(linkClose + 1); }
/// <summary> /// Fired when the value of a DependencyProperty is changed. /// </summary> /// <param name="d"></param> /// <param name="prop"></param> private void OnPropertyChanged(DependencyObject d, DependencyProperty prop) { // Make sure we have something to parse. if (Markdown == null) { return; } // Disconnect from OnClick handlers. UnhookListeners(); var args = new OnMarkdownReadyArgs(); try { // Try to parse the markdown. MarkdownDocument markdown = new MarkdownDocument(); markdown.Parse(Markdown); // Now try to display it var renderer = new XamlRenderer(markdown, this); renderer.Background = Background; renderer.BorderBrush = BorderBrush; renderer.BorderThickness = BorderThickness; renderer.CharacterSpacing = CharacterSpacing; renderer.FontFamily = FontFamily; renderer.FontSize = FontSize; renderer.FontStretch = FontStretch; renderer.FontStyle = FontStyle; renderer.FontWeight = FontWeight; renderer.Foreground = Foreground; renderer.IsTextSelectionEnabled = IsTextSelectionEnabled; renderer.Padding = Padding; renderer.CodeBackground = CodeBackground; renderer.CodeBorderBrush = CodeBorderBrush; renderer.CodeBorderThickness = CodeBorderThickness; renderer.CodeForeground = CodeForeground; renderer.CodeFontFamily = CodeFontFamily; renderer.CodePadding = CodePadding; renderer.CodeMargin = CodeMargin; renderer.Header1FontSize = Header1FontSize; renderer.Header1FontWeight = Header1FontWeight; renderer.Header1Margin = Header1Margin; renderer.Header2FontSize = Header2FontSize; renderer.Header2FontWeight = Header2FontWeight; renderer.Header2Margin = Header2Margin; renderer.Header3FontSize = Header3FontSize; renderer.Header3FontWeight = Header3FontWeight; renderer.Header3Margin = Header3Margin; renderer.Header4FontSize = Header4FontSize; renderer.Header4FontWeight = Header4FontWeight; renderer.Header4Margin = Header4Margin; renderer.Header5FontSize = Header5FontSize; renderer.Header5FontWeight = Header5FontWeight; renderer.Header5Margin = Header5Margin; renderer.Header6FontSize = Header6FontSize; renderer.Header6FontWeight = Header6FontWeight; renderer.Header6Margin = Header6Margin; renderer.HorizontalRuleBrush = HorizontalRuleBrush; renderer.HorizontalRuleMargin = HorizontalRuleMargin; renderer.HorizontalRuleThickness = HorizontalRuleThickness; renderer.ListMargin = ListMargin; renderer.ListGutterWidth = ListGutterWidth; renderer.ListBulletSpacing = ListBulletSpacing; renderer.ParagraphMargin = ParagraphMargin; renderer.QuoteBackground = QuoteBackground; renderer.QuoteBorderBrush = QuoteBorderBrush; renderer.QuoteBorderThickness = QuoteBorderThickness; renderer.QuoteForeground = QuoteForeground; renderer.QuoteMargin = QuoteMargin; renderer.QuotePadding = QuotePadding; renderer.TableBorderBrush = TableBorderBrush; renderer.TableBorderThickness = TableBorderThickness; renderer.TableCellPadding = TableCellPadding; renderer.TableMargin = TableMargin; renderer.TextWrapping = TextWrapping; Content = renderer.Render(); } catch (Exception ex) { DebuggingReporter.ReportCriticalError("Error while parsing and rendering: " + ex.Message); args.WasError = true; args.Exception = ex; } // #todo indicate if ready m_onMarkdownReady.Raise(this, args); }