I want to be able to set a property with an EventTrigger, there's a number of problems with this.
1) EventTriggers only support Actions, so I must use a storyBoard to set my properties.
2) Once I use a storyboard, I have two options:
In the below example, I want to set the IsChecked property to False when the button is clicked and I want the user to be able to change the IsChecked and/or I want to be able to change the property in code.
Example:
<EventTrigger SourceName="myButton" RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetName="myCheckBox" Storyboard.TargetProperty="IsChecked" FillBehavior="Stop"> <DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False" /> </BooleanAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>
I realize that I can use the "Completed" event after the storyboard completes to set the value to False. However, in this instance I want to contain the logic within the XAML, as this logic will be used on a custom control and is only specific to the UI.
Just create your own action.
namespace WpfUtil { using System.Reflection; using System.Windows; using System.Windows.Interactivity; /// <summary> /// Sets the designated property to the supplied value. TargetObject /// optionally designates the object on which to set the property. If /// TargetObject is not supplied then the property is set on the object /// to which the trigger is attached. /// </summary> public class SetPropertyAction : TriggerAction<FrameworkElement> { // PropertyName DependencyProperty. /// <summary> /// The property to be executed in response to the trigger. /// </summary> public string PropertyName { get { return (string)GetValue(PropertyNameProperty); } set { SetValue(PropertyNameProperty, value); } } public static readonly DependencyProperty PropertyNameProperty = DependencyProperty.Register("PropertyName", typeof(string), typeof(SetPropertyAction)); // PropertyValue DependencyProperty. /// <summary> /// The value to set the property to. /// </summary> public object PropertyValue { get { return GetValue(PropertyValueProperty); } set { SetValue(PropertyValueProperty, value); } } public static readonly DependencyProperty PropertyValueProperty = DependencyProperty.Register("PropertyValue", typeof(object), typeof(SetPropertyAction)); // TargetObject DependencyProperty. /// <summary> /// Specifies the object upon which to set the property. /// </summary> public object TargetObject { get { return GetValue(TargetObjectProperty); } set { SetValue(TargetObjectProperty, value); } } public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register("TargetObject", typeof(object), typeof(SetPropertyAction)); // Private Implementation. protected override void Invoke(object parameter) { object target = TargetObject ?? AssociatedObject; PropertyInfo propertyInfo = target.GetType().GetProperty( PropertyName, BindingFlags.Instance|BindingFlags.Public |BindingFlags.NonPublic|BindingFlags.InvokeMethod); propertyInfo.SetValue(target, PropertyValue); } } }
In this case I'm binding to a property called DialogResult on my viewmodel.
<Grid> <Button> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <wpf:SetPropertyAction PropertyName="DialogResult" TargetObject="{Binding}" PropertyValue="{x:Static mvvm:DialogResult.Cancel}"/> </i:EventTrigger> </i:Interaction.Triggers> Cancel </Button> </Grid>
As much as I love XAML, for this kinds of tasks I switch to code behind. Attached behaviors are a good pattern for this. Keep in mind, Expression Blend 3 provides a standard way to program and use behaviors. There are a few existing ones on the Expression Community Site.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With