Search code examples
wpfperformancetextboxfocustextblock

Xaml switch between TextBlock and TextBox


I've noticed that TextBoxes are very slow and create performance issues when the Text is changed dynamically by code (I need to change the Text continuosly to 10-15 TextBoxes at the same time), so, as a workaround, I've created a custom control with a TextBlock and a TextBox:

The TextBlock is used in almost all time.
The TextBox is used only when I need to edit the Text inside the control with keyboard.

My solution is to change the template and use the TextBox when the control is focused:

(Value is a string Dependency Property)

<Style TargetType="{x:Type local:CustomControl1}">

    <Setter Property="Value" Value="Val"/>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Value}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Style.Triggers>
        <Trigger Property="IsFocused" Value="True">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                        <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                            <TextBox HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
                                     Text="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>  

But when I click on the control nothing happens.
I think that the problem is that the "focus state" is passed to the internal TextBox, and the control loses the "focus state".

There is a better way to create a custom "TextBox" control like this, or a way to resolve this problem?


Solution

  • You don't need a custom control for this, that's just adding unnecessary overhead. What you're trying to create is still a TextBox, with all the usual behavior of a TextBox (focus etc). All you need to do is change the template to a TextBlock when it's not in focus:

    <Window.Resources>
    
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="False">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type TextBox}">
                                <TextBlock Text="{TemplateBinding Text}" />
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    
    </Window.Resources>
    
    <StackPanel>
        <TextBox Text="Hello World" />
        <TextBox Text="Goodbye World" />
    </StackPanel>
    

    enter image description here