Programmatically Call WPF TargetedTriggerAction

风流意气都作罢 提交于 2019-12-22 08:40:54

问题


I have a TargetedTriggerAction from a 3rd party library that would like to call/invoke without attaching it to a button. I have no problem getting it to work with the button, but I want to do it in response to some non-UI event.

Here is the action's class declaration:

 public class MeasureAction : TargetedTriggerAction<Map>

Here is my setup code so far:

    var measure = new MeasureAction();
    measure.TargetObject = _mapControl;
    measure.MeasureMode = MeasureAction.Mode.Polyline;
    measure.MapUnits = DistanceUnit.Miles;

I want to be able to do something like this, but I know Invoke is protected:

measure.Invoke();

回答1:


To invoke your trigger action, you need a trigger!

namespace TriggerTest
{
    using System.Windows;

    /// <summary>
    /// A trigger that may be invoked from code.
    /// </summary>
    public class ManualTrigger : System.Windows.Interactivity.TriggerBase<DependencyObject>
    {
        /// <summary>
        /// Invokes the trigger's actions.
        /// </summary>
        /// <param name="parameter">The parameter value.</param>
        public void Invoke(object parameter)
        {
            this.InvokeActions(parameter);
        }
    }
}

The above is a trigger implementation that may be invoked without any UI dependencies. For example:

var measure = new MeasureAction();
measure.TargetObject = _mapControl;
measure.MeasureMode = MeasureAction.Mode.Polyline;
measure.MapUnits = DistanceUnit.Miles; 

ManualTrigger trigger = new ManualTrigger();
trigger.Actions.Add(measure);
trigger.Invoke(null);

To make calling this even easier, you could add an extension method to TriggerAction.

namespace TriggerTest
{
    using System.Windows.Interactivity;

    /// <summary>
    /// Allows a trigger action to be invoked from code.
    /// </summary>
    public static class TriggerActionExtensions
    {
        /// <summary>
        /// Invokes a <see cref="TriggerAction"/> with the specified parameter.
        /// </summary>
        /// <param name="action">The <see cref="TriggerAction"/>.</param>
        /// <param name="parameter">The parameter value.</param>
        public static void Invoke(this TriggerAction action, object parameter)
        {
            ManualTrigger trigger = new ManualTrigger();
            trigger.Actions.Add(action);

            try
            {
                trigger.Invoke(parameter);
            }
            finally
            {
                trigger.Actions.Remove(action);
            }
        }

        /// <summary>
        /// Invokes a <see cref="TriggerAction"/>.
        /// </summary>
        /// <param name="action">The <see cref="TriggerAction"/>.</param>
        public static void Invoke(this TriggerAction action)
        {
            action.Invoke(null);
        }
    }
}

Now you can write what you really wanted:

var measure = new MeasureAction();
measure.TargetObject = _mapControl;
measure.MeasureMode = MeasureAction.Mode.Polyline;
measure.MapUnits = DistanceUnit.Miles; 
measure.Invoke();



回答2:


Is the 3rd party class sealed?

If not, the "best" answer would probably be to derive your own class from MeasureAction and add a invoker (keep it internal/protected if you want to keep things clean).

If it's sealed/otherwise frozen, your best bet is probably Reflection - there are ways to cache/otherwise speed up the cost of this call, but the basic code would be something like:

// Paste in the code in the original question here, name of instance == measure
var actionMethod = typeof(MeasureAction)
    .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
    .FirstOrDefault(meth => meth.Name == "Invoke");
if(actionMethod != null)
{
    var result = actionMethod.Invoke(measure, null);
}



回答3:


Old post but may help. I did like this

public class MyMeasureAction : MeasureAction
{
    public void Execute()
    {
        OnTargetChanged(null, (Map)TargetObject);
        Invoke(null);
    }
}

...

var mymeasure = new MyMeasureAction();
mymeasure.TargetObject = MyMap;
mymeasure.xxxx = xxxx
....
mymeasure.Execute();

The OnTargetChanged() method will initialize the internal Map of the MeasureAction



来源:https://stackoverflow.com/questions/12843674/programmatically-call-wpf-targetedtriggeraction

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!