是否可以将CallMethodAction与参数交互使用?

时间:2016-02-12 15:06:59

标签: wpf xaml blend

鉴于以下内容:

en_GB

有没有办法可以将GBP1.12作为参数传递给方法调用£1.12

2 个答案:

答案 0 :(得分:2)

CallMethodAction只能用于调用不带参数的方法或带有两个参数的方法,其中第一个参数是object类型,第二个参数可以赋值给EventArgs类型的变量。

鉴于此,您将无法使用CallMethodAction执行所需操作。但是,您可以创建自己的触发器操作,该操作将调用您的方法并传入您指定的值。我对此只进行了一些轻量级测试,但它应该非常接近你所需要的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Interactivity;

namespace LocalActions
{
    public class CallUnaryMethodAction : TargetedTriggerAction<DependencyObject>
    {
        // The name of the method to invoke.
        public static readonly DependencyProperty MethodNameProperty =
            DependencyProperty.Register( "MethodName",
                typeof( string ),
                typeof( CallUnaryMethodAction ),
                new PropertyMetadata( OnNeedsMethodInfoUpdated ) );

        public string MethodName
        {
            get { return (string)GetValue( MethodNameProperty ); }
            set { SetValue( MethodNameProperty, value ); }
        }

        // Flag that lets us determine if we want to search non-public methods in our target object.
        public static readonly DependencyProperty AllowNonPublicMethodsProperty =
            DependencyProperty.Register( "AllowNonPublicMethods",
                typeof( bool ),
                typeof( CallUnaryMethodAction ),
                new PropertyMetadata( OnNeedsMethodInfoUpdated ) );

        public bool AllowNonPublicMethods
        {
            get { return (bool)GetValue( AllowNonPublicMethodsProperty ); }
            set { SetValue( AllowNonPublicMethodsProperty, value ); }
        }

        // Parameter we want to pass to our method. If this has not been set, then the value passed
        // to the trigger action's Invoke method will be used instead.
        public static readonly DependencyProperty ParameterProperty =
            DependencyProperty.Register( "Parameter",
                typeof( object ),
                typeof( CallUnaryMethodAction ) );

        public object Parameter
        {
            get { return GetValue( ParameterProperty ); }
            set { SetValue( ParameterProperty, value ); }
        }

        private static void OnNeedsMethodInfoUpdated( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var action = d as CallUnaryMethodAction;
            if( action != null )
                action.UpdateMethodInfo();
        }

        protected override void OnAttached()
        {
            UpdateMethodInfo();
        }

        protected override void OnTargetChanged( DependencyObject oldTarget, DependencyObject newTarget )
        {
            UpdateMethodInfo();
        }

        protected override void Invoke( object parameter )
        {
            object target = this.TargetObject ?? this.AssociatedObject;
            if( target == null )
                return;

            // Determine what we are going to pass to our method.
            object methodParam = ReadLocalValue( ParameterProperty ) == DependencyProperty.UnsetValue ?
                parameter : this.Parameter;

            // Pick the best method to call given the parameter we want to pass.
            Method methodToCall = m_methods.FirstOrDefault( method =>
                (methodParam != null) && method.ParameterInfo.ParameterType.IsAssignableFrom( methodParam.GetType() ) );

            if( methodToCall == null )
                throw new InvalidOperationException( "No suitable method found." );

            methodToCall.MethodInfo.Invoke( target, new object[] { methodParam } );
        }

        private void UpdateMethodInfo()
        {
            m_methods.Clear();
            object target = this.TargetObject ?? this.AssociatedObject;
            if( target == null || string.IsNullOrEmpty( this.MethodName ) )
                return;

            // Find all unary methods with the given name.
            BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
            if( this.AllowNonPublicMethods )
                flags |= BindingFlags.NonPublic;

            foreach( MethodInfo methodInfo in target.GetType().GetMethods( flags ) )
            {
                if( methodInfo.Name == this.MethodName )
                {
                    ParameterInfo[] parameters = methodInfo.GetParameters();
                    if( parameters.Length == 1 )
                        m_methods.Add( new Method( methodInfo, parameters[0] ) );
                }
            }

            // Order the methods so that methods with most derived parameters are ordered first.
            // This will help us pick the most appropriate method in the call to Invoke.
            m_methods = m_methods.OrderByDescending<Method, int>( method =>
            {
                int rank = 0;
                for( Type type = method.ParameterInfo.ParameterType; type != typeof( object ); type = type.BaseType )
                    ++rank;
                return rank;
            } ).ToList<Method>();
        }

        private List<Method> m_methods = new List<Method>();

        // Holds info on the list of possible methods we can call.
        private class Method
        {
            public Method( MethodInfo methodInfo, ParameterInfo paramInfo )
            {
                this.MethodInfo = methodInfo;
                this.ParameterInfo = paramInfo;
            }

            public MethodInfo MethodInfo { get; private set; }
            public ParameterInfo ParameterInfo { get; private set; }
        }
    }
}

然后,您可以像在CallMethodAction中一样在XAML中使用它。您只需要引入适当的XAML命名空间。

...
xmlns:local="clr-namespace:LocalActions"
...

<ei:DataTrigger
    Binding="{
        Binding SomeVar,
        ElementName=SomeElement,
        FallbackValue=False,
        Mode=OneWay}"
    Value="True">
    <local:CallUnaryMethodAction
        TargetObject="{
            Binding Mode=OneWay,
            Path=Children,
            Source={StaticResource Foo}}"
        MethodName="Add"
        Parameter="{StaticResource Bar}"/>
</ei:DataTrigger>

假设您的DoubleAnimationUsingKeyFrames确实是一种资源(我根据您对x:Key的使用而猜测)。如果这不合适,那么您需要根据需要调整绑定。

答案 1 :(得分:1)

您可以尝试使用Interactivity中的 InvokeCommandAction

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<ei:DataTrigger
        Binding="{
        Binding SomeVar,
        ElementName=SomeElement,
        FallbackValue=False,
        Mode=OneWay}"
    Value="True">
    <i:InvokeCommandAction Command="{Binding SomeCommand, Source={StaticResource SomeViewModel}}" CommandParameter="Bar"/>
</ei:DataTrigger>