我有一个WPF的问题我无法解决,我有很多stackoverflow帖子没有任何运气所以我想我会看看是否有人可以帮助
我只想让我的DataGrid的单元格背景根据值上升或下降的值来脉冲两种颜色中的一种
我尝试使用EventTrigger NotifyOnTargetUpdated并绑定背景颜色,但不允许绑定到storyboard中的属性背景
然后我尝试将DataTriggers与状态字段一起使用," U" for up," 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>
答案 0 :(得分:2)
首先让我介绍一下我认为是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
时没有红色闪光。如果我们重新排序触发器,情况就是对称的。
这种行为的原因归结为两个事实:
当动画到达其结束时会发生什么事情由FillBehavior
属性控制,该属性有两个值 - HoldEnd
和Stop
,默认值为{{1} }。因此,在我们的情况下,当任一动画完成时,它保持背景HoldEnd
。它与背景实际上是透明的一致 - 如果背景没有动画,它会变回Transparent
。
鉴于我们对观察到的行为有一个解释 - 第一个红色动画是可见的,因为绿色动画尚未开始。但是一旦它被取消,当我们取消选中CornflowerBlue
重新启动红色动画时,我们无法看到它的效果,因为它们被持有背景CheckBox
的绿色动画覆盖。至少那是一个可行的逻辑模型 - 也许框架足够聪明,当它们的效果无论如何都会被忽略时不启动动画,并且实际上没有重新启动红色动画。
下一个合乎逻辑的步骤是在我们的动画上设置Transparent
。这让我们接近目标,但并不完全在那里。这两个例外情况看起来都很好:
FillBehavior=Stop
- 这可能不是所需的行为CornflowerBlue
,它不会立即停止,而是完成,只有这样我们才能看到红色动画的剩余部分选中或取消选中CheckBox
时,我们真正要做的是在当前动画正在运行时中止当前动画并将其替换为另一个动画。为此,我们可以命名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
。
1 我刚刚确认事实并非总是如此,即使 CornflowerBlue
- 您也无法设置两个动画上都没有em ColorAnimation
属性(并删除 To
元素),并且可以清楚地看到它们混合在一起。
答案 1 :(得分:1)
我发现这是一个common问题,在您的代码中,DataTrigger EnterActions已根据debug执行,但我不知道为什么背景在第一次之后没有更改,我把它放在tabcontrol中,每当我选择标签时,它只在第一次有效。
Finnaly,我发现一种方法可以解决它。你可以尝试一下。
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=last_trade_state}" Value="D">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)" >
<ColorAnimation Duration="00:00:1" From="LightSalmon" To="Transparent"
></ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=last_trade_state}" Value="U">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)">
<ColorAnimation Duration="00:00:1" From="LightGreen" To="Transparent"
></ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>