CallMethodAction
只能用於調用任一不帶參數或有兩個參數的方法,其中第一個參數是對象類型和的方法第二個可以被分配給一個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; }
}
}
}
然後,您可以正常使用它在您的XAML像你這樣的CallMethodAction
。您只需要引入適當的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
猜測)。如果這不合適,那麼您需要根據需要調整綁定。
我會試試這個。我將不得不做另一個可以調用Remove的方法......但是我可能找到了另一種使用我尚未測試過的數據綁定的更好方法......但這似乎與我想要的最接近。 – Will
我的第一個選擇將不起作用。但是,我敢肯定,這將是。我想創建另一個帳戶只是爲了再次提出這個答案。 – Will