有没有一种方法可以使用样式设置器来设置属性的属性?

5

编辑:在原问题中,我对setter的工作方式做出了一些错误的假设,因此我进行了修改,希望更准确、更有用。

我尝试通过让菜单项的图标在鼠标未悬停在该项上时半透明地显示来使其更加有趣。如果鼠标进入,图标应该被动画化,从而完全可见。

动画效果很好,Storyboard.TargetProperty 允许直接访问图标的不透明度属性:

<Style x:Key="MenuItemMouseOverStyle" TargetType="MenuItem">
    <Style.Triggers>
        <EventTrigger RoutedEvent="MouseEnter">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Icon.Opacity">
                        <EasingDoubleKeyFrame KeyTime="0" Value="0.5"/>
                        <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="MouseLeave">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Icon.Opacity">
                        <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                        <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0.5"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
</Style>

如果我尝试为初始图标透明度使用设置器,代码将无法编译:

<Setter Property="Icon.Opacity" Value="0.5"/>

编辑: 设置器并不像我尝试使用的那样工作,您不能访问属性的属性(请查看答案) 唯一可以做的就是指定目标类,如果样式的目标类型尚未设置,则以下样式应该是等效的:

<Style x:Key="Style1" TargetType="Image">
    <Setter Property="Opacity" Value="0.5"/>
</Style>
<Style x:Key="Style2">
    <Setter Property="Image.Opacity" Value="0.5"/>
</Style>

我的问题是是否有一种方法可以通过setter来实现这个功能。

(我目前的解决方法是使用单个关键帧故事板,在Loaded事件触发时触发,效果相当不错)

2个回答

1
我认为你不能像那样访问一个属性的属性,所以转换本身不是问题。即使 Icon 是 Image 类型也不行。例如,你可以尝试使用 Grid 的 Background Opacity。Background 是 Grid 的 Dependency Property,而 Opacity 是 Brush 的 Dependency Property,但以下行不起作用。
<Grid Background.Opacity="0.8"/>

你会收到一个错误提示

在类型“Background”中未找到可附加的属性“Opacity”。

你需要像这样在 Background 中设置它

<Grid>
    <Grid.Background>
        <SolidColorBrush Opacity="0.8"/>
    </Grid.Background>
</Grid>

所以,当你像这样做某事时,它的意思是什么?

<Grid TextBlock.Foreground="Red">
    <TextBlock Text="Test"/>
</Grid>

你实际上正在为TextBlock使用附加属性Foregroud。

Image没有名为Opacity的附加属性,因此您也无法这样做。

<MenuItem Image.Opacity="0.8" />

除了你已经在做的那个方法之外,另一个解决方法是使用像这样的东西(顶部 MenuItem 或者你想使用它的任何地方)。

<MenuItem x:Name="topMenuItem"
          ...>
    <MenuItem.Resources>
        <Style TargetType="Image">
            <Setter Property="Opacity" Value="0.5"/>
        </Style>
    </MenuItem.Resources>
    <!-- ... -->
</MenuItem>

你提出的解决方案是可行的,但是比单个关键帧解决方法更加麻烦,因为setter应该在相同的样式定义中,因为它属于动画。好吧,我没有期望有任何好的解决方案,因为整个setter和trigger的业务有点受限制(例如,EventTriggers仅适用于storyboard而不是简单的setter)无论如何还是谢谢。 - H.B.
@H.B.:是的,我同意,你已经在使用的解决方案更好,所以继续使用它吧 :) 如果Resources是一个DP,你可以将其添加到你的MenuItem样式中,但由于它不是,所以这是不可行的。 - Fredrik Hedblad
我不太明白你的意思,为什么资源应该是DP? 将图像样式嵌入Style.Resources似乎可以起作用... - H.B.
@H.B.:没错!Style.Resources 可以用。我的意思是你不能把 Resources 放在 setter 里,但正如你所说,Style.Resources 可以用。感谢您指出这一点 :) - Fredrik Hedblad

1

所以在阅读了Meleak的回答并发现可以通过资源在样式中拥有另一个样式后,最接近使用Setter实现这一点的方法就是嵌入一个样式来访问图标的不透明度。 在这里,我假设图标是一个图像,因此将其作为目标类型使用,完整的样式如下:

<Style x:Key="MenuItemMouseOverStyle" TargetType="MenuItem">
    <Style.Resources>
        <Style TargetType="Image">
            <Setter Property="Opacity" Value="0.5"/>
        </Style>
    </Style.Resources>
    <Style.Triggers>
        <EventTrigger RoutedEvent="MouseEnter">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Icon.Opacity">
                        <EasingDoubleKeyFrame KeyTime="0" Value="0.5"/>
                        <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="MouseLeave">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Icon.Opacity">
                        <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                        <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0.5"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
</Style>

唯一的问题是它实际上并没有设置Icon.Opacity,而是可能出现在菜单项中的所有图像的不透明度。

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