My problem seems to be the opposite of the one everybody else has. My WPF DataTrigger fires sometimes even when the viewmodel property to which it is tied does not change. I've put logging code in the property itself to make sure it's not changing.
Is there some easy to way determine WHY an animation is firing? Some event I can subscribe to let me put a breakpoint in my own code and look at the call stack at the moment the animation fires?
Here's the Storyboard. Just animating a double from 0 to 1 over 1 second. The double will be stored in FrameworkElement.Tag
<Storyboard x:Key="TagZeroToOne" x:Shared="False">
<DoubleAnimation Storyboard.TargetProperty="Tag" From="0" To="1" Duration="0:0:1.0" />
</Storyboard>
And here is the relevant bit of the style that uses it in the DataTrigger. (I've left out the item template and panel)
<!-- Style for ItemsControl that draws circular handles when ShapeVm is selected -->
<Style x:Key="ShapeHandlesItemsControlStyle" TargetType="{x:Type ItemsControl}">
<d:Style.DataContext>
<x:Type Type="gci:ShapeVm" />
</d:Style.DataContext>
<!-- Default style value of ItemsControl.Tag" property is 1.0 -->
<Setter Property="Tag">
<Setter.Value>
<sys:Double>1.0</sys:Double>
</Setter.Value>
</Setter>
<!--
We cannot animate Opacity directly because its max value depends upon
a binding but we be we can make it be dependent upon another property
"Tag" that we *do* animate. This requires a Math Converter as well
Picked up this technique from the following SO question
https://stackoverflow.com/questions/2186933/wpf-animation-binding-to-the-to-attribute-of-storyboard-animation/14164245#14164245
-->
<Setter Property="Opacity">
<Setter.Value>
<MultiBinding Converter="{StaticResource CvtMath}"
ConverterParameter="1.0 - (x *(1.0-y))"> <!-- Calculation -->
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" /> <!-- Animated operand (0.0 to 1.0) -->
<Binding ElementName="Root" Path="ShapeHandleOpacity" /> <!-- Configured opacity operand -->
</MultiBinding>
</Setter.Value>
</Setter>
<!-- When ShapeVm.IsSelected becomes true, animate the ItemsControl.Tag from 0 to 1.0 -->
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource TagZeroToOne}" />
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
The idea is that when the user first selects the shape, my code-behind sets its IsSelected property to "true". That makes the animation fire and I see the visual effect tied to my animation. But that's supposed to be it.
Instead, it seems that almost every other time I click on the object in question, The animation fires and I see the effect. Yet I have verified (repeatedly) via logging and breakpoints that the IsSelected property is never changing after that. Nobody is setting it. Nobody is firing a PropertyChanged Notification for it and as far as I can see, nobody is even firing PropertyChanged(null).
And here is the ShapeVm.IsSelected property
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
if (value == _isSelected)
return;
_isSelected = value;
Debug.WriteLine($"Shape selected change to {value}");
}
}
So how do I determine why WPF is making this trigger fire?