.net - 在 WPF 中定义多个时 DataTrigger 不触发

标签 .net wpf xaml datatrigger

我遇到了一个 WPF 问题,我无法解决,而且我已经发布了很多 stackoverflow 帖子,但都没有运气,所以我想我会看看是否有人可以提供帮助

我只是想让我的 DataGrid 的单元格背景根据值是上升还是下降来脉动两种颜色中的一种

我尝试使用 EventTrigger NotifyOnTargetUpdated 并绑定(bind)背景颜色,但不允许绑定(bind)到 Storyboard中的属性背景

然后我尝试将 DataTriggers 与状态字段一起使用,“U”表示向上,“D”表示向下。我在每个更新周期开始时将状态重置为“N”(更新受到限制),起初,每个场景都有 2 个 DataTriggers,看起来一切正常。我同时看到了绿色和红色动画,但后来我注意到有更新发生但没有更新。一旦更新通过,似乎只有首先声明的 DataTrigger 才真正起作用,在极少数情况下没有出现第一个条件时,另一个触发器会触发。为了检验这个理论是否正确,我首先运行了每个条件,正如预期的那样,在每种情况下,第一个声明的触发器只会触发 90% 的时间。

我到处搜索试图找到这种异常的原因,但没有运气,如果有人能阐明如何解决这个问题,甚至可能以更可靠的方式实现相同的功能,我将不胜感激。

 <DataGridTextColumn Header="Last Trade" Width="60" Binding="{Binding last_trade}" IsReadOnly="true">
      <DataGridTextColumn.CellStyle>
                    <Style TargetType="DataGridCell"> 
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=last_trade_state}" Value="D">
                                <DataTrigger.EnterActions>
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:01" From="LightSalmon" To="Transparent"></ColorAnimation>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </DataTrigger.EnterActions>
                            </DataTrigger>

                            <DataTrigger Binding="{Binding Path=last_trade_state}" Value="U">
                                <DataTrigger.EnterActions>
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:01" From="LightGreen" To="Transparent"></ColorAnimation>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </DataTrigger.EnterActions>
                            </DataTrigger>

                        </Style.Triggers>
                    </Style>
                </DataGridTextColumn.CellStyle>
            </DataGridTextColumn>

最佳答案

诊断

首先让我介绍一下我认为的MCVE说明问题:

<Grid Background="CornflowerBlue">
    <CheckBox x:Name="_CheckBox" Content="Toggle me" />
    <Grid.Style>
        <Style TargetType="Grid">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsChecked, ElementName=_CheckBox}" Value="False">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:01" From="LightSalmon" To="Transparent" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsChecked, ElementName=_CheckBox}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:01" From="LightGreen" To="Transparent" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

加载 Grid 时,我们会看到一个红色闪烁,表明触发了第一个触发器 - 这是预期的行为。如果我们随后检查 CheckBox,我们会看到一个绿色的闪光,这意味着第二个触发器被触发了——再次,正如预期的那样。但这就是问题所在 - 如果我们取消选中 CheckBox,我们将不再看到红色闪光。事实上,从现在开始,我们只会在选中时看到绿色闪烁,而在取消选中 CheckBox 时不会看到红色闪烁。如果我们对触发器重新排序,情况是对称的。

这种行为的原因归结为两个事实:

  1. 动画一旦启动,不会自动停止(默认情况下 - 请参阅进一步说明)
  2. 如果我们在一个已经设置动画的属性上应用一个动画,它不会停止/删除之前的动画,而是将它添加到该属性的动画列表中——在我们的例子中,最后添加的动画覆盖了由前一个,但情况可能并非总是如此1

当动画到达其持续时间结束时会发生什么由 FillBehavior 属性控制,该属性有两个值 - HoldEndStop ,默认值为 HoldEnd。所以在我们的例子中,当任一动画完成时,它都会保持背景 Transparent。它与实际透明的背景一致 - 如果背景没有动画,它将变回 CornflowerBlue

鉴于我们对观察到的行为有解释 - 第一个红色动画可见,因为绿色动画尚未开始。但是一旦是,当我们取消选中 CheckBox 时,红色动画会重新启动,但我们看不到它的效果,因为它们被保持背景 Transparent 的绿色动画覆盖了.至少这是一个可行的逻辑模型——也许框架足够聪明,不会在它们的效果无论如何都会被忽略时不启动动画,并且红色动画实际上并没有重新启动。

半解

下一个合乎逻辑的步骤是在我们的动画上设置 FillBehavior=Stop。这让我们接近我们的目标,但还不够。除了这两个异常(exception),一切看起来都很好:

  1. 一旦动画结束,背景将返回到 CornflowerBlue - 这可能不是所需的行为
  2. 如果我们在绿色动画仍在运行时取消选中 CheckBox,它不会立即停止,而是会结束,然后我们才能看到红色动画的剩余部分

解决方案

当检查或未选中复选框时,我们真正想做的是在运行时流产当前动画并将其替换为另一个动画。为此,我们可以命名 BeginStoryboard 元素并使用 StopStoryboard 元素中止当前动画:

<Grid Background="CornflowerBlue">
    <CheckBox x:Name="_CheckBox" Content="Toggle me" />
    <Grid.Style>
        <Style TargetType="Grid">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsChecked, ElementName=_CheckBox}" Value="False">
                    <DataTrigger.EnterActions>
                        <StopStoryboard BeginStoryboardName="Storyboard2" />
                        <BeginStoryboard Name="Storyboard1">
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:01" From="LightSalmon" To="Transparent" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsChecked, ElementName=_CheckBox}" Value="True">
                    <DataTrigger.EnterActions>
                        <StopStoryboard BeginStoryboardName="Storyboard1" />
                        <BeginStoryboard Name="Storyboard2">
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:01" From="LightGreen" To="Transparent" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

FillBehavior=Stop 的使用是可选的,它只会控制背景是否返回到 CornflowerBlue

1 我刚刚确认事实上并非总是如此,即使使用 ColorAnimation - 你可以简单地不设置 To 属性既没有动画(也没有放置 StopStoryboard 元素),并且可以清楚地看到它们混合在一起。

关于.net - 在 WPF 中定义多个时 DataTrigger 不触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28586884/

相关文章:

wpf - 如何在 WPF 中设置按钮上的文本?

c# - 如何在 .net core 2.1 中忽略 SSL 验证

wpf - 我可以实现自己的 View 解析服务并让 RequestNavigate 使用它吗?

c# - 在 Windows XP 下通过远程桌面渲染 WPF 有问题吗?

wpf - WPF列表框在MouseOver上的ItemTemplate中显示按钮

c# - Command.CanExecute 触发后 CommandParameter 绑定(bind)解析

c# - 绑定(bind)到 Properties.Settings.Default.myString 的文本框文本不会更新 myString

c# - 在图像点击上在模拟器中打开图库

.net - 在 Windows 窗体面板中查找控件

c# - 根据字符串生成Guid