Binding of static method/function to Func<T> property in XAML
I'm working on using XAML to create an object tree and one of the nodes looks like this:
public class ExecuteMethod : INode
{
#region Implementation of INode
public bool Evaluate()
{
return Function != null && Function();
}
public string Name { get; set; }
private string _type;
public string Type
{
get
{
if (string.IsNullOrEmpty(_type))
{
_type = GetType().Name;
}
return _type;
}
}
#endregion
public Func<bool> Function { get; set; }
}
My goal is essential to make the XAML and code behind as clean as possible which isn't the case right now where I'm creating 开发者_Go百科wrapper properties for every function:
public static Func<bool> Func1 { get { return Method1; } }
public static bool Method1()
{
//Do stuff here
return true;
}
and the xaml looks like this for the above code:
<Root
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="clr-namespace:XamlBT;assembly=XamlBT"
xmlns:d="clr-namespace:TestBT;assembly=TestBT">
<Root.Child>
<Sequence Name="sequence1" >
<ExecuteMethod Name="e1.1" Function="{x:Static d:Program.Func1}" />
<Selector Name="selector1" >
<ExecuteMethod Name="e2.1" Function="{x:Static d:Program.Func1}" />
</Selector>
</Sequence>
</Root.Child>
I would like to know if there's a quick and easy way to bind methods/functions to the Func property, I'm talking about the method here NOT the value of the executed method/function. (I can think of using some reflection magic in a valueConverter or inside the ExecuteMethod node/class but that just feels dirty and weird) An example of how I'd like the XAML to look:
<Root
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="clr-namespace:XamlBT;assembly=XamlBT"
xmlns:d="clr-namespace:TestBT;assembly=TestBT">
<Root.Child>
<Sequence Name="sequence1" >
<ExecuteMethod Name="e1.1" Function="{x:Static d:Program.Method1}" />
<Selector Name="selector1" >
<ExecuteMethod Name="e2.1" Function="{x:Static d:Program.Method1}" />
</Selector>
</Sequence>
</Root.Child>
Thanks for any help in advance and sorry for the bad English grammar, it's not my native language :)
Thanks jbtule!
here's the solution if anyone wants it:
[MarkupExtensionReturnType(typeof (Func<bool>))]
public class StaticMethodExtension : MarkupExtension
{
public StaticMethodExtension(string method)
{
Method = method;
}
[ConstructorArgument("method")]
public string Method { get; set; }
private Func<bool> _func;
#region Overrides of MarkupExtension
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (_func == null)
{
int index = Method.IndexOf('.');
if (index < 0)
{
throw new ArgumentException("MarkupExtensionBadStatic");
}
string qualifiedTypeName = this.Method.Substring(0, index);
if (qualifiedTypeName == string.Empty)
{
throw new ArgumentException("MarkupExtensionBadStatic");
}
IXamlTypeResolver service = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
if (service == null)
{
throw new ArgumentException("MarkupExtensionNoContext");
}
var memberType = service.Resolve(qualifiedTypeName);
var str = this.Method.Substring(index + 1, (this.Method.Length - index) - 1);
if (str == string.Empty)
{
throw new ArgumentException("MarkupExtensionBadStatic");
}
var reflectedFunc = memberType.GetMethod(str,
BindingFlags.FlattenHierarchy | BindingFlags.Public |
BindingFlags.Static);
if (reflectedFunc != null)
{
if (reflectedFunc.ReturnType == typeof(bool))
{
var v = Delegate.CreateDelegate(typeof(Func<bool>), reflectedFunc, true);
_func = (Func<bool>) v;
}
}
}
return _func;
}
#endregion
}
I can think of couple ways to make it look cleaner but there isn't a binding syntax for what you are asking. I'm guessing what you would be most happy with would be writing your own markup extension so you could make it look like {d:StaticMethod Program.Method1}
, but you would definitely have to use reflection, but it would be trivial to cache and would look better than a value converter.
精彩评论