diff --git a/README.md b/README.md
index 824a429..d4b63ae 100644
--- a/README.md
+++ b/README.md
@@ -124,6 +124,7 @@ If you encounter any issues or have feedback, please report them [here](https://
## 🔥 DevWinUI 🔥
### ⚡ What’s Inside? ⚡
+ - ✨ RichTextFormatter
- ✨ Converter
- ✨ Extensions
- ✨ Helpers
@@ -250,6 +251,9 @@ Install-Package DevWinUI.ContextMenu
### ProgressButton
![DevWinUI](https://raw.githubusercontent.com/ghost1372/DevWinUI-Resources/refs/heads/main/DevWinUI-Docs/ProgressButton.gif)
+### RichTextFormatter Helper
+![DevWinUI](https://raw.githubusercontent.com/ghost1372/DevWinUI-Resources/refs/heads/main/DevWinUI-Docs/RichTextFormatter.png)
+
### TextBox
![DevWinUI](https://raw.githubusercontent.com/ghost1372/DevWinUI-Resources/refs/heads/main/DevWinUI-Docs/TextBox.png)
diff --git a/dev/DevWinUI.Gallery/Assets/NavViewMenu/AppData.json b/dev/DevWinUI.Gallery/Assets/NavViewMenu/AppData.json
index 6d7dfde..e74a752 100644
--- a/dev/DevWinUI.Gallery/Assets/NavViewMenu/AppData.json
+++ b/dev/DevWinUI.Gallery/Assets/NavViewMenu/AppData.json
@@ -94,6 +94,13 @@
"ImagePath": "ms-appx:///Assets/Fluent/RatingControl.png",
"IsSpecialSection": false,
"Items": [
+ {
+ "UniqueId": "DevWinUIGallery.Views.RichTextFormatterPage",
+ "Title": "RichTextFormatter",
+ "Subtitle": "Formats a TextBlock/RichTextBlock using HTML-like formatting codes",
+ "IsNew": true,
+ "ImagePath": "ms-appx:///Assets/Fluent/RichEditBox.png"
+ },
{
"UniqueId": "DevWinUIGallery.Views.ProgressButtonPage",
"Title": "ProgressButton",
diff --git a/dev/DevWinUI.Gallery/T4Templates/NavigationPageMappings.cs b/dev/DevWinUI.Gallery/T4Templates/NavigationPageMappings.cs
index fa1d9c2..6079330 100644
--- a/dev/DevWinUI.Gallery/T4Templates/NavigationPageMappings.cs
+++ b/dev/DevWinUI.Gallery/T4Templates/NavigationPageMappings.cs
@@ -25,6 +25,7 @@ public partial class NavigationPageMappings
{"DevWinUIGallery.Views.WaveCirclePage", typeof(DevWinUIGallery.Views.WaveCirclePage)},
{"DevWinUIGallery.Views.BubblePage", typeof(DevWinUIGallery.Views.BubblePage)},
{"DevWinUIGallery.Views.GooeyPage", typeof(DevWinUIGallery.Views.GooeyPage)},
+ {"DevWinUIGallery.Views.RichTextFormatterPage", typeof(DevWinUIGallery.Views.RichTextFormatterPage)},
{"DevWinUIGallery.Views.ProgressButtonPage", typeof(DevWinUIGallery.Views.ProgressButtonPage)},
{"DevWinUIGallery.Views.TextBoxPage", typeof(DevWinUIGallery.Views.TextBoxPage)},
{"DevWinUIGallery.Views.TileControlPage", typeof(DevWinUIGallery.Views.TileControlPage)},
diff --git a/dev/DevWinUI.Gallery/Views/Pages/Features/RichTextFormatterPage.xaml b/dev/DevWinUI.Gallery/Views/Pages/Features/RichTextFormatterPage.xaml
new file mode 100644
index 0000000..3bb29c9
--- /dev/null
+++ b/dev/DevWinUI.Gallery/Views/Pages/Features/RichTextFormatterPage.xaml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+ RichTextFormatterHelper.FormatTextBlock(text, textBlock);
+
+
+
+
+
+
+
+
+
+
+
+ RichTextFormatterHelper.FormatRichTextBlock(text, richTextBlock);
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/DevWinUI.Gallery/Views/Pages/Features/RichTextFormatterPage.xaml.cs b/dev/DevWinUI.Gallery/Views/Pages/Features/RichTextFormatterPage.xaml.cs
new file mode 100644
index 0000000..0e789ae
--- /dev/null
+++ b/dev/DevWinUI.Gallery/Views/Pages/Features/RichTextFormatterPage.xaml.cs
@@ -0,0 +1,26 @@
+namespace DevWinUIGallery.Views;
+
+public sealed partial class RichTextFormatterPage : Page
+{
+ public RichTextFormatterPage()
+ {
+ this.InitializeComponent();
+ Loaded += RichTextFormatterPage_Loaded;
+ }
+
+ private void RichTextFormatterPage_Loaded(object sender, RoutedEventArgs e)
+ {
+ Txt_TextChanged(null, null);
+ Txt2_TextChanged(null, null);
+ }
+
+ private void Txt_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ RichTextFormatterHelper.FormatTextBlock(Txt.Text, txtBlock);
+ }
+
+ private void Txt2_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ RichTextFormatterHelper.FormatRichTextBlock(Txt2.Text, txtRichBlock);
+ }
+}
diff --git a/dev/DevWinUI/Extensions/Extensions.cs b/dev/DevWinUI/Extensions/Extensions.cs
index 2fc5fbb..22ce9d3 100644
--- a/dev/DevWinUI/Extensions/Extensions.cs
+++ b/dev/DevWinUI/Extensions/Extensions.cs
@@ -5,4 +5,12 @@ public static SolidColorBrush GetSolidColorBrush(this string hex)
{
return ColorHelper.GetSolidColorBrush(hex);
}
+ public static void FormatRichTextBlock(this string textWithHTMLFormatting, RichTextBlock richTextBlock)
+ {
+ RichTextFormatterHelper.FormatRichTextBlock(textWithHTMLFormatting, richTextBlock);
+ }
+ public static void FormatTextBlock(this string textWithHTMLFormatting, TextBlock textBlock)
+ {
+ RichTextFormatterHelper.FormatTextBlock(textWithHTMLFormatting, textBlock);
+ }
}
diff --git a/dev/DevWinUI/Helpers/RichTextFormatterHelper.cs b/dev/DevWinUI/Helpers/RichTextFormatterHelper.cs
new file mode 100644
index 0000000..691e660
--- /dev/null
+++ b/dev/DevWinUI/Helpers/RichTextFormatterHelper.cs
@@ -0,0 +1,194 @@
+using Microsoft.UI.Text;
+using Microsoft.UI.Xaml.Documents;
+using System.Text.RegularExpressions;
+using Windows.UI.Text;
+
+namespace DevWinUI;
+public partial class RichTextFormatterHelper
+{
+ ///
+ /// Formats a RichTextBlock using HTML-like formatting codes, supported tags: br, b, u, i, font size='size', and pipe characters which are treated like br. Also supports font color='hexcolor' and font bgcolor='hexcolor'.
+ /// To combine both foreground and background colors, use font colors='hexforecolor,hexbackcolor' (colors separated by a comma).
+ ///
+ ///
+ ///
+ public static void FormatRichTextBlock(string textWithHTMLFormatting, RichTextBlock richTextBlock)
+ {
+ // Clearing existing content
+ richTextBlock.Blocks.Clear();
+
+ if (textWithHTMLFormatting == null)
+ return;
+
+ // Replacing
with a unique placeholder that is unlikely to appear in the text
+ string placeholder = "\uE000"; // Using a Private Use Area Unicode character as a placeholder
+ string processedText = Regex.Replace(textWithHTMLFormatting, "
", placeholder, RegexOptions.IgnoreCase); // replace
with linebreak placeholder
+ processedText = processedText.Replace("|", placeholder); // replace | with linebreak placeholder
+
+ // Pattern to match various tags including foreground and background colors
+ string pattern = $@"(.*?)|(.*?)|(.*?)|(.*?)|(.*?)|(.*?)|(.*?)|{Regex.Escape(placeholder)}";
+
+ var paragraph = new Paragraph();
+ ProcessFormattingText(processedText, pattern, paragraph.Inlines);
+ richTextBlock.Blocks.Add(paragraph);
+ }
+
+ ///
+ /// Formats a TextBlock using HTML-like formatting codes, supported tags: br, b, u, i, font size='size', and pipe characters which are treated like br. Also supports font color='hexcolor', but TextBlocks do not support the background colors in this fashion, so use the RichTextBlock overload instead if backcolors are needed.
+ ///
+ ///
+ ///
+ public static void FormatTextBlock(string textWithHTMLFormatting, TextBlock textBlock)
+ {
+ // Clearing existing content
+ textBlock.Inlines.Clear();
+
+ if (textWithHTMLFormatting == null)
+ return;
+
+ // Replacing
with a unique placeholder that is unlikely to appear in the text
+ string placeholder = "\uE000"; // Using a Private Use Area Unicode character as a placeholder
+ string processedText = Regex.Replace(textWithHTMLFormatting, "
", placeholder, RegexOptions.IgnoreCase); // replace
with linebreak placeholder
+ processedText = processedText.Replace("|", placeholder); // replace | with linebreak placeholder
+
+ // Pattern to match various tags including foreground colors
+ string pattern = $@"(.*?)|(.*?)|(.*?)|(.*?)|(.*?)|{Regex.Escape(placeholder)}";
+
+ ProcessFormattingText(processedText, pattern, textBlock.Inlines);
+ }
+
+ ///
+ /// Used by FormatTextBlock() to process the text and apply formatting to apply to the RichTextBlock or TextBlock
+ ///
+ ///
+ ///
+ ///
+ private static void ProcessFormattingText(string text, string pattern, InlineCollection inlines)
+ {
+ int lastIndex = 0;
+
+ foreach (Match match in Regex.Matches(text, pattern))
+ {
+ // Text before bold, underlined, italic, sized or line break
+ if (match.Index > lastIndex)
+ {
+ var runBeforeTag = new Run
+ {
+ Text = text.Substring(lastIndex, match.Index - lastIndex)
+ };
+ inlines.Add(runBeforeTag);
+ }
+
+ if (match.Value == "\uE000") // Handle line break
+ {
+ inlines.Add(new LineBreak());
+ }
+ else
+ {
+ if (match.Groups[1].Success) // Handle bold text
+ {
+ var span = new Span
+ {
+ FontWeight = FontWeights.Bold
+ };
+ ProcessFormattingText(match.Groups[1].Value, pattern, span.Inlines);
+ inlines.Add(span);
+ }
+ else if (match.Groups[2].Success) // Handle underlined text
+ {
+ var underline = new Underline();
+ ProcessFormattingText(match.Groups[2].Value, pattern, underline.Inlines);
+ inlines.Add(underline);
+ }
+ else if (match.Groups[3].Success) // Handle italic text
+ {
+ var span = new Span
+ {
+ FontStyle = FontStyle.Italic
+ };
+ ProcessFormattingText(match.Groups[3].Value, pattern, span.Inlines);
+ inlines.Add(span);
+ }
+ else if (match.Groups[4].Success && match.Groups[5].Success) // Handle sized text
+ {
+ var span = new Span
+ {
+ FontSize = double.Parse(match.Groups[4].Value)
+ };
+ ProcessFormattingText(match.Groups[5].Value, pattern, span.Inlines);
+ inlines.Add(span);
+ }
+ else if (match.Groups[6].Success && match.Groups[7].Success) // Handle foreground color text
+ {
+ var span = new Span
+ {
+ Foreground = new SolidColorBrush(ColorHelper.GetColorFromHex(match.Groups[6].Value))
+ };
+ ProcessFormattingText(match.Groups[7].Value, pattern, span.Inlines);
+ inlines.Add(span);
+ }
+ else if (match.Groups[8].Success && match.Groups[9].Success) // Handle background color text
+ {
+ var span = new Span();
+ var border = new Border
+ {
+ Background = new SolidColorBrush(ColorHelper.GetColorFromHex(match.Groups[8].Value)),
+ Child = new TextBlock
+ {
+ Text = match.Groups[9].Value,
+ TextWrapping = TextWrapping.Wrap
+ }
+ };
+
+ var inlineUIContainer = new InlineUIContainer
+ {
+ Child = border
+ };
+
+ inlines.Add(inlineUIContainer);
+ }
+ else if (match.Groups[10].Success && match.Groups[11].Success) // Handle combined foreground and background color text
+ {
+ var colors = match.Groups[10].Value.Split(',');
+ var foregroundColor = ColorHelper.GetColorFromHex(colors[0]);
+ var backgroundColor = ColorHelper.GetColorFromHex(colors[1]);
+
+ var span = new Span
+ {
+ Foreground = new SolidColorBrush(foregroundColor)
+ };
+
+ var border = new Border
+ {
+ Background = new SolidColorBrush(backgroundColor),
+ Child = new TextBlock
+ {
+ Text = match.Groups[11].Value,
+ TextWrapping = TextWrapping.Wrap,
+ Foreground = new SolidColorBrush(foregroundColor)
+ }
+ };
+
+ var inlineUIContainer = new InlineUIContainer
+ {
+ Child = border
+ };
+
+ inlines.Add(inlineUIContainer);
+ }
+ }
+
+ lastIndex = match.Index + match.Length;
+ }
+
+ // Text after the last tag, if any
+ if (lastIndex < text.Length)
+ {
+ var runAfterLastTag = new Run
+ {
+ Text = text.Substring(lastIndex)
+ };
+ inlines.Add(runAfterLastTag);
+ }
+ }
+}