在XAML中将静态方法/函数绑定到Func<T>属性

10

我正在尝试使用XAML创建一个对象树,其中一个节点看起来像这样:

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; }

}

我的目标是尽可能使XAML和代码干净整洁,但现在我为每个函数创建了包装器属性,这并不是最佳实践:

public static Func<bool> Func1 { get { return Method1; } }

public static bool Method1()
{
    //Do stuff here
    return true;
}

对于上述代码,XAML代码如下:

<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>
我想知道是否有一种快捷简便的方法将方法/函数绑定到Func属性,我所说的是这里的方法而不是执行的方法/函数的返回值。(我可以考虑在valueConverter或ExecuteMethod节点/类中使用一些反射魔法,但那只会让人感觉很肮脏和奇怪) 这是我想要XAML看起来的样子的一个示例:
<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>

非常感谢您的帮助,提前致歉我的英语语法不好,这不是我的母语 :)

2个回答

9
感谢jbtule!
如果有人需要解决方案,这里是它:
[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
}

7
我可以想到几种方法使它看起来更干净,但你所要求的没有绑定语法。我猜你最满意的可能是编写自己的标记扩展, 这样你就可以让它看起来像{d:StaticMethod Program.Method1},但你肯定要使用反射,但缓存是微不足道的,而且比值转换器更好看。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接