【问题标题】:WPF Button behavior using Triggers使用触发器的 WPF 按钮行为
【发布时间】:2013-04-28 19:53:05
【问题描述】:

我有一个Button,其自定义外观由ControlTemplate 定义。

它包含一个Canvas,其中包含一个Path。我想根据鼠标状态在Path.Opacity 中添加更改:

  • 默认 - 0.5
  • 鼠标悬停,未按下 - 1.0
  • 鼠标悬停,按下 - 0.5

只需将Path.Opacity 的本地值设置为0.5 并为Trigger 添加一个Trigger,即可涵盖第一种情况:

<Button x:Class="ImagingShop.Panosphere.Controls.PathButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="100" d:DesignWidth="100"
        Name="pathButton">

    <Button.Template>
        <ControlTemplate>
            <Canvas Background="Transparent" Width="{TemplateBinding Width}" Height="{TemplateBinding Width}">
                <Canvas.Style>
                    <Style TargetType="Canvas">
                        <Setter Property="Path.Opacity" Value="0.5"/>
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Path.Opacity" Value="1.0"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Canvas.Style>
                <Path Data="{Binding ElementName=pathButton, Path=PathData}" Stretch="Uniform" Fill="#FFFFFFFF" Width="{TemplateBinding Width}" Height="{TemplateBinding Width}"/>
            </Canvas>
        </ControlTemplate>
    </Button.Template>

    <Grid>

    </Grid>
</Button>

但是,第三种情况不起作用。我添加了以下触发器:

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="IsMouseOver" Value="True"/>
        <Condition Property="Button.IsPressed" Value="True"/>
    </MultiTrigger.Conditions>
    <Setter Property="Path.Opacity" Value="0.75"/>
</MultiTrigger>

所以这应该将Path.Opacity 设置为0.75 是鼠标悬停在按钮上并且按钮被按下。

由于不透明度更改为0.5 而不是0.75,我对此感到困惑!触发器似乎适用,但没有按预期工作...

【问题讨论】:

  • 那么 - 不能仅使用 XAML 重新设置按钮的样式吗?看来 Button.IsPressed 应该可以工作 - 有一个 XAML example 正在这样做。

标签: wpf button triggers controltemplate


【解决方案1】:

您为什么不使用ButtonOpacity 并直接在ButtonStyle 上触发,您的ControlTemplate 除了这个Path 之外什么都没有。

<Style TargetType="{x:Type local:PathButton}">
  <Setter Property="Opacity"
          Value=".5" />
  <Setter Property="OverridesDefaultStyle"
          Value="True" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:PathButton}">
        <Canvas Width="{TemplateBinding Width}"
                Height="{TemplateBinding Width}"
                Background="Transparent">
          <Path Width="{TemplateBinding Width}"
                Height="{TemplateBinding Width}"
                Data="{Binding ElementName=pathButton,
                                Path=PathData}"
                Fill="#FFFFFFFF"
                Opacity="{TemplateBinding Opacity}"
                Stretch="Uniform" />
        </Canvas>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Style.Triggers>
    <Trigger Property="IsMouseOver"
              Value="True">
      <Setter Property="Opacity"
              Value="1" />
    </Trigger>
    <Trigger Property="IsPressed"
              Value="True">
      <Setter Property="Opacity"
              Value=".75" />
    </Trigger>
  </Style.Triggers>
</Style>

将产生您期望的输出。

更新:

您可以只在ResourceDictionary 中包含Style,并在代码隐藏文件中包含子类声明。这将只生成一个 xaml 文件。在此方法中,您不会留下 2 个 xaml 文件。

还将PathData 的绑定切换为RelativeSource 绑定。

您可以从Here 下载此示例。打开看看

我还使用了一个插件 NestIn,它允许您通过编辑 vsproj 文件并添加 DependsOn 属性将文件分组到自定义组中。这使您可以将 ResourceDictionary 和代码隐藏类文件组合到一个实体 PathButton.xaml 中,就像 UserControlWindow 在 IDE 中的代码隐藏文件一样。

【讨论】:

  • 好的,这部分可行,但我不得不将整个样式移到 PathButton.xaml 代码之外 - 我想将它放在里面的原因是 {TemplateBinding PathData} 不起作用,只有 {Binding ElementName=pathButton, Path=PathData} 起作用。 PathData 是 String 类型的普通依赖属性。样式现在指的是一些元素名称,它是一个神奇的常数,我希望代码尽可能独立(最好是单个 XAML 文件......)。如果每个自定义控件至少有两个 XAML 文件(一个用于代码,一个用于样式),那么代码将非常分散……
  • @Libor 我已经用一个简短的描述更新了我的答案,并链接到一个保管箱下载,您可以获得并查看如何在仅 1 个 xaml 文件中构建它并使用PathData 的 RelativeSource 绑定而不是 TemplateBinding。下载并自己看看。
  • 谢谢!现在它就像一个魅力。我一开始尝试在 Button.Style 中添加 PathButton 样式,但这会导致类型不匹配,因为样式针对的是 PathButton 而不是 Button。感谢您的代码,我意识到除了样式本身之外,按钮不需要 XAML。我仍然对 TemplateBindingExtension 感到困惑,因为它可以无缝地与 WPF 控件属性一起使用,但根本不能与自定义控件属性一起使用......好吧,至少有一个解决方案(尽管它看起来不像 TemplateBinding 那样简单优雅)。
  • @Libor Yh 这是一个已知问题,TemplateBinding 有时不适用于自定义 DP。你可以在 SO 上找到一些讨论它的线程。您可以使用稍短的{Binding PathData, RelativeSource={RelativeSource TemplatedParent}} :) 因为这只是在一个样式中
猜你喜欢
  • 2012-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
  • 2015-07-31
相关资源
最近更新 更多