Basically in my app I have a RichEditBox which is required to save its data on TextChanged event and load the text from saved settings OnLoaded event, after weeks of experimentation I was able to reproduce the issue in an minimal app for you guys to test.
Aim : Ultimately no matter I use dark or light theme to save the RTF text in this rich edit box, whenever it is loaded again in whatever theme it should show the correct text color in both dark and light themes. and during the running app if the user changes theme of their device, the text color should also change as expected. I am not sure how to save the rtf text here it ignores the text color maybe?
Reproduce the bug here : https://github.com/touseefbsb/RichEditBoxColorBug
Everytime you change something and try to test the whole flow again just make sure to change the key string in both Loaded and TextChanged events, to make sure entirely new RTF value is being saved and being loaded later, the key in loaded and textchanging events must always match and should be changed everytime you want to start from step 1.
Xaml
<StackPanel>
<TextBlock>abc</TextBlock>
<Button>abc</Button>
<RichEditBox
x:Name="REB"
Height="60"
AcceptsReturn="True"
BorderThickness="0"
Loaded="REB_Loaded"
PlaceholderText="placeholder."
TextChanged="REB_TextChanged"
TextWrapping="Wrap" />
</StackPanel>
Code Behind
private void REB_Loaded(object sender, RoutedEventArgs e)
{
var localSettings = ApplicationData.Current.LocalSettings;
var localValue = localSettings.Values["ts5"] as string; // Change the key value on every new test
var text = string.IsNullOrEmpty(localValue) ? string.Empty : localValue;
REB.Document.SetText(TextSetOptions.FormatRtf, text);
}
private void REB_TextChanged(object sender, RoutedEventArgs e)
{
var localSettings = ApplicationData.Current.LocalSettings;
REB.Document.GetText(TextGetOptions.FormatRtf, out var tmpNar);
if (!string.IsNullOrEmpty(tmpNar) && !string.IsNullOrWhiteSpace(tmpNar))
{
localSettings.Values["ts5"] = tmpNar; // Change the key value on every new test
}
}
Windows 10 device version : 1903
Project target and min sdk version : 1903
I had similar issues trying to convert RTF to HTML from a RichEditBox
.
As long as we assume you don't allow font color changes it is not that hard. Both suggested options would also work if you allow font color changes through the document, but this introduces a lot of work and trade-off (i.e. do you invert colors selected in light theme when displaying them in dark?, certain colors look better with black background, others with white, etc.)
ITextDocument
This option is quite simple and works quite well. Underneath the RichEditBox
there is an ITextDocument
which contains the actual text (accessed through RichEditBox.Document
). After you set the text of this document you can also set the font color (it is even possible to change to font color for certain parts of the text this way):
REB_Loaded
private void REB_Loaded(object sender, RoutedEventArgs e)
{
var localSettings = ApplicationData.Current.LocalSettings;
var localValue = localSettings.Values["ts4"] as string;
var text = string.IsNullOrEmpty(localValue) ? string.Empty : localValue;
REB.Document.SetText(TextSetOptions.FormatRtf, text);
// Select all text currently in the RichtEditBox
// and make it white or black depending on the currently requested theme
REB.Document.GetRange(0, text.Length).CharacterFormat.ForegroundColor =
Window.Current.Content is FrameworkElement fe
? fe.ActualTheme == ElementTheme.Dark
? Windows.UI.Colors.White
: Windows.UI.Colors.Black
: Windows.UI.Colors.Black; // Assume light theme if actual theme cannot be determined
}
I have tested this and this seems to work as well.
A more low-level method would be to just change the raw RTF just after you load it from the LocalSettings
and just before you set the text of the RichEditBox
. If you inspect the raw RTF you would see something like this:
{\rtf1\fbidis\ansi\ansicpg1252\deff0\nouicompat\deflang2057{\fonttbl{\f0\fnil\fcharset0 Segoe UI;}{\f1\fnil Segoe UI;}}
{\colortbl ;\red255\green255\blue255;}
{\*\generator Riched20 10.0.19041}\viewkind4\uc1
\pard\tx720\cf1\f0\fs21\lang1033 test text\f1\par}
The thing to note here is the second line: {\colortbl ...}
, this part defines the font color. If you now just change the 255's to 0's you change the font from white to black. I have written two extensions methods and a quick test in your code seems to work:
Extension class
public static class Extensions
{
public static string ConvertWhiteTextToBlack(this string s)
=> s.Replace("\\red255\\green255\\blue255", "\\red0\\green0\\blue0");
public static string ConvertBlackTextToWhite(this string s)
=> s.Replace("\\red0\\green0\\blue0", "\\red255\\green255\\blue255");
}
REB_Loaded
private void REB_Loaded(object sender, RoutedEventArgs e)
{
var localSettings = ApplicationData.Current.LocalSettings;
var localValue = localSettings.Values["ts4"] as string;
var text = string.IsNullOrEmpty(localValue) ? string.Empty : localValue;
System.Diagnostics.Debug.WriteLine("[REB_Loaded (start)]" + text);
// Make black text white if dark theme is requested
text = Window.Current.Content is FrameworkElement fe
? fe.ActualTheme == ElementTheme.Light
? text.ConvertWhiteTextToBlack()
: text.ConvertBlackTextToWhite()
: text.ConvertWhiteTextToBlack(); // Assume light theme if actual theme cannot be determined
System.Diagnostics.Debug.WriteLine("[REB_Loaded (end)]" + text);
REB.Document.SetText(TextSetOptions.FormatRtf, text);
}
P.S. I hope these solutions are also applicable outside your MVCE and in your main app. If not post a reply, and I'll try to help you out.
P.P.S. You don't need to change your whole PC theme to change the app from dark to light. Instead just set the RequestedTheme
property in the Page
header in MainPage.xaml
to either Light
or Dark
.