WPF XAML Apply Opacity to Brush Only

130 Views Asked by At

I have read that for better performance, you should apply opacity to the foreground/background brush rather than the entire element. That is what I am trying to do, but I cannot figure it out.

Here is my XAML that works, but is setting the entire TextBlock element opacity:

<DataGrid>

    <DataGrid.Resources>
        <local:OpacityConverter x:Key="OpacityConverterKey" />
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn Width="1*" Binding="{Binding Number}">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="TextBlock">
                    <Setter Property="Opacity" Value="{Binding Number, Converter={StaticResource OpacityConverterKey}}" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Status}" Value="0">
                            <Setter Property="Foreground" Value="Lime" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Status}" Value="1">
                            <Setter Property="Foreground" Value="Red" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>

</DataGrid>

Here was my attempt to bind the opacity for just the foreground brush of TextBlock:

<DataGrid>

    <DataGrid.Resources>
        <local:OpacityConverter x:Key="OpacityConverterKey" />
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn Width="1*" Binding="{Binding Number}">

            <TextBlock.Foreground>
                <SolidColorBrush Color="Blue" Opacity="{Binding Distance, Converter={StaticResource OpacityConverterKey}}" />
            </TextBlock.Foreground>

            <DataGridTextColumn.ElementStyle>
                <Style TargetType="TextBlock">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Status}" Value="0">
                            <Setter Property="Foreground" Value="Lime" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Status}" Value="1">
                            <Setter Property="Foreground" Value="Red" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>

</DataGrid>

The converter does not work in this situation. Visual Studio underlines it and says "No DataContext found for binding." It doesn't have issue with the first example though.

How can I go about just setting the brush opacity?

Thanks for your time.

1

There are 1 best solutions below

7
BionicCode On

Your given example does not work because the Brush is assigned to a property (Foreground). Therefore it is not part of the visual tree (it's a simple property value). Either follow the suggestion of Clemens (return a configured Brush instead of an Opacity value) or animate the Foreground property using a trigger or define the Brush as a Resource using a Style.

When defining the Brush as a resource it will be able to inherit the DataContext of the styled element.

The following example will give you both performance optimizations:
a) modify Brush.Opacity instead of UIElement.Opacity
b) and use a shared resource instead of an inlined object (inlined objects are copied for each element instance).

<Window>
  <Window.Resources>
    <local:OpacityConverter x:Key="OpacityConverter" />

    <Style TargetType="TextBlock">
      <Style.Resources>

        <!-- Resource will inherit the DataContext of TextBlock -->
        <SolidColorBrush x:Key="ForegroundBrush" Color="Red"
                         Opacity="{Binding Distance, Converter={StaticResource OpacityConverter}}" />
      </Style.Resources>

      <Setter Property="Foreground"
              Value="{StaticResource ForegroundBrush}" />
    </Style>
  </Window.Resources>
</Window>

Example that shows how to change the foreground brush's Opacity and Foreground of all cells in a DataGrid:

<DataGrid>
  <DataGrid.CellStyle>
    <Style TargetType="DataGridCell">
      <Style.Resources>
        <local:OpacityConverter x:Key="OpacityConverter" />
        <SolidColorBrush x:Key="ForegroundBrush"
                         Color="Blue"
                         Opacity="{Binding Distance, Converter={StaticResource OpacityConverterKey}}" />
      </Style.Resources>

      <Setter Property="Foreground"
              Value="{StaticResource ForegroundBrush}" />

      <Style.Triggers>
        <DataTrigger Binding="{Binding Status}"
                     Value="0">
          <Setter Property="Foreground"
                  Value="Lime" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Status}"
                     Value="1">
          <Setter Property="Foreground"
                  Value="Red" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </DataGrid.CellStyle>      
</DataGrid>