Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting a property with an EventTrigger

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:

  • Stop: Once the animation has stopped the value reverts back to before the animation started
  • HoldEnd: This locks the property, so that neither code, nor user interaction can change the property that the animation is holding.

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.

like image 908
Chris Nicol Avatar asked Jun 03 '09 00:06

Chris Nicol


2 Answers

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> 

like image 93
Neutrino Avatar answered Sep 28 '22 06:09

Neutrino


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.

like image 31
Sergey Aldoukhov Avatar answered Sep 28 '22 07:09

Sergey Aldoukhov