Setting a property with an EventTrigger Setting a property with an EventTrigger wpf wpf

Setting a property with an EventTrigger


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.


I modified Neutrino's solution to make the xaml look less verbose when specifying the value:

Sorry for no pictures of the rendered xaml, just imagine a [=] hamburger button that you click and it turns into [<-] a back button and also toggles the visibility of a Grid.

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"...<Grid>    <Button x:Name="optionsButton">        <i:Interaction.Triggers>            <i:EventTrigger EventName="Click">                <local:SetterAction PropertyName="Visibility" Value="Collapsed" />                <local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsBackButton}" Value="Visible" />                <local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsPanel}" Value="Visible" />            </i:EventTrigger>        </i:Interaction.Triggers>        <glyphs:Hamburger Width="10" Height="10" />    </Button>    <Button x:Name="optionsBackButton" Visibility="Collapsed">        <i:Interaction.Triggers>            <i:EventTrigger EventName="Click">                <local:SetterAction PropertyName="Visibility" Value="Collapsed" />                <local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsButton}" Value="Visible" />                <local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsPanel}" Value="Collapsed" />            </i:EventTrigger>        </i:Interaction.Triggers>        <glyphs:Back Width="12" Height="11" />    </Button></Grid>...<Grid Grid.RowSpan="2" x:Name="optionsPanel" Visibility="Collapsed"></Grid>

You can also specify values this way like in Neutrino's solution:

<Button x:Name="optionsButton">    <i:Interaction.Triggers>        <i:EventTrigger EventName="Click">            <local:SetterAction PropertyName="Visibility" Value="{x:Static Visibility.Collapsed}" />            <local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsBackButton}" Value="{x:Static Visibility.Visible}" />            <local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsPanel}" Value="{x:Static Visibility.Visible}" />        </i:EventTrigger>    </i:Interaction.Triggers>    <glyphs:Hamburger Width="10" Height="10" /></Button>

And here's the code.

using System;using System.ComponentModel;using System.Reflection;using System.Windows;using System.Windows.Interactivity;namespace Mvvm.Actions{    /// <summary>    /// Sets a specified property to a value when invoked.    /// </summary>    public class SetterAction : TargetedTriggerAction<FrameworkElement>    {        #region Properties        #region PropertyName        /// <summary>        /// Property that is being set by this setter.        /// </summary>        public string PropertyName        {            get { return (string)GetValue(PropertyNameProperty); }            set { SetValue(PropertyNameProperty, value); }        }        public static readonly DependencyProperty PropertyNameProperty =            DependencyProperty.Register("PropertyName", typeof(string), typeof(SetterAction),            new PropertyMetadata(String.Empty));        #endregion        #region Value        /// <summary>        /// Property value that is being set by this setter.        /// </summary>        public object Value        {            get { return (object)GetValue(ValueProperty); }            set { SetValue(ValueProperty, value); }        }        public static readonly DependencyProperty ValueProperty =            DependencyProperty.Register("Value", typeof(object), typeof(SetterAction),            new PropertyMetadata(null));        #endregion        #endregion        #region Overrides        protected override void Invoke(object parameter)        {            var target = TargetObject ?? AssociatedObject;            var targetType = target.GetType();            var property = targetType.GetProperty(PropertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);            if (property == null)                throw new ArgumentException(String.Format("Property not found: {0}", PropertyName));            if (property.CanWrite == false)                throw new ArgumentException(String.Format("Property is not settable: {0}", PropertyName));            object convertedValue;            if (Value == null)                convertedValue = null;            else            {                var valueType = Value.GetType();                var propertyType = property.PropertyType;                if (valueType == propertyType)                    convertedValue = Value;                else                {                    var propertyConverter = TypeDescriptor.GetConverter(propertyType);                    if (propertyConverter.CanConvertFrom(valueType))                        convertedValue = propertyConverter.ConvertFrom(Value);                    else if (valueType.IsSubclassOf(propertyType))                        convertedValue = Value;                    else                        throw new ArgumentException(String.Format("Cannot convert type '{0}' to '{1}'.", valueType, propertyType));                }            }            property.SetValue(target, convertedValue);        }        #endregion    }}