静态方法/函数绑定到XAML中的Func <t>属性</t>

时间:2011-02-28 20:03:19

标签: wpf xaml data-binding c#-4.0 binding

我正在使用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 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:5)

我可以想出几种方法让它看起来更干净但是没有一个绑定语法来解决你的问题。我猜你最满意的是writing your own markup extension,所以你可以让它看起来像{d:StaticMethod Program.Method1},但你肯定要使用反射,但是缓存并看起来很简单比价值转换器更好。