diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml
index 1ead34838..69430b398 100644
--- a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml
+++ b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml
@@ -41,6 +41,11 @@
+ Text="{x:Bind Text, Mode=OneTime}"
+ UseAutoLinks="True"
+ UseEmphasisExtras="True"
+ UseListExtras="True"
+ UsePipeTables="True"
+ UseTaskLists="True" />
diff --git a/components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs b/components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs
new file mode 100644
index 000000000..fb0bd4180
--- /dev/null
+++ b/components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs
@@ -0,0 +1,170 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Markdig.Syntax;
+
+namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock;
+
+public partial class MarkdownTextBlock
+{
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(
+ nameof(Config),
+ typeof(MarkdownConfig),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(null, OnConfigChanged)
+ );
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty TextProperty = DependencyProperty.Register(
+ nameof(Text),
+ typeof(string),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(null, OnTextChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty UseEmphasisExtrasProperty = DependencyProperty.Register(
+ nameof(UseEmphasisExtras),
+ typeof(bool),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(false));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty UsePipeTablesProperty = DependencyProperty.Register(
+ nameof(UsePipeTables),
+ typeof(bool),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(false));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty UseListExtrasProperty = DependencyProperty.Register(
+ nameof(UseListExtras),
+ typeof(bool),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(false));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty UseTaskListsProperty = DependencyProperty.Register(
+ nameof(UseTaskLists),
+ typeof(bool),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(false));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty UseAutoLinksProperty = DependencyProperty.Register(
+ nameof(UseAutoLinks),
+ typeof(bool),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(false));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty UseSoftlineBreakAsHardlineBreakProperty = DependencyProperty.Register(
+ nameof(UseSoftlineBreakAsHardlineBreak),
+ typeof(bool),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(false));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ private static readonly DependencyProperty MarkdownDocumentProperty = DependencyProperty.Register(
+ nameof(MarkdownDocument),
+ typeof(MarkdownDocument),
+ typeof(MarkdownTextBlock),
+ new PropertyMetadata(null));
+
+ public MarkdownConfig Config
+ {
+ get => (MarkdownConfig)GetValue(ConfigProperty);
+ set => SetValue(ConfigProperty, value);
+ }
+
+ ///
+ /// Gets or sets the markdown text to display.
+ ///
+ public string Text
+ {
+ get => (string)GetValue(TextProperty);
+ set => SetValue(TextProperty, value);
+ }
+
+ ///
+ /// If true, adds support for strikethroughs, superscript, subscript, inserted, and marked text.
+ ///
+ public bool UseEmphasisExtras
+ {
+ get => (bool)GetValue(UseEmphasisExtrasProperty);
+ set => SetValue(UseEmphasisExtrasProperty, value);
+ }
+
+ ///
+ /// If true, adds support for GitHub-style pipe tables.
+ ///
+ public bool UsePipeTables
+ {
+ get => (bool)GetValue(UsePipeTablesProperty);
+ set => SetValue(UsePipeTablesProperty, value);
+ }
+
+ ///
+ /// If true, adds support for alphabetic and roman numbering in lists.
+ ///
+ public bool UseListExtras
+ {
+ get => (bool)GetValue(UseListExtrasProperty);
+ set => SetValue(UseListExtrasProperty, value);
+ }
+
+ ///
+ /// If true, adds support for GitHub-style task lists using the [ ] and [x] syntax.
+ ///
+ public bool UseTaskLists
+ {
+ get => (bool)GetValue(UseTaskListsProperty);
+ set => SetValue(UseTaskListsProperty, value);
+ }
+
+ ///
+ /// If true, parses text that looks like URIs into hyperlinks (e.g. https://...).
+ ///
+ public bool UseAutoLinks
+ {
+ get => (bool)GetValue(UseAutoLinksProperty);
+ set => SetValue(UseAutoLinksProperty, value);
+ }
+
+ ///
+ /// If true, considers single newlines as hardline breaks.
+ ///
+ public bool UseSoftlineBreakAsHardlineBreak
+ {
+ get => (bool)GetValue(UseSoftlineBreakAsHardlineBreakProperty);
+ set => SetValue(UseSoftlineBreakAsHardlineBreakProperty, value);
+ }
+
+ ///
+ /// Gets the parsed markdown document. May be null if the document has not been parsed yet.
+ ///
+ public MarkdownDocument? MarkdownDocument
+ {
+ get => (MarkdownDocument)GetValue(MarkdownDocumentProperty);
+ private set => SetValue(MarkdownDocumentProperty, value);
+ }
+}
diff --git a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs
index 01e05751f..d9b8be705 100644
--- a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs
+++ b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs
@@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers;
+using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers;
+using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers.Extensions;
+using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers.Inlines;
using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.TextElements;
using Markdig;
using Markdig.Syntax;
@@ -14,47 +17,10 @@ public partial class MarkdownTextBlock : Control
{
private const string MarkdownContainerName = "MarkdownContainer";
private Grid? _container;
- private MarkdownPipeline _pipeline;
+ private MarkdownPipeline _pipeline = null!;
private MyFlowDocument _document;
private WinUIRenderer? _renderer;
- private static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(
- nameof(Config),
- typeof(MarkdownConfig),
- typeof(MarkdownTextBlock),
- new PropertyMetadata(null, OnConfigChanged)
- );
-
- private static readonly DependencyProperty TextProperty = DependencyProperty.Register(
- nameof(Text),
- typeof(string),
- typeof(MarkdownTextBlock),
- new PropertyMetadata(null, OnTextChanged));
-
- private static readonly DependencyProperty MarkdownDocumentProperty = DependencyProperty.Register(
- nameof(MarkdownDocument),
- typeof(MarkdownDocument),
- typeof(MarkdownTextBlock),
- new PropertyMetadata(null));
-
- public MarkdownConfig Config
- {
- get => (MarkdownConfig)GetValue(ConfigProperty);
- set => SetValue(ConfigProperty, value);
- }
-
- public string Text
- {
- get => (string)GetValue(TextProperty);
- set => SetValue(TextProperty, value);
- }
-
- public MarkdownDocument? MarkdownDocument
- {
- get => (MarkdownDocument)GetValue(MarkdownDocumentProperty);
- private set => SetValue(MarkdownDocumentProperty, value);
- }
-
public event EventHandler? OnLinkClicked;
internal void RaiseLinkClickedEvent(Uri uri) => OnLinkClicked?.Invoke(this, new LinkClickedEventArgs(uri));
@@ -79,17 +45,24 @@ public MarkdownTextBlock()
{
this.DefaultStyleKey = typeof(MarkdownTextBlock);
_document = new MyFlowDocument();
- _pipeline = new MarkdownPipelineBuilder()
- .UseEmphasisExtras()
- .UseAutoLinks()
- .UseTaskLists()
- .UsePipeTables()
- .Build();
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
+
+ var pipelineBuilder = new MarkdownPipelineBuilder();
+
+ // NOTE: Order matters here
+ if (UseEmphasisExtras) pipelineBuilder = pipelineBuilder.UseEmphasisExtras();
+ if (UsePipeTables) pipelineBuilder = pipelineBuilder.UsePipeTables();
+ if (UseListExtras) pipelineBuilder = pipelineBuilder.UseListExtras();
+ if (UseTaskLists) pipelineBuilder = pipelineBuilder.UseTaskLists();
+ if (UseAutoLinks) pipelineBuilder = pipelineBuilder.UseAutoLinks();
+ if (UseSoftlineBreakAsHardlineBreak) pipelineBuilder = pipelineBuilder.UseSoftlineBreakAsHardlineBreak();
+
+ _pipeline = pipelineBuilder.Build();
+
_container = (Grid)GetTemplateChild(MarkdownContainerName);
_container.Children.Clear();
_container.Children.Add(_document.RichTextBlock);
@@ -128,6 +101,31 @@ private void Build()
if (_renderer == null)
{
_renderer = new WinUIRenderer(_document, Config, this);
+
+ // Default block renderers
+ _renderer.ObjectRenderers.Add(new CodeBlockRenderer());
+ _renderer.ObjectRenderers.Add(new ListRenderer());
+ _renderer.ObjectRenderers.Add(new HeadingRenderer());
+ _renderer.ObjectRenderers.Add(new ParagraphRenderer());
+ _renderer.ObjectRenderers.Add(new QuoteBlockRenderer());
+ _renderer.ObjectRenderers.Add(new ThematicBreakRenderer());
+ _renderer.ObjectRenderers.Add(new HtmlBlockRenderer());
+
+ // Default inline renderers
+ if (UseAutoLinks) _renderer.ObjectRenderers.Add(new AutoLinkInlineRenderer());
+ _renderer.ObjectRenderers.Add(new CodeInlineRenderer());
+ _renderer.ObjectRenderers.Add(new DelimiterInlineRenderer());
+ _renderer.ObjectRenderers.Add(new EmphasisInlineRenderer());
+ _renderer.ObjectRenderers.Add(new HtmlEntityInlineRenderer());
+ _renderer.ObjectRenderers.Add(new LineBreakInlineRenderer());
+ _renderer.ObjectRenderers.Add(new LinkInlineRenderer());
+ _renderer.ObjectRenderers.Add(new LiteralInlineRenderer());
+ _renderer.ObjectRenderers.Add(new ContainerInlineRenderer());
+
+ // Extension renderers
+ if (UsePipeTables) _renderer.ObjectRenderers.Add(new TableRenderer());
+ if (UseTaskLists) _renderer.ObjectRenderers.Add(new TaskListRenderer());
+ _renderer.ObjectRenderers.Add(new HtmlInlineRenderer());
}
_pipeline.Setup(_renderer);
ApplyText(false);
diff --git a/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs b/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs
index a9f772423..c4e00543b 100644
--- a/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs
+++ b/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs
@@ -33,12 +33,6 @@ public WinUIRenderer(MyFlowDocument document, MarkdownConfig config, MarkdownTex
FlowDocument = document;
// set style
_stack.Push(FlowDocument);
- LoadOverridenRenderers();
- }
-
- private void LoadOverridenRenderers()
- {
- LoadRenderers();
}
public override object Render(MarkdownObject markdownObject)
@@ -52,7 +46,6 @@ public void ReloadDocument()
_stack.Clear();
FlowDocument.RichTextBlock.Blocks.Clear();
_stack.Push(FlowDocument);
- LoadOverridenRenderers();
}
public void WriteLeafInline(LeafBlock leafBlock)
@@ -145,32 +138,4 @@ private static void AddInline(IAddChild parent, IAddChild inline)
{
parent.AddChild(inline);
}
-
- protected virtual void LoadRenderers()
- {
- // Default block renderers
- ObjectRenderers.Add(new CodeBlockRenderer());
- ObjectRenderers.Add(new ListRenderer());
- ObjectRenderers.Add(new HeadingRenderer());
- ObjectRenderers.Add(new ParagraphRenderer());
- ObjectRenderers.Add(new QuoteBlockRenderer());
- ObjectRenderers.Add(new ThematicBreakRenderer());
- ObjectRenderers.Add(new HtmlBlockRenderer());
-
- // Default inline renderers
- ObjectRenderers.Add(new AutoLinkInlineRenderer());
- ObjectRenderers.Add(new CodeInlineRenderer());
- ObjectRenderers.Add(new DelimiterInlineRenderer());
- ObjectRenderers.Add(new EmphasisInlineRenderer());
- ObjectRenderers.Add(new HtmlEntityInlineRenderer());
- ObjectRenderers.Add(new LineBreakInlineRenderer());
- ObjectRenderers.Add(new LinkInlineRenderer());
- ObjectRenderers.Add(new LiteralInlineRenderer());
- ObjectRenderers.Add(new ContainerInlineRenderer());
-
- // Extension renderers
- ObjectRenderers.Add(new TableRenderer());
- ObjectRenderers.Add(new TaskListRenderer());
- ObjectRenderers.Add(new HtmlInlineRenderer());
- }
}