uwpisenabledricheditbox

RichEditBox looses color formatting when disable then enable


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.


Solution

  • 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>