2

I am using a RichEditBox in a UWP application, and I need to enable and disable it in the software to perform some tasks. The issue I am running into is that when I disable, then re-enable it, any color formatting gets lost. I have created a simple example here, to try out the issue. You can type some text, color it in red, then disable and re-enable. The color gets reverted to black.

XAML

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <Button Content="Disable" Click="OnDisable"/>
        <Button Content="Enable" Click="OnEnable"/>
        <Button Content="Red" Click="OnRed"/>
    </StackPanel>
    <RichEditBox Name="RichEditor" Width="500" Height="200"/>
</StackPanel>

C#

private void OnDisable(object sender, RoutedEventArgs e)
{
    RichEditor.IsEnabled = false;
}

private void OnEnable(object sender, RoutedEventArgs e)
{
    RichEditor.IsEnabled = true;
}

private void OnRed(object sender, RoutedEventArgs e)
{
     RichEditor.Document.Selection.CharacterFormat.ForegroundColor = Colors.Red;
}

This looks like a bug in the RichEditBox component, and I am wondering if anyone has a workaround to allow me to enable and disable the text without losing the color formatting. Below the example to reproduce the issue.

ClaudiaWey
  • 167
  • 9

2 Answers2

3

See the Control style and template part in the RichEditBox Class:

You can modify the default Style and ControlTemplate to give the control a unique appearance.The default style, template, and resources that define the look of the control are included in the generic.xaml file. For design purposes, generic.xaml is available in the (Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP<SDK version>\Generic folder from a Windows Software Development Kit (SDK) installation. Styles and resources from different versions of the SDK might have different values.

So you can find the default style for System.Windows.Controls.RichEditBox control, here is the default style target on version 1803:

<!-- Default style for System.Windows.Controls.RichEditBox -->
        <Style TargetType="RichEditBox">
            <Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}" />
            <Setter Property="MinHeight" Value="{ThemeResource TextControlThemeMinHeight}" />
            <Setter Property="Foreground" Value="{ThemeResource TextControlForeground}" />
            <Setter Property="Background" Value="{ThemeResource TextControlBackground}" />
            <Setter Property="ContentLinkForegroundColor" Value="{ThemeResource ContentLinkForegroundColor}" />
            <Setter Property="ContentLinkBackgroundColor" Value="{ThemeResource ContentLinkBackgroundColor}" />
            <Setter Property="SelectionHighlightColor" Value="{ThemeResource TextControlSelectionHighlightColor}" />
            <Setter Property="BorderBrush" Value="{ThemeResource TextControlBorderBrush}" />
            <Setter Property="BorderThickness" Value="{ThemeResource TextControlBorderThemeThickness}" />
            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
            <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
            <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" />
            <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
            <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
            <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
            <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
            <Setter Property="TextWrapping" Value="Wrap" />
            <Setter Property="Padding" Value="{ThemeResource TextControlThemePadding}" />
            <Setter Property="UseSystemFocusVisuals" Value="{ThemeResource IsApplicationFocusVisualKindReveal}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="RichEditBox">
                        <Grid>

                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">

                                    <VisualState x:Name="Disabled">

                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlHeaderForegroundDisabled}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundDisabled}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderBrushDisabled}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundDisabled}" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Normal" />

                                    <VisualState x:Name="PointerOver">

                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderBrushPointerOver}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundPointerOver}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundPointerOver}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundPointerOver}" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Focused">

                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundFocused}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundFocused}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderBrushFocused}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundFocused}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="RequestedTheme">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Light" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>

                            </VisualStateManager.VisualStateGroups>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>
                            <Border x:Name="BorderElement"
                            Grid.Row="1"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Grid.ColumnSpan="2"
                            Grid.RowSpan="1" />
                            <ContentPresenter x:Name="HeaderContentPresenter"
                            x:DeferLoadStrategy="Lazy"
                            Visibility="Collapsed"
                            Grid.Row="0"
                            Foreground="{ThemeResource TextControlHeaderForeground}"
                            Margin="0,0,0,8"
                            Grid.ColumnSpan="2"
                            Content="{TemplateBinding Header}"
                            ContentTemplate="{TemplateBinding HeaderTemplate}"
                            FontWeight="Normal" />
                            <ScrollViewer x:Name="ContentElement"
                            Grid.Row="1"
                            HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                            HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                            VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                            VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                            IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
                            IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
                            IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
                            Margin="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}"
                            IsTabStop="False"
                            ZoomMode="Disabled"
                            AutomationProperties.AccessibilityView="Raw" />
                            <TextBlock x:Name="PlaceholderTextContentPresenter"
                            Grid.Row="1"
                            Foreground="{ThemeResource TextControlPlaceholderForeground}"
                            Margin="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}"
                            Grid.ColumnSpan="2"
                            Text="{TemplateBinding PlaceholderText}"
                            TextAlignment="{TemplateBinding TextAlignment}"
                            IsHitTestVisible="False" />

                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

