UWP RichEditBox 在深色模式下保存并在浅色模式下打开时的文本颜色问题

UWP RichEditBox text color issue when saved in dark mode and opened in light mode

基本上,在我的应用程序中,我有一个 RichEditBox,它需要将其数据保存在 TextChanged 事件中,并从保存的设置中加载文本OnLoaded 事件,经过数周的实验,我能够在一个最小的应用程序中重现该问题供大家测试。

Aim : 最终无论我使用深色或浅色主题将 RTF 文本保存在这个丰富的编辑框中,无论何时以任何主题再次加载它都应该显示正确深色和浅色主题中的文本颜色。在 运行ning 应用程序期间,如果用户更改其设备的主题,文本颜色也应按预期更改。我不确定如何在此处保存 rtf 文本,它可能会忽略文本颜色吗?

在此处重现错误https://github.com/touseefbsb/RichEditBoxColorBug

  1. 确保您的设备主题为“深色”。
  2. 运行 应用程序并在 RichEditBox 中添加一些文本(顶部的文本块和按钮只是为了确保应用程序不会在页面加载时自动聚焦到 richeditbox)。

  1. 单击屏幕上的其他位置以从 richeditbox 上松开焦点,然后关闭应用程序。
  2. 运行 再次打开该应用,您会发现您之前输入的文本已经按预期出现了,现在请关闭该应用。

  1. 将您设备的主题设置为“Light”,然后再次 运行 应用程序,现在您会注意到 richeditbox 似乎是空的。

  1. 但实际上它不是空的,问题是文本颜色是白色的,就像richeditbox的颜色一样,而文本颜色在light theme中应该是黑色的。这可以通过使用光标选择文本并注意出现突出显示的文本来证明。

备注

每次您更改某些内容并尝试再次测试整个流程时,只需确保更改 key LoadedTextChanged 事件中的字符串,以确保保存并正在保存全新的 RTF 值稍后加载,loaded 和 textchanging 事件中的键必须始终匹配,并且每次你想从第 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 时遇到了类似的问题。

简介

只要我们假设您不允许更改字体颜色,这并不难。如果您允许通过文档更改字体颜色,那么这两个建议的选项也可以使用,但这会带来很多工作并且 trade-off(即,当您在黑暗中显示它们时,您是否反转在浅色主题中选择的颜色?,某些颜色看起来更好黑色背景,其他白色背景等)

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

一种更 low-level 的方法是在您从 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,您会将字体从白色更改为黑色。我已经编写了两个扩展方法,并且在您的代码中进行快速测试似乎有效:

扩展名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。我希望这些解决方案也适用于您的 MVCE 之外和您的主应用程序。如果没有post回复,我会尽力帮助你。
P.P.S。您无需更改整个 PC 主题即可将应用程序从深色更改为浅色。相反,只需将 MainPage.xaml 中的 Page header 中的 RequestedTheme 属性 设置为 LightDark.