使用样式触发器来设置嵌套对象的属性

11

我在一个大画布上画了一个小多边形。当鼠标移动到画布上方时,我想要突出显示这个多边形。代码如下:

<UserControl ...>
  <Canvas Name="canvas" Height="22" Width="22">
      <Canvas.Resources>
          <Style TargetType="Canvas">
              <Style.Triggers>
                  <Trigger Property="IsMouseOver" Value="false">
                      <Setter Property="polygon.Stroke" Value="#EEEEEE"/>
                  </Trigger>
                  <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="polygon.Stroke" Value="Aqua"/>
                </Trigger>
              </Style.Triggers>
          </Style>
      </Canvas.Resources>
      <Polygon Points="11,1 16,6 16,16 11,21" Name="polygon">
              <Polygon.Fill>
                  <SolidColorBrush Color="#EEEEEE"/>
              </Polygon.Fill>
      </Polygon>
  </Canvas>
</UserControl>

但是setter方法无法访问“polygon”。

3个回答

20

您不能像那样使用Setters,如果您使用这种符号,引擎将查找附加属性,或者在点之前的类型上没有设置Style.TargetType属性。

最简单的方法可能是将样式应用于多边形本身,并使用DataTrigger绑定到Canvas,以便您可以根据其属性触发操作。

  <Polygon Points="11,1 16,6 16,16 11,21" Name="polygon">
       <Polygon.Fill>
           <SolidColorBrush Color="#EEEEEE"/>
       </Polygon.Fill>
       <Polygon.Style>
          <Style TargetType="{x:Type Polygon}">
             <Style.Triggers> 
                <DataTrigger
                   Binding="{Binding Path=IsMouseOver,
                                     RelativeSource={RelativeSource
                                     AncestorType={x:Type Canvas}}}"
                   Value="True">
                   <Setter Property="Stroke" Value="Red"/>
                </DataTrigger>
             </Style.Triggers>
          </Style>
       <Polygon.Style>
  </Polygon>

它可以工作,但仍然只有当鼠标在多边形上方时才有效,而不是在画布的其他部分上方。 :( - Badiboy
@Badiboy:正如另一个答案所指出的,你需要在画布上设置背景,否则就没有命中测试。 - H.B.
@AngelWPF:如果我不故意添加代码,大部分时间可能会导致人们复制和粘贴而不是理解概念。例如,您的代码在绑定中使用了RelativeSource,虽然还有其他方法可用,因此即使没有复制该代码,某种方法也正在加强通用概念。 - H.B.
@H.B.,我认为既然您已经解释了答案,代码将有助于一个初学者开发者更清楚地理解。例如,我曾经也是一个初学者,当只有解释的文字时,我会感到非常困惑。再次抱歉编辑了您的答案。如果您愿意,可以将其删除。 - WPF-it
@H.B. 我替换了这个用户控件的HitTestCore,因此即使画布中没有背景,事件也会被触发。不过我会尝试设置背景... - Badiboy
@H.B. Shure,背景真的解决了问题。非常感谢您的帮助! - Badiboy

1

尝试使用EventTrigger,因为其他类型的触发器只能在模板或样式中使用。而我们已经知道Style.Trigger不能适用于你的情况。因此,这里有一个可行的示例:

<Canvas Name="canvas" Height="22" Width="22">
    <Polygon Points="11,1 16,6 16,16 11,21" Name="polygon">
        <Polygon.Fill>
            <SolidColorBrush x:Name="brush" Color="#EEEEEE"/>
        </Polygon.Fill>
        <Polygon.Triggers>
            <EventTrigger RoutedEvent="UIElement.MouseEnter">
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetName="brush" Storyboard.TargetProperty="Color">
                        <ColorAnimation From="#EEEEEE" To="Aqua" Duration="00:00:00.01" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger RoutedEvent="UIElement.MouseLeave">
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetName="brush" Storyboard.TargetProperty="Color">
                        <ColorAnimation From="Aqua" To="#EEEEEE" Duration="00:00:00.01" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Polygon.Triggers>
    </Polygon>
</Canvas>

你可以使用普通触发器(Trigger.EnterActionsTrigger.ExitActions)来完成相同的事情,关键是这是一种不同的动画。此外,您的示例不再在画布上触发,而是在多边形本身上触发。 - H.B.
对于EnterActions/ExitActions,您需要一个IsMouseOver属性,它是IInputInterface的一部分。但是Canvas和Polygon都没有其实现。 - Sergei B.
Canvas是透明的,所以路由事件MouseEnter/MouseLeave不会触发。您需要为其指定一些背景,至少几乎透明。 - Sergei B.
似乎只有在鼠标悬停于多边形上时,“RoutedEvent”才能起作用,因为如果它们都在事件点下,则从父级路由到子级... - Badiboy
@invisible:示例中画布是否透明并不重要,而且多边形和画布都有IsMouseOver,你在说什么? - H.B.
同意,我的失败,有IsMouseOver。 - Sergei B.

-2
它正在查找名为“多边形”的Canvas属性,而该属性又具有名为“Stroke”的属性。如果你想让setter定位到不同的对象,你需要使用TargetName。
<Setter TargetName="polygon" Property="Stroke" Value="#EEEEEE" />

2
我尝试过了。但是“TargetName属性不能在样式Setter上设置”。 - Badiboy
3
难为情了。我总是忘记那个小限制。 - Matthew Walton

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