Search code examples
wpfxamltextboxmaterial-designcontroltemplate

Issues with XAML MaterialDesign TextBox style: background when enabled and helpertext


I'm using Material Design library in XAML. I need to re-style some components because I'm using a particular textbox in which I have a clickable icon.

<StackPanel Orientation="Horizontal" Width="328"  Grid.Column="0" Background="#3B3A3A">
   <TextBox Style="{StaticResource Style}" materialDesign:HintAssist.Hint="Text" Width="300" 
            TextWrapping="Wrap" materialDesign:HintAssist.HelperText="Text1"/>
   <Button Opacity="1" Padding="2,0,0,0"
           Height="53.2"
           Background="Transparent" 
           BorderBrush="Transparent"
           Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}"
           CommandTarget="{Binding ElementName=DialogSelection}">
      <materialDesign:PackIcon Kind="ArrowExpand"/>
   </Button>

First of all I need to remove the background when the textbox isFocused, so in the style I did something like this:

<Style x:Key="Style" TargetType="TextBox" BasedOn="{StaticResource MaterialDesignFilledTextFieldTextBox}">
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type TextBox}">
            <Border x:Name="border" 
                    BorderBrush="{TemplateBinding BorderBrush}" 
                    BorderThickness="{TemplateBinding BorderThickness}" 
                    Background="{TemplateBinding Background}" 
                    Width="328"
                    materialDesign:BottomDashedLineAdorner.Thickness="{TemplateBinding Margin}">
               <TextBox x:Name="text" TextWrapping="WrapWithOverflow" FontSize="16" FontWeight="Regular" Foreground="White"/>
            </Border>
            <ControlTemplate.Triggers>
               <Trigger Property="IsEnabled" Value="True">
                  <Setter Property="BorderBrush" TargetName="border"  Value="#656565"/>
                  <Setter Property="Background" Value="#3b3a3a"/>
               </Trigger>
               <Trigger Property="IsFocused" Value="True">
                  <Setter Property="BorderBrush" TargetName="border" Value="#00B5CE"/>
                  <Setter Property="Background" Value="#656565"/>
                  <Setter Property="BorderThickness" Value="2"/>
               </Trigger>
            </ControlTemplate.Triggers>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

The issue is that using this code for the style (with the control template) I don't have available the helper text. How can I combine the two things? (I mean my settings for the background when the textbox isFocused and a HelperText available?)

NB: If I don't modify the template and just setting the background it happens that the background when the textbox isFocused isn't as I want but the HelperText is visible


Solution

  • It does not work, because you overwrite the control template of the TextBox and omit most of it that is needed for it to work correctly. A control template defines the visual apprearance of a control, as well as the states and transitions between them. You cannot base a contol template on another as you can with styles. Creating a custom control template means:

    • Creating it from scratch with all the required states and parts or
    • Copying the base/default style and adapting it.

    For standard WPF controls, you can find required parts and states in the documentation, e.g. for TextBox here. Omitting any of the required components will lead to unexpected behavior or broken visuals states. In case of Material Design, there are even more things necessary to make the controls work correctly, but they are not documented like on MSDN, so you have to create a copy of the default style and adapt it.

    You can find the default styles for TextBox here on Github. In newer versions, the styles are renamed to MaterialDesignFilledTextBox because of this issue. The derived style hierarchy is as follows:

    • MaterialDesignTextBoxBase
      • MaterialDesignFloatingHintTextBox
        • MaterialDesignFloatingHintTextBox
          • MaterialDesignFilledTextFieldTextBox

    The control template is defined in MaterialDesignTextBoxBase, which is the base style for all other styles. What you have to do now is to copy the MaterialDesignTextBoxBase style, give it a name and adapt the states as in your provided code. You can merge the setters of the three derived styles above into your custom style. Then you will have a custom style that incorporates all necessary states and parts that will work as you expect it.