From above style, you can see the Disabled VisualState code:

<VisualState x:Name="Disabled">

    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlHeaderForegroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderBrushDisabled}" />
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>

In this Disabled VisualState, you can find that the ContentElement's Foreground will be ThemeResource TextControlForegroundDisabled when you disable the RichEditBox. Since the text's Foreground has been changed when you disable the RichEditBox, you lose the color format.

You can keep the color format by deleting the code of changing the ContentElement's Foreground as the following Disabled VisualState:

<VisualState x:Name="Disabled">

    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlHeaderForegroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderBrushDisabled}" />
        </ObjectAnimationUsingKeyFrames>
        <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>-->
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundDisabled}" />
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>
Breeze Liu - MSFT
  • 3,734
  • 1
  • 10
  • 13
  • That worked in my sample code. It doesn't yet work in my app where the color gets reverted to black when regaining focus. I guess I just need to figure out what extra is happening, but I am happy with your solution. Thanks so much!! – ClaudiaWey Oct 09 '18 at 22:30
  • I figure out what was the difference in my example. I am using the TextToolbar, and that causes the color to revert to black OnFocus. Is this a bug of the TextToolbar? Any suggestion on how to prevent it? – ClaudiaWey Oct 09 '18 at 23:52
  • Correction, I think this happens when I attach the TextToolbar to the RichEditBox. It reverts the text to black. Any suggestion on how to prevent it? – ClaudiaWey Oct 10 '18 at 00:01
  • @ClaudiaWey I tried to add a `TextToolbar` to the `RichEditBox`, but I could not find that it reverts the text to black. You can post a new thread with detailed code and the steps to help me see the issue. – Breeze Liu - MSFT Oct 10 '18 at 02:01
0
Color myColor = Colors.Black; // this will act as your toggle of color you change it according to logic of your app in this case I will show you how you can retain the color even when disabled. Whenever you change the color of your richEditBox to red or to any color, just assign that color to it as well. Here I have set it default color to black.

private void OnDisable(object sender, RoutedEventArgs e)
{
    RichEditor.IsEnabled = false;
}

private void OnEnable(object sender, RoutedEventArgs e)
{
    RichEditor.IsEnabled = true;
    //Now after enabling just set the myColor property to RichEditBox Foreground.
    RichEditor.Document.Selection.CharacterFormat.ForegroundColor = myColor;
}

private void OnRed(object sender, RoutedEventArgs e)
{
     RichEditor.Document.Selection.CharacterFormat.ForegroundColor = Colors.Red;
     myColor = Colors.Red; // whatever color you set to the RichEditBox, set it to myColor as well.
}
Muhammad Touseef
  • 4,357
  • 4
  • 31
  • 75
  • unfortunately, this doesn't work. The change doesn't take effect right away. I could make this change in RichEditor.IsEnabledChanged, but also this would not work, because the color was only applied to a region of the text. I can have black text with a word in blue and a word in red. This information is stored in the RTF format of the RichEditBox, but the color gets lost when disabling and re-enabling the control. My only workaround was to store the RTF text before losing the focus and re-set it after. Feels pretty hacky, but can't figure out a better way. Can you? – ClaudiaWey Oct 07 '18 at 01:55