问题描述
基本上在我的应用程序中,我有一个 RichEditBox,它需要在 TextChanged 事件上保存其数据并从保存的设置 OnLoaded 加载文本事件,经过数周的实验,我能够在一个最小的应用程序中重现该问题供你们测试。
目标:最终无论我使用深色主题还是浅色主题将 RTF 文本保存在这个丰富的编辑框中,无论何时在任何主题中再次加载它都应该在深色中显示正确的文本颜色和轻主题。并且在运行应用程序期间,如果用户更改其设备的主题,则文本颜色也应按预期更改。我不确定如何在此处保存 rtf 文本,它可能会忽略文本颜色?
在此处重现错误:https://github.com/touseefbsb/RichEditBoxColorBug
注意
每次更改某些内容并尝试再次测试整个流程时,请确保更改键 Loaded 和 TextChanged 事件中的字符串,以确保保存全新的 RTF 值并稍后加载,加载和文本更改中的关键事件必须始终匹配,并且每次要从第 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>
背后的代码
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 设备版本:1903
项目目标和最小sdk版本:1903
解决方法
我在尝试将 RTF 从 RichEditBox
转换为 HTML 时遇到了类似的问题。
介绍
只要我们假设您不允许更改字体颜色,这并不难。如果您允许通过文档更改字体颜色,这两个建议的选项也可以使用,但这会带来很多工作和权衡(即,您是否在深色显示时反转浅色主题中选择的颜色?,某些颜色与黑色看起来更好)背景,其他白色等)
1.更改 ITextDocument
这个选项非常简单而且效果很好。在 RichEditBox
下方有一个 ITextDocument
,其中包含实际文本(通过 RichEditBox.Document
访问)。设置好本文档的文本后,您还可以设置字体颜色(甚至可以通过这种方式将文本的某些部分更改为字体颜色):
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
}
我已经对此进行了测试,这似乎也有效。
2. 更改 RTF
更底层的方法是在从 LocalSettings
加载原始 RTF 之后和设置 RichEditBox
的文本之前更改原始 RTF。如果您检查原始 RTF,您会看到如下内容:
{\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}
这里要注意的是第二行:{\colortbl ...}
,这部分定义了字体颜色。如果您现在只是将 255 更改为 0,则您将字体从白色更改为黑色。我已经编写了两个扩展方法,并且对您的代码进行了快速测试似乎可以正常工作:
扩展类
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);
}
附言我希望这些解决方案也适用于您的 MVCE 之外和您的主应用程序。如果没有回复,我会尽力帮助你。
P.P.S.您无需更改整个 PC 主题即可将应用程序从深色更改为浅色。只需将 RequestedTheme
的 Page
标头中的 MainPage.xaml
属性设置为 Light
或 Dark
。