绑定到WPF中的方法?


90

在这种情况下,如何在WPF中绑定到对象方法?

public class RootObject
{
    public string Name { get; }

    public ObservableCollection<ChildObject> GetChildren() {...}
}

public class ChildObject
{
    public string Name { get; }
}

XAML:

<TreeView ItemsSource="some list of RootObjects">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type data:RootObject}" 
                                  ItemsSource="???">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type data:ChildObject}">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

在这里,我想绑定到每棵树上的GetChildren方法RootObject

EDIT绑定到ObjectDataProvider似乎无效,因为我正在绑定到项目列表,并且ObjectDataProvider需要静态方法,或者它创建了自己的实例并使用该实例。

例如,使用马特的答案,我得到:

System.Windows.Data错误:33:ObjectDataProvider无法创建对象。Type ='RootObject'; 错误=“构造函数的参数错误。”

System.Windows.Data错误:34:ObjectDataProvider:尝试在类型上调用方法失败;方法='GetChildren'; Type ='RootObject'; 错误='无法在目标上调用指定的成员。TargetException:'System.Reflection.TargetException:非静态方法需要一个目标。


是啊,你说得对。ObjectDataProvider确实具有ObjectInstance属性(可以在特定实例上调用其方法),但是我不认为它是依赖项属性,因此您无法绑定它(AFAIK)。
马特·汉密尔顿,

1
是的,我尝试绑定到ObjectInstance并发现它不是依赖项属性。
卡梅伦·麦克法兰

无论如何,我都会把答案留在那里,既可以为您的更新提供一些背景信息,也可以帮助其他人找到与此问题足够相似的问题。
马特·汉密尔顿,

您实际上是否需要绑定到ObjectInstance?(它将更改)假设这样,您可以创建自己的更改事件处理并更新代码中的ObjectDataProvider ...
Tim Lovell-Smith 2010年

1
事实发生一年后,刚刚用一些源代码更新了我的答案。
德鲁·诺阿克斯

Answers:


71

另一种可能对您IValueConverter有用的方法是创建一个将方法名作为参数的自定义,以便将其像这样使用:

ItemsSource="{Binding 
    Converter={StaticResource MethodToValueConverter},
    ConverterParameter='GetChildren'}"

该转换器将使用反射找到并调用该方法。这要求该方法没有任何参数。

这是这种转换器的来源的示例:

public sealed class MethodToValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var methodName = parameter as string;
        if (value==null || methodName==null)
            return value;
        var methodInfo = value.GetType().GetMethod(methodName, new Type[0]);
        if (methodInfo==null)
            return value;
        return methodInfo.Invoke(value, new object[0]);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException("MethodToValueConverter can only be used for one way conversion.");
    }
}

并进行相应的单元测试:

[Test]
public void Convert()
{
    var converter = new MethodToValueConverter();
    Assert.AreEqual("1234", converter.Convert(1234, typeof(string), "ToString", null));
    Assert.AreEqual("ABCD", converter.Convert(" ABCD ", typeof(string), "Trim", null));

    Assert.IsNull(converter.Convert(null, typeof(string), "ToString", null));

    Assert.AreEqual("Pineapple", converter.Convert("Pineapple", typeof(string), "InvalidMethodName", null));
}

请注意,此转换器不强制执行该targetType参数。


6
嗯,...好像是黑客,但我开始认为这可能是唯一的方法。该死的肯定会最简单的!
八十一团结

25

不知道它在您的方案中将如何工作,但是您可以使用该MethodName属性ObjectDataProvider使它调用特定方法(具有您的特定参数)MethodParameters属性的)以检索其数据。

这是直接从MSDN页面获取的代码段:

<Window.Resources>
    <ObjectDataProvider ObjectType="{x:Type local:TemperatureScale}"
        MethodName="ConvertTemp" x:Key="convertTemp">
        <ObjectDataProvider.MethodParameters>
            <system:Double>0</system:Double>
            <local:TempType>Celsius</local:TempType>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

这就是在类的实例ObjectDataProvider上调用ConvertTemp方法TemperatureScale,并传递两个参数(0TempType.Celsius)。


10

您必须绑定该方法吗?

您可以绑定到使用方法是吸气剂的属性吗?

public ObservableCollection<ChildObject> Children
{
   get
   {
      return GetChildren();
   }
}

2
我认为Cameron的评论意味着他绑定到一种他不能添加属性的类型。
Drew Noakes

2
如果方法可能长时间运行,则应避免绑定到调用方法esp的属性。拥有这种方法,它的属性并不是一个好的设计,因为代码使用者希望该属性仅访问局部变量。
markmnl 2010年

@markmnl那么直接绑定到函数的意义是什么?因此,OP的问题对您的情况没有任何意义?
Teoman shipahi 2015年

4

除非您可以添加属性来调用该方法(或创建添加该属性的包装器类),否则我所知道的唯一方法是使用ValueConverter。



3

您可以使用 System.ComponentModel动态定义类型的属性(它们不属于已编译的元数据)。我在WPF中使用此方法来启用对绑定到将其值存储在字段中的类型的绑定,因为不可能绑定到字段。

ICustomTypeDescriptorTypeDescriptionProvider类型可能让你实现你想要的。根据这篇文章

TypeDescriptionProvider允许您编写一个单独的类来实现ICustomTypeDescriptor,然后将该类注册为其他类型的描述的提供者。

我还没有尝试过这种方法,但是希望对您有帮助。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.