Search code examples
wpfxamlsettertextblockdatatrigger

Overwrite Text property in a Setter (or a better approach)


I'm struggling with replicating a switch in WPF XAML, where I want to go through some bindings hierarchically and set my Text property to the last true value I get.

<TextBlock Grid.Row="4" Grid.Column="2">
  <Run Text="No hits"/>
  <TextBlock.Style>
    <Style>
      <Style.Triggers>
        <DataTrigger Binding="{Binding FirstValue}" Value="True">
          <Setter Property="TextBlock.Text" Value="FirstValueHit"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding SecondValue}" Value="True">
          <Setter Property="TextBlock.Text" Value="SecondValueHit"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding ThirdValue}" Value="True">
          <Setter Property="TextBlock.Text" Value="ThirdValueHit"/>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </TextBlock.Style>
</TextBlock>

My problem here is that if all 3 hits, I will end up with the string "No hits FirstValueHit SecondValueHit ThirdValueHit".

Is there an easy way to make this overwrite the previous TextBlock.Text property, as it would if I were to change the Foreground color for instance.

If I had Foreground="Red" and then on a setter put it to Yellow, I would get a yellow foreground, and not an orange one (red plus yellow).

Or is there a better way to make this behave like a switch and just flip the order and break when it gets a hit?


Solution

  • TextBlock.Text is a bit special since it is just a convenient way to deal with the TextBlock.Inlines. This is why you see the artifact of the combined No hits FirstValueHit SecondValueHit ThirdValueHit. However, as long as you don't want to deal with multiple Run elements, it can be handled the same way as any other property.

    Basically, set the property in the style instead of directly in the control. Otherwise the local value will override the style trigger result. Also, set the Style.TargetType in order to access the target types properties directly.

    <TextBlock Grid.Row="4" Grid.Column="2">
      <TextBlock.Style>
        <Style TargetType="TextBlock">
          <Setter Property="Text" Value="No hits"/>
          <Style.Triggers>
            <DataTrigger Binding="{Binding FirstValue}" Value="True">
              <Setter Property="Text" Value="FirstValueHit"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding SecondValue}" Value="True">
              <Setter Property="Text" Value="SecondValueHit"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding ThirdValue}" Value="True">
              <Setter Property="Text" Value="ThirdValueHit"/>
            </DataTrigger>
          </Style.Triggers>
        </Style>
      </TextBlock.Style>
    </TextBlock>