wpf 触发器 属性 IsPressed 无法正常工作

wpf trigger property IsPressed not working correctly

当我点击一个Button时,其中的图像必须改变并且保持改变。我尝试在ButtonStyle上使用Triggers,将图像绑定到IsPressed属性,但是当Button被释放时,图片 returns 上一张。请帮忙。

<Button Content="Easy Locate" Height="20" Width="85" Margin="0,2,0,0">
  <Button.Style>
    <Style TargetType="{x:Type Button}">
      <Style.Triggers>
        <Trigger Property="IsPressed" Value="True">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="{x:Type Button}">
                <Border BorderThickness="0">
                  <Image Source="/AltusClient;component/Images/waiting.png"
                         Height="20"
                         Width="25"/>
                </Border>
                <!--<ControlTemplate.Triggers>
                  <Trigger Property="IsPressed" Value="True">
                    <Setter Property="Background" Value="Transparent"/>
                    <Setter Property="BorderThickness" Value="0"/>
                  </Trigger>
                </ControlTemplate.Triggers>-->
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Button.Style>
</Button>

这是一个按您想要的方式工作的按钮示例。您可以通过添加另一个 Trigger 将其 Tag 属性 设置为 null、一个空字符串或世界上任何其他东西,轻松地将按钮切换回默认状态比 "ButtonHasBeenPressed"

<Button Content="Button Content">
    <Button.Style>
        <Style TargetType="Button">
            <Style.Resources>
                <ControlTemplate 
                    x:Key="PressedTemplate" 
                    TargetType="Button">
                    <Border 
                        Background="LightSkyBlue" 
                        BorderBrush="DeepSkyBlue" 
                        BorderThickness="4"
                        >
                        <TextBlock 
                            Text="Replace this TextBlock with your own content" 
                            Foreground="ForestGreen" 
                            />
                    </Border>
                </ControlTemplate>
            </Style.Resources>
            <Style.Triggers>
                <!-- 
                We can't set Template directly with DiscreteObjectKeyFrame because 
                "Cannot freeze this Storyboard timeline tree for use across threads".

                So instead we kludge it by setting Tag and putting a trigger on that. 
                -->
                <Trigger 
                    Property="Tag" 
                    Value="ButtonHasBeenPressed"
                    >
                    <Setter 
                        Property="Template" 
                        Value="{StaticResource PressedTemplate}" 
                        />
                </Trigger>
                <Trigger Property="IsPressed" Value="True">
                    <!-- 
                    Values set by a Trigger setter are automatically rolled 
                    back when the Trigger condition no longer applies. This 
                    is not true of values applied by a Storyboard in an enter 
                    action. 
                    -->
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames 
                                    BeginTime="00:00:00" 
                                    Storyboard.TargetProperty="Tag"
                                    >
                                    <DiscreteObjectKeyFrame 
                                        KeyTime="00:00:00" 
                                        Value="ButtonHasBeenPressed" 
                                        />
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

您也可以使用代码隐藏。

假设按钮是:

<Button Click="Button_Click">
  <Image Source="/Image1.png"/>
</Button>

那么,后面的代码可以是:

private void Button_Click(object sender, RoutedEventArgs e)
{
    var b = sender as Button;

    if (b == null)
        return;

    var image = new Image { Source = GetImageSource(), };

    b.Content = image;
}

private BitmapImage GetImageSource()
{
    var imageSource = new BitmapImage();

    imageSource.BeginInit();
    imageSource.UriSource = new Uri("/Image2.png", UriKind.Relative);
    imageSource.EndInit();

    return imageSource;
}

这是一个简化版本,每次用户单击时都会加载新图像。如果想避免不必要的二次加载,可以像private bool _imageSet;这样设置一个private flag,在Button_Click方法上设置。

您还可以在 Window(或 UserControl)初始化时尽早加载新图像。

最后,我建议您将所有图像放在 ResourceDictionary 中,并通过 StaticResource Key 在整个应用程序中调用它们,而不是到处使用 URI。但那是另一个话题了。