Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 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 :)

like image 912
Simon Rasmussen Avatar asked Feb 28 '11 20:02

Simon Rasmussen


Video Answer


1 Answers

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
}
like image 193
Simon Rasmussen Avatar answered Sep 27 '22 19:09

Simon Rasmussen