diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlock.md b/components/MarkdownTextBlock/samples/MarkdownTextBlock.md
index c43b67567..87b2bde3e 100644
--- a/components/MarkdownTextBlock/samples/MarkdownTextBlock.md
+++ b/components/MarkdownTextBlock/samples/MarkdownTextBlock.md
@@ -34,3 +34,9 @@ See all the markdown features and syntax supported by the control:
Try typing markdown and see it rendered in real-time:
> [!Sample MarkdownTextBlockLiveEditorSample]
+
+## Custom theme sample
+Try different styling options for all markdown elements with a custom theme:
+
+> [!Sample MarkdownTextBlockCustomThemeSample]
+
diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomThemeSample.xaml b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomThemeSample.xaml
new file mode 100644
index 000000000..c5d228654
--- /dev/null
+++ b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomThemeSample.xaml
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomThemeSample.xaml.cs b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomThemeSample.xaml.cs
new file mode 100644
index 000000000..02897311c
--- /dev/null
+++ b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomThemeSample.xaml.cs
@@ -0,0 +1,498 @@
+// 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 CommunityToolkit.WinUI.Controls;
+using Microsoft.UI;
+using System.Runtime.CompilerServices;
+using Windows.UI;
+
+
+#if !WINAPPSDK
+using FontWeights = Windows.UI.Text.FontWeights;
+#else
+using FontWeights = Microsoft.UI.Text.FontWeights;
+#endif
+
+namespace MarkdownTextBlockExperiment.Samples;
+
+///
+/// A sample demonstrating custom theming options for the MarkdownTextBlock control with live editing.
+///
+[ToolkitSample(id: nameof(MarkdownTextBlockCustomThemeSample), "Custom Theme", description: "A sample showcasing custom theming options with live editing for headings, code blocks, quotes, tables, and more.")]
+public sealed partial class MarkdownTextBlockCustomThemeSample : Page, INotifyPropertyChanged
+{
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ public MarkdownConfig MarkdownConfig { get; private set; }
+ public MarkdownThemes Themes => MarkdownConfig.Themes;
+
+ private string _markdownText = "";
+ public string MarkdownText
+ {
+ get => _markdownText;
+ set { _markdownText = value; OnPropertyChanged(); }
+ }
+
+ // === Heading Properties ===
+ private double _h1FontSize = 28;
+ public double H1FontSize
+ {
+ get => _h1FontSize;
+ set { _h1FontSize = value; OnPropertyChanged(); }
+ }
+
+ private double _h2FontSize = 24;
+ public double H2FontSize
+ {
+ get => _h2FontSize;
+ set { _h2FontSize = value; OnPropertyChanged(); }
+ }
+
+ private double _h3FontSize = 20;
+ public double H3FontSize
+ {
+ get => _h3FontSize;
+ set { _h3FontSize = value; OnPropertyChanged(); }
+ }
+
+ private int _h1ColorIndex = 0;
+ public int H1ColorIndex
+ {
+ get => _h1ColorIndex;
+ set { _h1ColorIndex = value; OnPropertyChanged(); }
+ }
+
+ // === Inline Code Properties ===
+ private double _inlineCodeFontSize = 13;
+ public double InlineCodeFontSize
+ {
+ get => _inlineCodeFontSize;
+ set { _inlineCodeFontSize = value; OnPropertyChanged(); }
+ }
+
+ private double _inlineCodePadding = 4;
+ public double InlineCodePadding
+ {
+ get => _inlineCodePadding;
+ set { _inlineCodePadding = value; OnPropertyChanged(); }
+ }
+
+ private double _inlineCodeCornerRadius = 4;
+ public double InlineCodeCornerRadius
+ {
+ get => _inlineCodeCornerRadius;
+ set { _inlineCodeCornerRadius = value; OnPropertyChanged(); }
+ }
+
+ private double _inlineCodeBorderThickness = 1;
+ public double InlineCodeBorderThickness
+ {
+ get => _inlineCodeBorderThickness;
+ set { _inlineCodeBorderThickness = value; OnPropertyChanged(); }
+ }
+
+ private int _inlineCodeColorIndex = 0;
+ public int InlineCodeColorIndex
+ {
+ get => _inlineCodeColorIndex;
+ set { _inlineCodeColorIndex = value; OnPropertyChanged(); }
+ }
+
+ private int _inlineCodeBackgroundColorIndex = 0;
+ public int InlineCodeBackgroundColorIndex
+ {
+ get => _inlineCodeBackgroundColorIndex;
+ set { _inlineCodeBackgroundColorIndex = value; OnPropertyChanged(); }
+ }
+
+ private int _inlineCodeBorderColorIndex = 0;
+ public int InlineCodeBorderColorIndex
+ {
+ get => _inlineCodeBorderColorIndex;
+ set { _inlineCodeBorderColorIndex = value; OnPropertyChanged(); }
+ }
+
+ // === Code Block Properties ===
+ private double _codeBlockPadding = 12;
+ public double CodeBlockPadding
+ {
+ get => _codeBlockPadding;
+ set { _codeBlockPadding = value; OnPropertyChanged(); }
+ }
+
+ private double _codeBlockCornerRadius = 8;
+ public double CodeBlockCornerRadius
+ {
+ get => _codeBlockCornerRadius;
+ set { _codeBlockCornerRadius = value; OnPropertyChanged(); }
+ }
+
+ private double _codeBlockBorderThickness = 1;
+ public double CodeBlockBorderThickness
+ {
+ get => _codeBlockBorderThickness;
+ set { _codeBlockBorderThickness = value; OnPropertyChanged(); }
+ }
+
+ private int _codeBlockFontIndex = 0;
+ public int CodeBlockFontIndex
+ {
+ get => _codeBlockFontIndex;
+ set { _codeBlockFontIndex = value; OnPropertyChanged(); }
+ }
+
+ private int _codeBlockBackgroundColorIndex = 0;
+ public int CodeBlockBackgroundColorIndex
+ {
+ get => _codeBlockBackgroundColorIndex;
+ set { _codeBlockBackgroundColorIndex = value; OnPropertyChanged(); }
+ }
+
+ private int _codeBlockBorderColorIndex = 0;
+ public int CodeBlockBorderColorIndex
+ {
+ get => _codeBlockBorderColorIndex;
+ set { _codeBlockBorderColorIndex = value; OnPropertyChanged(); }
+ }
+
+ // === Quote Properties ===
+ private double _quoteBorderWidth = 4;
+ public double QuoteBorderWidth
+ {
+ get => _quoteBorderWidth;
+ set { _quoteBorderWidth = value; OnPropertyChanged(); }
+ }
+
+ private double _quotePadding = 12;
+ public double QuotePadding
+ {
+ get => _quotePadding;
+ set { _quotePadding = value; OnPropertyChanged(); }
+ }
+
+ private double _quoteCornerRadius = 8;
+ public double QuoteCornerRadius
+ {
+ get => _quoteCornerRadius;
+ set { _quoteCornerRadius = value; OnPropertyChanged(); }
+ }
+
+ private int _quoteColorIndex = 0;
+ public int QuoteColorIndex
+ {
+ get => _quoteColorIndex;
+ set { _quoteColorIndex = value; OnPropertyChanged(); }
+ }
+
+ // === Table Properties ===
+ private double _tableCellPadding = 8;
+ public double TableCellPadding
+ {
+ get => _tableCellPadding;
+ set { _tableCellPadding = value; OnPropertyChanged(); }
+ }
+
+ private double _tableBorderThickness = 1;
+ public double TableBorderThickness
+ {
+ get => _tableBorderThickness;
+ set { _tableBorderThickness = value; OnPropertyChanged(); }
+ }
+
+ // === Horizontal Rule Properties ===
+ private double _horizontalRuleThickness = 2;
+ public double HorizontalRuleThickness
+ {
+ get => _horizontalRuleThickness;
+ set { _horizontalRuleThickness = value; OnPropertyChanged(); }
+ }
+
+ private double _horizontalRuleMargin = 16;
+ public double HorizontalRuleMargin
+ {
+ get => _horizontalRuleMargin;
+ set { _horizontalRuleMargin = value; OnPropertyChanged(); }
+ }
+
+ // === Image Properties ===
+ private double _imageMaxWidth = 0;
+ public double ImageMaxWidth
+ {
+ get => _imageMaxWidth;
+ set { _imageMaxWidth = value; OnPropertyChanged(); }
+ }
+
+ private double _imageMaxHeight = 0;
+ public double ImageMaxHeight
+ {
+ get => _imageMaxHeight;
+ set { _imageMaxHeight = value; OnPropertyChanged(); }
+ }
+
+ private int _imageStretchIndex = 0;
+ public int ImageStretchIndex
+ {
+ get => _imageStretchIndex;
+ set { _imageStretchIndex = value; OnPropertyChanged(); }
+ }
+
+ // Color lookup helpers
+ private static readonly Brush[] HeadingColors = new Brush[]
+ {
+ new SolidColorBrush(Colors.DodgerBlue),
+ new SolidColorBrush(Colors.Coral),
+ new SolidColorBrush(Colors.MediumSeaGreen),
+ new SolidColorBrush(Colors.Gold),
+ new SolidColorBrush(Colors.Orchid),
+ (Brush)Application.Current.Resources["TextFillColorPrimaryBrush"]
+ };
+
+ private static readonly Brush[] InlineCodeColors = new Brush[]
+ {
+ new SolidColorBrush(Colors.Orange),
+ new SolidColorBrush(Colors.Coral),
+ new SolidColorBrush(Colors.LimeGreen),
+ new SolidColorBrush(Colors.DeepSkyBlue),
+ (Brush)Application.Current.Resources["TextFillColorPrimaryBrush"]
+ };
+
+ private static readonly Brush[] CodeBackgroundColors = new Brush[]
+ {
+ new SolidColorBrush(Color.FromArgb(40, 100, 100, 255)),
+ new SolidColorBrush(Color.FromArgb(30, 50, 50, 80)),
+ new SolidColorBrush(Color.FromArgb(40, 0, 0, 0)),
+ new SolidColorBrush(Color.FromArgb(40, 50, 150, 50)),
+ (Brush)Application.Current.Resources["ExpanderHeaderBackground"]
+ };
+
+ private static readonly Brush[] CodeBorderColors = new Brush[]
+ {
+ new SolidColorBrush(Colors.SlateGray),
+ new SolidColorBrush(Colors.DimGray),
+ new SolidColorBrush(Colors.DarkSlateGray),
+ new SolidColorBrush(Colors.MediumSlateBlue),
+ new SolidColorBrush(Colors.Transparent)
+ };
+
+ private static readonly Brush[] QuoteColors = new Brush[]
+ {
+ new SolidColorBrush(Colors.DodgerBlue),
+ new SolidColorBrush(Colors.Gray),
+ new SolidColorBrush(Colors.MediumSeaGreen),
+ new SolidColorBrush(Colors.Coral)
+ };
+
+ private static readonly FontFamily[] CodeFonts = new FontFamily[]
+ {
+ new FontFamily("Cascadia Code"),
+ new FontFamily("Consolas"),
+ new FontFamily("Courier New"),
+ new FontFamily("Segoe UI")
+ };
+
+ private static readonly Stretch[] ImageStretchOptions = new Stretch[]
+ {
+ Stretch.Uniform,
+ Stretch.None,
+ Stretch.Fill,
+ Stretch.UniformToFill
+ };
+
+ private const string SampleMarkdown = @"
+# Custom Theme Demo
+
+This sample demonstrates the **custom theming** capabilities of the `MarkdownTextBlock` control.
+
+## Heading Styles
+
+Each heading level has customizable foreground color, font size, weight, and margin.
+
+### Heading 3
+#### Heading 4
+
+## Inline Code
+
+Here is some `inline code` with custom styling. Try adjusting the padding, corner radius, and colors in the editor panel!
+
+Another example: `config.Themes.InlineCodePadding`
+
+## Images
+
+Images can be styled with max width, max height, and stretch options. Notice how the text flows naturally without any gaps above or below the image:
+
+
+
+The image above automatically scales to respect the max width setting while maintaining its aspect ratio. Text continues to flow seamlessly below it.
+
+## Code Blocks
+
+```csharp
+// Code blocks have custom styling too!
+public class CustomTheme
+{
+ public string Name { get; set; }
+ public Color PrimaryColor { get; set; }
+
+ public void ApplyTheme()
+ {
+ Console.WriteLine($""Applying theme: {Name}"");
+ }
+}
+```
+
+## Block Quotes
+
+> This is a styled block quote with custom background,
+> border color, padding, and corner radius.
+>
+> Try changing the border width and corner radius!
+
+## Links
+
+Check out [this link](https://github.com/CommunityToolkit) - links have custom foreground colors.
+
+## Tables
+
+| Feature | Status | Notes |
+|---------|--------|-------|
+| Headings | ✅ | Per-level colors |
+| Inline Code | ✅ | Full styling |
+| Code Blocks | ✅ | Background, border, font |
+| Quotes | ✅ | Border, background, radius |
+
+---
+
+## Horizontal Rule
+
+The line above is a horizontal rule with customizable thickness and margin.
+
+## Lists
+
+- Adjust the theme settings on the right panel
+- Click **Apply Changes** to see updates
+- Use **Reset to Defaults** to start over
+";
+
+ public MarkdownTextBlockCustomThemeSample()
+ {
+ MarkdownConfig = new MarkdownConfig { Themes = CreateThemes() };
+ _markdownText = SampleMarkdown;
+ this.InitializeComponent();
+ }
+
+ private MarkdownThemes CreateThemes()
+ {
+ return new MarkdownThemes
+ {
+ H1FontSize = H1FontSize,
+ H1FontWeight = FontWeights.Bold,
+ H1Foreground = HeadingColors[H1ColorIndex],
+ H1Margin = new Thickness(0, 20, 0, 10),
+
+ H2FontSize = H2FontSize,
+ H2FontWeight = FontWeights.SemiBold,
+ H2Foreground = new SolidColorBrush(Colors.MediumSlateBlue),
+
+ H3FontSize = H3FontSize,
+ H3FontWeight = FontWeights.SemiBold,
+ H3Foreground = new SolidColorBrush(Colors.MediumPurple),
+
+ InlineCodeFontSize = InlineCodeFontSize,
+ InlineCodePadding = new Thickness(InlineCodePadding, InlineCodePadding / 2, InlineCodePadding, InlineCodePadding / 2),
+ InlineCodeCornerRadius = new CornerRadius(InlineCodeCornerRadius),
+ InlineCodeBorderThickness = new Thickness(InlineCodeBorderThickness),
+ InlineCodeForeground = InlineCodeColors[InlineCodeColorIndex],
+ InlineCodeBackground = CodeBackgroundColors[InlineCodeBackgroundColorIndex],
+ InlineCodeBorderBrush = CodeBorderColors[InlineCodeBorderColorIndex],
+
+ CodeBlockPadding = new Thickness(CodeBlockPadding),
+ CodeBlockCornerRadius = new CornerRadius(CodeBlockCornerRadius),
+ CodeBlockBorderThickness = new Thickness(CodeBlockBorderThickness),
+ CodeBlockFontFamily = CodeFonts[CodeBlockFontIndex],
+ CodeBlockBackground = CodeBackgroundColors[CodeBlockBackgroundColorIndex],
+ CodeBlockForeground = new SolidColorBrush(Colors.LightGreen),
+ CodeBlockBorderBrush = CodeBorderColors[CodeBlockBorderColorIndex],
+
+ QuoteBorderThickness = new Thickness(QuoteBorderWidth, 0, 0, 0),
+ QuotePadding = new Thickness(QuotePadding, QuotePadding / 2, QuotePadding, QuotePadding / 2),
+ QuoteCornerRadius = new CornerRadius(0, QuoteCornerRadius, QuoteCornerRadius, 0),
+ QuoteBorderBrush = QuoteColors[QuoteColorIndex],
+ QuoteBackground = new SolidColorBrush(Color.FromArgb(20, 100, 149, 237)),
+ QuoteForeground = new SolidColorBrush(Colors.CornflowerBlue),
+
+ TableCellPadding = new Thickness(TableCellPadding, TableCellPadding / 2, TableCellPadding, TableCellPadding / 2),
+ TableBorderThickness = TableBorderThickness,
+ TableBorderBrush = new SolidColorBrush(Colors.SlateGray),
+ TableHeadingBackground = new SolidColorBrush(Color.FromArgb(40, 100, 149, 237)),
+
+ HorizontalRuleThickness = HorizontalRuleThickness,
+ HorizontalRuleMargin = new Thickness(0, HorizontalRuleMargin, 0, HorizontalRuleMargin),
+ HorizontalRuleBrush = new SolidColorBrush(Colors.MediumSlateBlue),
+
+ LinkForeground = new SolidColorBrush(Colors.DeepSkyBlue),
+
+ ImageMaxWidth = ImageMaxWidth,
+ ImageMaxHeight = ImageMaxHeight,
+ ImageStretch = ImageStretchOptions[ImageStretchIndex],
+ };
+ }
+
+ private void ApplyTheme_Click(object sender, RoutedEventArgs e)
+ {
+ // Create new config with updated themes and re-render
+ MarkdownConfig = new MarkdownConfig { Themes = CreateThemes() };
+ MarkdownTextBlock.Config = MarkdownConfig;
+
+ // Force re-render by toggling text
+ var text = MarkdownText;
+ MarkdownText = "";
+ MarkdownText = text;
+ }
+
+ private void ResetTheme_Click(object sender, RoutedEventArgs e)
+ {
+ // Reset all values to defaults
+ H1FontSize = 28;
+ H2FontSize = 24;
+ H3FontSize = 20;
+ H1ColorIndex = 0;
+
+ InlineCodeFontSize = 13;
+ InlineCodePadding = 4;
+ InlineCodeCornerRadius = 4;
+ InlineCodeBorderThickness = 1;
+ InlineCodeColorIndex = 0;
+ InlineCodeBackgroundColorIndex = 0;
+ InlineCodeBorderColorIndex = 0;
+
+ CodeBlockPadding = 12;
+ CodeBlockCornerRadius = 8;
+ CodeBlockBorderThickness = 1;
+ CodeBlockFontIndex = 0;
+ CodeBlockBackgroundColorIndex = 1;
+ CodeBlockBorderColorIndex = 1;
+
+ QuoteBorderWidth = 4;
+ QuotePadding = 12;
+ QuoteCornerRadius = 8;
+ QuoteColorIndex = 0;
+
+ TableCellPadding = 8;
+ TableBorderThickness = 1;
+
+ HorizontalRuleThickness = 2;
+ HorizontalRuleMargin = 16;
+
+ ImageMaxWidth = 0;
+ ImageMaxHeight = 0;
+ ImageStretchIndex = 0;
+
+ ApplyTheme_Click(sender, e);
+ }
+}
diff --git a/components/MarkdownTextBlock/src/HtmlWriter.cs b/components/MarkdownTextBlock/src/HtmlWriter.cs
index 40c4b932c..a094b506c 100644
--- a/components/MarkdownTextBlock/src/HtmlWriter.cs
+++ b/components/MarkdownTextBlock/src/HtmlWriter.cs
@@ -33,7 +33,7 @@ public static void WriteHtml(WinUIRenderer renderer, HtmlNodeCollection nodes)
IAddChild hyperLink;
if (node.ChildNodes.Any(n => n.Name != "#text"))
{
- var myHyperlinkButton = new MyHyperlinkButton(node, renderer.Config.BaseUrl);
+ var myHyperlinkButton = new MyHyperlinkButton(node, renderer.Config.BaseUrl, renderer.Config.Themes);
myHyperlinkButton.ClickEvent += (sender, e) =>
{
var button = (HyperlinkButton)sender;
@@ -48,8 +48,7 @@ public static void WriteHtml(WinUIRenderer renderer, HtmlNodeCollection nodes)
}
else
{
- var myHyperlink = new MyHyperlink(node, renderer.Config.BaseUrl);
- myHyperlink.TextElement.Foreground = renderer.Config.Themes.LinkForeground;
+ var myHyperlink = new MyHyperlink(node, renderer.Config.BaseUrl, renderer.Config.Themes);
myHyperlink.ClickEvent += (sender, e) =>
{
var uri = sender.NavigateUri;
diff --git a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Extensions/TableRenderer.cs b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Extensions/TableRenderer.cs
index fd1528807..bc2a8a956 100644
--- a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Extensions/TableRenderer.cs
+++ b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Extensions/TableRenderer.cs
@@ -14,7 +14,8 @@ protected override void Write(WinUIRenderer renderer, Table table)
if (renderer == null) throw new ArgumentNullException(nameof(renderer));
if (table == null) throw new ArgumentNullException(nameof(table));
- var myTable = new MyTable(table, renderer.Config.Themes);
+ var themes = renderer.Config.Themes;
+ var myTable = new MyTable(table, themes);
renderer.Push(myTable);
@@ -47,7 +48,7 @@ protected override void Write(WinUIRenderer renderer, Table table)
};
}
- var myCell = new MyTableCell(cell, textAlignment, row.IsHeader, columnIndex, rowIndex);
+ var myCell = new MyTableCell(cell, textAlignment, row.IsHeader, columnIndex, rowIndex, themes);
renderer.Push(myCell);
renderer.Write(cell);
diff --git a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs
index 8dd0c24c6..c8bf38ffd 100644
--- a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs
+++ b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs
@@ -25,7 +25,7 @@ protected override void Write(WinUIRenderer renderer, AutolinkInline link)
url = "#";
}
- var autolink = new MyAutolinkInline(link);
+ var autolink = new MyAutolinkInline(link, renderer.Config.Themes);
autolink.ClickEvent += (sender, e) =>
{
renderer.MarkdownTextBlock.RaiseLinkClickedEvent(sender.NavigateUri);
diff --git a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs
index c514c45de..d99d67ff2 100644
--- a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs
+++ b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs
@@ -30,7 +30,7 @@ protected override void Write(WinUIRenderer renderer, LinkInline link)
{
if (link.FirstChild is LinkInline linkInlineChild && linkInlineChild.IsImage)
{
- var myHyperlinkButton = new MyHyperlinkButton(link, renderer.Config.BaseUrl);
+ var myHyperlinkButton = new MyHyperlinkButton(link, renderer.Config.BaseUrl, renderer.Config.Themes);
myHyperlinkButton.ClickEvent += (sender, e) =>
{
var button = (HyperlinkButton)sender;
@@ -43,14 +43,11 @@ protected override void Write(WinUIRenderer renderer, LinkInline link)
// Optionally restore later; not needed unless reused.
}
};
- // Apply link foreground to nested RichTextBlock content
- // (Handled in MyHyperlinkButton initialization via MarkdownConfig.Default for now)
renderer.Push(myHyperlinkButton);
}
else
{
- var hyperlink = new MyHyperlink(link, renderer.Config.BaseUrl);
- hyperlink.TextElement.Foreground = renderer.Config.Themes.LinkForeground;
+ var hyperlink = new MyHyperlink(link, renderer.Config.BaseUrl, renderer.Config.Themes);
hyperlink.ClickEvent += (sender, e) =>
{
var uri = sender.NavigateUri;
diff --git a/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs b/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs
index 81de7c73b..13d03c6bf 100644
--- a/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs
+++ b/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs
@@ -9,6 +9,7 @@ namespace CommunityToolkit.WinUI.Controls.TextElements;
internal class MyAutolinkInline : IAddChild
{
private AutolinkInline _autoLinkInline;
+ private MarkdownThemes _themes;
public TextElement TextElement { get; private set; }
@@ -24,12 +25,14 @@ public event TypedEventHandler? ClickEvent
}
}
- public MyAutolinkInline(AutolinkInline autoLinkInline)
+ public MyAutolinkInline(AutolinkInline autoLinkInline, MarkdownThemes themes)
{
_autoLinkInline = autoLinkInline;
+ _themes = themes;
TextElement = new Hyperlink()
{
NavigateUri = new Uri(autoLinkInline.Url),
+ Foreground = _themes.LinkForeground
};
}
diff --git a/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs b/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs
index fdbb9ad6d..dcabeb8ac 100644
--- a/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs
+++ b/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs
@@ -13,6 +13,7 @@ internal class MyHyperlink : IAddChild
private LinkInline? _linkInline;
private HtmlNode? _htmlNode;
private string? _baseUrl;
+ private MarkdownThemes _themes;
public event TypedEventHandler ClickEvent
{
@@ -33,27 +34,29 @@ public TextElement TextElement
get => _hyperlink;
}
- public MyHyperlink(LinkInline linkInline, string? baseUrl)
+ public MyHyperlink(LinkInline linkInline, string? baseUrl, MarkdownThemes themes)
{
_baseUrl = baseUrl;
+ _themes = themes;
var url = linkInline.GetDynamicUrl != null ? linkInline.GetDynamicUrl() ?? linkInline.Url : linkInline.Url;
_linkInline = linkInline;
_hyperlink = new Hyperlink()
{
NavigateUri = Extensions.GetUri(url, baseUrl),
- Foreground = MarkdownConfig.Default.Themes.LinkForeground
+ Foreground = _themes.LinkForeground
};
}
- public MyHyperlink(HtmlNode htmlNode, string? baseUrl)
+ public MyHyperlink(HtmlNode htmlNode, string? baseUrl, MarkdownThemes themes)
{
_baseUrl = baseUrl;
+ _themes = themes;
var url = htmlNode.GetAttribute("href", "#");
_htmlNode = htmlNode;
_hyperlink = new Hyperlink()
{
NavigateUri = Extensions.GetUri(url, baseUrl),
- Foreground = MarkdownConfig.Default.Themes.LinkForeground
+ Foreground = _themes.LinkForeground
};
}
diff --git a/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs b/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs
index 594d6fd66..ceb63a4bd 100644
--- a/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs
+++ b/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs
@@ -15,6 +15,7 @@ internal class MyHyperlinkButton : IAddChild
private string? _baseUrl;
private LinkInline? _linkInline;
private HtmlNode? _htmlNode;
+ private MarkdownThemes _themes;
public event RoutedEventHandler? ClickEvent
{
@@ -35,21 +36,22 @@ public TextElement TextElement
get => _inlineUIContainer;
}
- public MyHyperlinkButton(LinkInline linkInline, string? baseUrl)
- : this(linkInline.GetDynamicUrl != null ? linkInline.GetDynamicUrl() ?? linkInline.Url : linkInline.Url, baseUrl, null, linkInline)
+ public MyHyperlinkButton(LinkInline linkInline, string? baseUrl, MarkdownThemes themes)
+ : this(linkInline.GetDynamicUrl != null ? linkInline.GetDynamicUrl() ?? linkInline.Url : linkInline.Url, baseUrl, null, linkInline, themes)
{
}
- public MyHyperlinkButton(HtmlNode htmlNode, string? baseUrl)
- : this(htmlNode.GetAttribute("href", "#"), baseUrl, htmlNode, null)
+ public MyHyperlinkButton(HtmlNode htmlNode, string? baseUrl, MarkdownThemes themes)
+ : this(htmlNode.GetAttribute("href", "#"), baseUrl, htmlNode, null, themes)
{
}
- private MyHyperlinkButton(string? url, string? baseUrl, HtmlNode? htmlNode, LinkInline? linkInline)
+ private MyHyperlinkButton(string? url, string? baseUrl, HtmlNode? htmlNode, LinkInline? linkInline, MarkdownThemes themes)
{
_baseUrl = baseUrl;
_htmlNode = htmlNode;
_linkInline = linkInline;
+ _themes = themes;
_hyperLinkButton = new HyperlinkButton
{
NavigateUri = Extensions.GetUri(url, baseUrl),
@@ -65,8 +67,8 @@ private MyHyperlinkButton(string? url, string? baseUrl, HtmlNode? htmlNode, Link
_flowDoc = new MyFlowDocument(_linkInline!);
}
_inlineUIContainer.Child = _hyperLinkButton;
- _flowDoc.RichTextBlock.Foreground = MarkdownConfig.Default.Themes.LinkForeground;
- _hyperLinkButton.Content = _flowDoc.RichTextBlock;
+ _flowDoc.RichTextBlock.Foreground = _themes.LinkForeground;
+ _hyperLinkButton.Content = _flowDoc.RichTextBlock;
}
public void AddChild(IAddChild child)
diff --git a/components/MarkdownTextBlock/src/TextElements/MyImage.cs b/components/MarkdownTextBlock/src/TextElements/MyImage.cs
index 64b94fd84..feb039f1d 100644
--- a/components/MarkdownTextBlock/src/TextElements/MyImage.cs
+++ b/components/MarkdownTextBlock/src/TextElements/MyImage.cs
@@ -18,6 +18,7 @@ internal class MyImage : IAddChild
private HtmlNode? _htmlNode;
private IImageProvider? _imageProvider;
private ISVGRenderer _svgRenderer;
+ private MarkdownThemes _themes;
private double _precedentWidth;
private double _precedentHeight;
private bool _loaded;
@@ -33,6 +34,7 @@ public MyImage(LinkInline linkInline, Uri uri, MarkdownConfig config)
_uri = uri;
_imageProvider = config.ImageProvider;
_svgRenderer = config.SVGRenderer == null ? new DefaultSVGRenderer() : config.SVGRenderer;
+ _themes = config.Themes;
Init();
var size = Extensions.GetMarkdownImageSize(linkInline);
if (size.Width != 0)
@@ -55,6 +57,7 @@ public MyImage(HtmlNode htmlNode, MarkdownConfig? config)
_htmlNode = htmlNode;
_imageProvider = config?.ImageProvider;
_svgRenderer = config?.SVGRenderer == null ? new DefaultSVGRenderer() : config.SVGRenderer;
+ _themes = config?.Themes ?? MarkdownThemes.Default;
Init();
int.TryParse(
htmlNode.GetAttribute("width", "0"),
@@ -142,26 +145,46 @@ private async void LoadImage(object sender, RoutedEventArgs e)
_loaded = true;
}
- if (_precedentWidth != 0)
- {
- _image.Width = _precedentWidth;
- }
- if (_precedentHeight != 0)
- {
- _image.Height = _precedentHeight;
- }
+ // Determine the actual image dimensions
+ double actualWidth = _precedentWidth != 0 ? _precedentWidth : _image.Width;
+ double actualHeight = _precedentHeight != 0 ? _precedentHeight : _image.Height;
- // Apply theme constraints if provided
- var themes = MarkdownConfig.Default.Themes;
- if (themes.ImageMaxWidth > 0)
- {
- _image.MaxWidth = themes.ImageMaxWidth;
- }
- if (themes.ImageMaxHeight > 0)
+ // Apply max constraints and calculate the final size
+ // When using Uniform stretch with max constraints, we need to calculate
+ // the actual rendered size to avoid gaps
+ double finalWidth = actualWidth;
+ double finalHeight = actualHeight;
+
+ bool hasMaxWidth = _themes.ImageMaxWidth > 0;
+ bool hasMaxHeight = _themes.ImageMaxHeight > 0;
+
+ if (hasMaxWidth || hasMaxHeight)
{
- _image.MaxHeight = themes.ImageMaxHeight;
+ double scaleX = hasMaxWidth && actualWidth > _themes.ImageMaxWidth
+ ? _themes.ImageMaxWidth / actualWidth
+ : 1.0;
+ double scaleY = hasMaxHeight && actualHeight > _themes.ImageMaxHeight
+ ? _themes.ImageMaxHeight / actualHeight
+ : 1.0;
+
+ // For Uniform stretch, use the smaller scale to maintain aspect ratio
+ if (_themes.ImageStretch == Stretch.Uniform || _themes.ImageStretch == Stretch.UniformToFill)
+ {
+ double uniformScale = Math.Min(scaleX, scaleY);
+ finalWidth = actualWidth * uniformScale;
+ finalHeight = actualHeight * uniformScale;
+ }
+ else
+ {
+ // For other stretch modes, apply constraints independently
+ finalWidth = actualWidth * scaleX;
+ finalHeight = actualHeight * scaleY;
+ }
}
- _image.Stretch = themes.ImageStretch;
+
+ _image.Width = finalWidth;
+ _image.Height = finalHeight;
+ _image.Stretch = _themes.ImageStretch;
}
catch (Exception) { }
}
diff --git a/components/MarkdownTextBlock/src/TextElements/MyTableCell.cs b/components/MarkdownTextBlock/src/TextElements/MyTableCell.cs
index 1374b7afd..46c4f71cb 100644
--- a/components/MarkdownTextBlock/src/TextElements/MyTableCell.cs
+++ b/components/MarkdownTextBlock/src/TextElements/MyTableCell.cs
@@ -46,7 +46,7 @@ public int RowIndex
get => _rowIndex;
}
- public MyTableCell(TableCell tableCell, TextAlignment textAlignment, bool isHeader, int columnIndex, int rowIndex)
+ public MyTableCell(TableCell tableCell, TextAlignment textAlignment, bool isHeader, int columnIndex, int rowIndex, MarkdownThemes themes)
{
_isHeader = isHeader;
_tableCell = tableCell;
@@ -66,8 +66,8 @@ public MyTableCell(TableCell tableCell, TextAlignment textAlignment, bool isHead
_ => HorizontalAlignment.Left,
};
- // Use themed table cell padding if available
- _container.Padding = MarkdownConfig.Default.Themes.TableCellPadding;
+ // Use themed table cell padding
+ _container.Padding = themes.TableCellPadding;
if (_isHeader)
{
_flowDocument.RichTextBlock.FontWeight = FontWeights.Bold;