可以在EventTrigger中给出条件吗?我已经为单选按钮写了下面的EventTrigger (Mouse.MouseLeave)。我希望不应为处于选中状态(IsChecked=True)的项目触发此操作。
<EventTrigger RoutedEvent="Mouse.MouseLeave" SourceName="border">
<BeginStoryboard Name="out_BeginStoryboard" Storyboard="{StaticResource out}" />
<RemoveStoryboard BeginStoryboardName="over_BeginStoryboard" />
</EventTrigger>
请告诉我如何才能做到这一点?
提前谢谢。
发布于 2010-05-13 06:52:50
您不能以这种方式使用EventTrigger。调用EventTriggers的WPF的RoutedEventHandler没有提供任何机制来使触发器成为条件触发器,而且您不能通过将TriggerAction子类化来解决这个问题,因为没有要覆盖的受保护的Invoke()或Execute()操作。
但是,使用自定义类可以很容易地完成这一点。下面是它的用法:
<Border>
<my:ConditionalEventTrigger.Triggers>
<my:ConditionalEventTriggerCollection>
<my:ConditionalEventTrigger RoutedEvent="Mouse.MouseLeave"
Condition="{Binding IsChecked, ElementName=checkbox}">
<BeginStoryboard Name="out_BeginStoryboard" Storyboard="{StaticResource out}" />
<RemoveStoryboard BeginStoryboardName="over_BeginStoryboard" />
</my:ConditionalEventTrigger>
</my:ConditionalEventTriggerCollection>
</my:ConditionalEventTrigger.Triggers>
...
下面是它的实现方式:
[ContentProperty("Actions")]
public class ConditionalEventTrigger : FrameworkContentElement
{
public RoutedEvent RoutedEvent { get; set; }
public List<TriggerAction> Actions { get; set; }
// Condition
public bool Condition { get { return (bool)GetValue(ConditionProperty); } set { SetValue(ConditionProperty, value); } }
public static readonly DependencyProperty ConditionProperty = DependencyProperty.Register("Condition", typeof(bool), typeof(ConditionalEventTrigger));
// "Triggers" attached property
public static ConditionalEventTriggerCollection GetTriggers(DependencyObject obj) { return (ConditionalEventTriggerCollection)obj.GetValue(TriggersProperty); }
public static void SetTriggers(DependencyObject obj, ConditionalEventTriggerCollection value) { obj.SetValue(TriggersProperty, value); }
public static readonly DependencyProperty TriggersProperty = DependencyProperty.RegisterAttached("Triggers", typeof(ConditionalEventTriggerCollection), typeof(ConditionalEventTrigger), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
// When "Triggers" is set, register handlers for each trigger in the list
var element = (FrameworkElement)obj;
var triggers = (List<ConditionalEventTrigger>)e.NewValue;
foreach(var trigger in triggers)
element.AddHandler(trigger.RoutedEvent, new RoutedEventHandler((obj2, e2) =>
trigger.OnRoutedEvent(element)));
}
});
public ConditionalEventTrigger()
{
Actions = new List<TriggerAction>();
}
// When an event fires, check the condition and if it is true fire the actions
void OnRoutedEvent(FrameworkElement element)
{
DataContext = element.DataContext; // Allow data binding to access element properties
if(Condition)
{
// Construct an EventTrigger containing the actions, then trigger it
var dummyTrigger = new EventTrigger { RoutedEvent = _triggerActionsEvent };
foreach(var action in Actions)
dummyTrigger.Actions.Add(action);
element.Triggers.Add(dummyTrigger);
try
{
element.RaiseEvent(new RoutedEventArgs(_triggerActionsEvent));
}
finally
{
element.Triggers.Remove(dummyTrigger);
}
}
}
static RoutedEvent _triggerActionsEvent = EventManager.RegisterRoutedEvent("", RoutingStrategy.Direct, typeof(EventHandler), typeof(ConditionalEventTrigger));
}
// Create collection type visible to XAML - since it is attached we cannot construct it in code
public class ConditionalEventTriggerCollection : List<ConditionalEventTrigger> {}
享受吧!
发布于 2010-11-14 22:43:35
这就是对我有效的..。
我想要基于鼠标悬停在UI元素上并且UI元素的相关所有者处于活动状态(即启用以使玩家移动)来执行动画。
为了支持这些需求,我使用了相对源代码绑定来克服缺乏对事件触发条件的支持。
示例:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource self}, Path=IsMouseOver}" Value="True" />
<Condition Binding="{Binding Path=IsPlayer1Active}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.GradientStops[0].Color" To="#FF585454" Duration="0:0:.25"/>
<ColorAnimation Storyboard.TargetProperty="Background.GradientStops[1].Color" To="Black" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
发布于 2010-08-05 04:48:55
这是我修改过的Ray's answer版本,它只在设置了源触发器时创建和附加虚拟事件,而不是每次都这样做。我认为这对于我的场景会更好,因为我正在发起一个关于数百个项目的事件,而不仅仅是一两个:
[ContentProperty("Actions")]
public class ConditionalEventTrigger : FrameworkContentElement
{
static readonly RoutedEvent DummyEvent = EventManager.RegisterRoutedEvent(
"", RoutingStrategy.Direct, typeof(EventHandler), typeof(ConditionalEventTrigger));
public static readonly DependencyProperty TriggersProperty = DependencyProperty.RegisterAttached(
"Triggers", typeof(ConditionalEventTriggers), typeof(ConditionalEventTrigger),
new FrameworkPropertyMetadata(RefreshTriggers));
public static readonly DependencyProperty ConditionProperty = DependencyProperty.Register(
"Condition", typeof(bool), typeof(ConditionalEventTrigger)); // the Condition is evaluated whenever an event fires
public ConditionalEventTrigger()
{
Actions = new List<TriggerAction>();
}
public static ConditionalEventTriggers GetTriggers(DependencyObject obj)
{ return (ConditionalEventTriggers)obj.GetValue(TriggersProperty); }
public static void SetTriggers(DependencyObject obj, ConditionalEventTriggers value)
{ obj.SetValue(TriggersProperty, value); }
public bool Condition
{
get { return (bool)GetValue(ConditionProperty); }
set { SetValue(ConditionProperty, value); }
}
public RoutedEvent RoutedEvent { get; set; }
public List<TriggerAction> Actions { get; set; }
// --- impl ----
// we can't actually fire triggers because WPF won't let us (stupid sealed internal methods)
// so, for each trigger, make a dummy trigger (on a dummy event) with the same actions as the real trigger,
// then attach handlers for the dummy event
public static void RefreshTriggers(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var targetObj = (FrameworkElement)obj;
// start by clearing away the old triggers
foreach (var t in targetObj.Triggers.OfType<DummyEventTrigger>().ToArray())
targetObj.Triggers.Remove(t);
// create and add dummy triggers
foreach (var t in ConditionalEventTrigger.GetTriggers(targetObj))
{
t.DataContext = targetObj.DataContext; // set and Track DataContext so binding works
// targetObj.GetDataContextChanged().WeakSubscribe(dc => t.DataContext = targetObj.DataContext);
var dummyTrigger = new DummyEventTrigger { RoutedEvent = DummyEvent };
foreach (var action in t.Actions)
dummyTrigger.Actions.Add(action);
targetObj.Triggers.Add(dummyTrigger);
targetObj.AddHandler(t.RoutedEvent, new RoutedEventHandler((o, args) => {
if (t.Condition) // evaluate condition when the event gets fired
targetObj.RaiseEvent(new RoutedEventArgs(DummyEvent));
}));
}
}
class DummyEventTrigger : EventTrigger { }
}
public class ConditionalEventTriggers : List<ConditionalEventTrigger> { }
它的用法如下:
<Border>
<local:ConditionalEventTrigger.Triggers>
<local:ConditionalEventTriggers>
<local:ConditionalEventTrigger RoutedEvent="local:ClientEvents.Flash" Condition="{Binding IsFlashing}">
<BeginStoryboard Name="FlashAnimation">...
这条线
// targetObj.GetDataContextChanged().WeakSubscribe(dc => t.DataContext = targetObj.DataContext);
使用反应式框架和我编写的一些扩展方法,基本上我们需要订阅目标对象的.DataContextChanged
事件,但我们需要使用弱引用。如果您的对象从来不更改它们的datacontext,那么您根本就不需要这些代码
https://stackoverflow.com/questions/2764415
复制相似问题