使用XAML更改背景不透明度而不改变颜色

8
在我的C# / WPF / .NET 4.5应用程序中,我想实现一个触发器,可以切换控件的背景不透明度而不改变其颜色。
通常,要设置控件的背景画刷,我会使用以下Setter:
<Setter TargetName="TargetControl" Property="Background">
<Setter.Value>
  <SolidColorBrush Color="Red" Opacity="0.2"/>
</Setter.Value>

现在我面临这样的情况:我只需更改透明度而不更改颜色。如果这种情况下我的setter会是什么样子呢?我并不关心背景颜色是什么,但我希望在更改透明度的同时保留颜色。
更多细节:
原因是我正在处理一个ItemsControl,在这个控件中,背景颜色根据项目的AlternationIndex而变化。
<ItemsControl ItemsSource="{Binding SomeCollection}" AlternationCount="6">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Grid x:Name="GridWithin">
      <!-- ... -->
      </Grid>
      <DataTemplate.Triggers>
        <!-- Aternating colors for each row -->
        <Trigger Property="ItemsControl.AlternationIndex" Value="0">
          <Setter TargetName="GridWithin" Property="Background">
            <Setter.Value>
              <SolidColorBrush Color="Red" Opacity="0.2"/>
            </Setter.Value>
          </Setter>
        </Trigger>
        <Trigger Property="ItemsControl.AlternationIndex" Value="1">
          <Setter TargetName="AllGesturesDataTemplateGrid" Property="Background">
            <Setter.Value>
              <SolidColorBrush Color="Green" Opacity="0.2"/>
            </Setter.Value>
          </Setter>
        </Trigger>
        <!-- ... -->
        <!-- Highlight when a hit is registered -->
        <DataTrigger>
          <DataTrigger.Conditions>
            <Condition Binding="{Binding IsHit}" Value="True" />
          </MultiDataTrigger.Conditions>
          <!-- The culprit -->
          <Setter TargetName="GridWithin" Property="Background">
            <Setter.Value>
              <SolidColorBrush Opacity="0.7"/>
            </Setter.Value>
          </Setter>
          <!-- /culprit -->
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>
3个回答

7
我花了一些时间去考虑如何最好地实现这个...结果比我最初想象的要棘手。尽管如此,它是可以实现的,但需要编写相当多的代码。为了能够定位到 Background Brush 对象的实际 Opacity 属性,您需要使用一个 StoryBoard ... 这就是为什么这个代码示例如此冗长的原因。
由于我们需要在 DataTrigger 中使用一个 Storyboard 对象,这意味着我们必须将 DataTrigger.EnterActions 作为一个 Storyboard 使用,因为 Storyboard 不能用于普通的 DataTrigger.Setters 集合中。这也意味着,我们还必须使用 DataTrigger.ExitActions 提供另一个 Storyboard,将 Opacity 属性设置回其原始值。请尝试以下内容:
<Grid Name="YourGrid">
    <Grid.Background>
        <SolidColorBrush Color="Green" Opacity="0.2" />
    </Grid.Background>
    <Grid.Style>
        <Style TargetType="{x:Type Grid}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsMouseOver, ElementName=YourGrid}" 
                    Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimationUsingKeyFrames 
Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)">
                                    <LinearDoubleKeyFrame Value="0.7" KeyTime="0:0:0"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimationUsingKeyFrames 
Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)">
                                    <LinearDoubleKeyFrame Value="0.2" KeyTime="0:0:0"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

尽管实现此方法所需的代码量很大,但它确实可以完全达到您的要求。然而,有一种更简单的方法可以获得同样的整体效果,但是需要稍微少一些代码。您可以将一个Rectangle添加到每个Grid单元格或分割线的后面,并在其中设置颜色和不透明度。使用此方法,您可以直接设置Rectangle.Opacity值,尽管这会使用额外的控件...选择权在您手中。

1
我最终使用了 Rectangle 方法 =) - mbaytas

2
此答案与@Sheridan的几乎完全相同,但它节省了几行XAML代码(因为已经有太多的代码了...)
Grid Name="YourGrid">
    <Grid.Background>
        <SolidColorBrush Color="Green" Opacity="0.2" />
    </Grid.Background>
    <Grid.Style>
        <Style TargetType="{x:Type Grid}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsMouseOver, ElementName=YourGrid}" 
                    Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)">
                                <DoubleAnimation To="0.7" Duration="0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)">
                                <DoubleAnimation To="0.2" Duration="0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

但也因为它值得认可。 - Jeremy Little

-1
“Grid”有自己的“Opacity”属性和“Background”属性。也许可以使用您的触发器来更改不透明度,而保留背景颜色不变?

-1 改变 Grid.Opacity 显然也会使所有内容透明...显然不是所请求的。 - Sheridan
"GridWithin" 是项控件中单个项目的模板根。 - Dave
触发 AlternatingIndex 来设置该网格的背景,并触发 IsHit 来设置其不透明度。 - Dave
“GridWithin”是项控件中单个项的模板根源。首先,您为什么认为是这样?在问题作者的XAML中肯定没有显示。其次,即使它只包含一个控件并且您设置了“Grid.Opacity”属性,单个控件也会被淡化,我相信这不是要求。 - Sheridan
其次,是的,你是对的,不透明度会被继承到网格中的所有控件,这不是想要的结果,我的错误。 - Dave
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接