绑定到WPF中的方法?

时间:2009-02-02 05:16:27

标签: .net wpf data-binding xaml

如何在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方法。

编辑绑定到ObjectDataProvider似乎不起作用,因为我绑定了一个项目列表,ObjectDataProvider需要一个静态方法,或者它创建了自己的实例并使用它。

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

  

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

     

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

7 个答案:

答案 0 :(得分:64)

另一种可能对您有用的方法是创建一个自定义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参数。

答案 1 :(得分:24)

不确定它在您的方案中的效果如何,但您可以使用ObjectDataProvider上的MethodName属性让它调用特定方法(如果您使用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,它在“TemperatureScale”类的实例上调用“ConvertTemp”方法,传递两个参数(0和TempType.Celsius)。

答案 2 :(得分:9)

你必须绑定到方法吗?

你能绑定一个getter是方法的属性吗?

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

答案 3 :(得分:4)

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

答案 4 :(得分:3)

ObjectDataProvider还有一个ObjectInstance属性,可以用来代替ObjectType

答案 5 :(得分:3)

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

ICustomTypeDescriptorTypeDescriptionProvider类型可能会让您实现您想要的效果。根据{{​​3}}:

  

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

我自己没有尝试过这种方法,但我希望它对你的情况有帮助。

答案 6 :(得分:0)

要绑定到WPF场景中的对象方法,可以绑定到返回委托的属性。