【问题标题】:UWP RichEditBox text color issue when saved in dark mode and opened in light mode在深色模式下保存并在浅色模式下打开时 UWP RichEditBox 文本颜色问题
【发布时间】:2021-04-16 11:07:08
【问题描述】:

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

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

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

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

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

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

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

注意

每次您更改某些内容并尝试再次测试整个流程时,只需确保更改 key LoadedTextChanged 事件中的字符串,以确保保存全新的 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
        }
    }

MISC 信息

Windows 10 设备版本:1903

项目目标和最小 sdk 版本:1903

【问题讨论】:

    标签: c# text uwp themes richeditbox


    【解决方案1】:

    我在尝试将 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,您会看到如下内容:

    {\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 之外和您的主应用程序。如果没有回复,我会尽力帮助您。
    附言您无需更改整个 PC 主题即可将应用程序从暗变为亮。相反,只需将MainPage.xamlPage 标头中的RequestedTheme 属性设置为LightDark

    【讨论】:

    • 我尝试了第一个解决方案,现在它在浅色主题上看起来不错,但在深色主题上出现问题。即:richeditbox 文本在深色主题上是黑色的,但是一旦我专注于它并再次失去焦点,它就会变成白色。我在 github 中提供的同一应用程序中对此进行了测试。现在我将研究第二个解决方案
    • 似乎第二种解决方案产生了完全相同的错误,深色主题文本始终为黑色,直到它被聚焦(它)将其背景变为白色,文本保持黑色,然后当你失去焦点时它,然后文本按预期变为白色。
    • 我调试并发现“请求的主题始终是默认的”,因为它从设备主题获取主题,而应用程序本身没有特定的浅色或深色主题。所以我们可能需要检测 applicationTheme 而不是 Requested 主题
    • 好的,我使用“Frame frame = Window.Current.Content as Frame;”然后将“frame.ActualTheme”属性与 ElementTheme 而不是 Application RequestedTheme 匹配,并且效果很好。它适用于您的两种解决方案。请使用此信息更新您的答案,我会标记您的答案:)
    • 感谢所有反馈,我会更新我的答案。
    猜你喜欢
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    相关资源
    最近更新 更多