正如承诺的那样,我已经重新审视了这个答案来举个例子。我发现我的原始答案不起作用,因为无法在运行时修改触发器集合。还有另一种解决方案,我将在这里解释。
更新答案
由于我们无法在运行时更改触发器集合,我看到了两个可能的选项:
- 制作一个智能的 EventTrigger,它将知道如何处理第一个
TargetUpdated 事件并忽略它。
- 创建我们自己的新附加事件,让 EventTrigger 处理它,并仅在我们希望 EventTrigger 触发时引发它,即每次更新目标时,除了第一次。
第一个选项可以使用Blend SDK and inheriting from TriggerBase<T>。我还没有尝试过,但这可能是一个不错的方法。
第二个选项相当简单,在这里提供:
public class AfterLoadBehavior
{
#region TargetUpdatedAfterLoad Attached Event
public static readonly RoutedEvent TargetUpdatedAfterLoadEvent = EventManager.RegisterRoutedEvent(
"TargetUpdatedAfterLoad", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AfterLoadBehavior));
public static void AddNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
UIElement uiElement = d as UIElement;
if (uiElement != null)
{
uiElement.AddHandler(TargetUpdatedAfterLoadEvent, handler);
}
}
public static void RemoveNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
UIElement uiElement = d as UIElement;
if (uiElement != null)
{
uiElement.RemoveHandler(TargetUpdatedAfterLoadEvent, handler);
}
}
#endregion
#region RaiseTargetUpdatedAfterLoadEvent Attached Property
public static bool GetRaiseTargetUpdatedAfterLoadEvent(FrameworkElement obj)
{
return (bool)obj.GetValue(RaiseTargetUpdatedAfterLoadEventProperty);
}
public static void SetRaiseTargetUpdatedAfterLoadEvent(FrameworkElement obj, bool value)
{
obj.SetValue(RaiseTargetUpdatedAfterLoadEventProperty, value);
}
public static readonly DependencyProperty RaiseTargetUpdatedAfterLoadEventProperty =
DependencyProperty.RegisterAttached("RaiseTargetUpdatedAfterLoadEvent", typeof(bool), typeof(AfterLoadBehavior),
new PropertyMetadata(false, OnRaiseTargetUpdatedAfterLoadEventChanged));
private static void OnRaiseTargetUpdatedAfterLoadEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = (FrameworkElement)d;
frameworkElement.AddHandler(Binding.TargetUpdatedEvent, new RoutedEventHandler((sender, args) =>
{
if (GetIsFirstValueChange(frameworkElement))
{
SetIsFirstValueChange(frameworkElement, false);
return;
}
frameworkElement.RaiseEvent(new RoutedEventArgs(AfterLoadBehavior.TargetUpdatedAfterLoadEvent));
}));
}
#endregion
#region IsFirstValueChange Attached Property
public static bool GetIsFirstValueChange(FrameworkElement obj)
{
return (bool)obj.GetValue(IsFirstValueChangeProperty);
}
public static void SetIsFirstValueChange(FrameworkElement obj, bool value)
{
obj.SetValue(IsFirstValueChangeProperty, value);
}
public static readonly DependencyProperty IsFirstValueChangeProperty =
DependencyProperty.RegisterAttached("IsFirstValueChange", typeof(bool), typeof(AfterLoadBehavior),
new PropertyMetadata(true));
#endregion
}
使用这个,你需要像这样修改你的风格:
<Style TargetType="DataGridCell" x:Key="FlashStyle">
<Setter Property="local:AfterLoadBehavior.RaiseTargetUpdatedAfterLoadEvent" Value="True" />
<Style.Triggers>
<EventTrigger RoutedEvent="{x:Static local:AfterLoadBehavior.TargetUpdatedAfterLoadEvent}">
<BeginStoryboard>
<Storyboard x:Name="Blink" AutoReverse="True">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="00:00:01" Value="Red" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
此行为的作用是注册Binding.TargetUpdated 事件并在第一次调用时忽略它。其他时候,它会引发新创建的TargetUpdatedAfterLoadEvent,由您的EventTrigger 处理。
结果证明它比我最初预期的要复杂一些,但是这里并没有发生什么疯狂的事情,一旦你将这个行为添加到你的代码中,它就非常容易使用。
希望这会有所帮助。
原始答案(不起作用)
我不知道有一个简单的仅限 XAML 的解决方案,但您可以编写一个附加属性,该属性将注册到 DataGridCell 的 Loaded 事件,并且仅在加载后添加事件触发器。