UWP RichEditBox 在暗模式下保存并在亮模式下打开时的文本颜色问题 介绍1.更改 ITextDocument2. 更改 RTF

问题描述

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

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

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

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

image 1

image 2

  1. 单击屏幕上的其他位置以从 RicheditBox 中释放焦点,然后关闭应用。
  2. 再次运行应用程序,您会发现之前输入的文本已按预期出现,现在关闭应用程序。

image 3

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

image 4

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

image 5

注意

每次更改某些内容并尝试再次测试整个流程时,请确保更改 LoadedTextChanged 事件中的字符串,以确保保存全新的 RTF 值并稍后加载,加载和文本更改中的关键事件必须始终匹配,并且每次要从第 1 步开始时都应该更改。

image 6

代码

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 主题即可将应用程序从深色更改为浅色。只需将 RequestedThemePage 标头中的 MainPage.xaml 属性设置为 LightDark

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...