绑定到 WPF 中的方法?

Posted

技术标签:

【中文标题】绑定到 WPF 中的方法?【英文标题】:Bind to a method in WPF? 【发布时间】:2010-10-04 20:58:03 【问题描述】:

在这种情况下,如何在 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>

这里我想在树的每个RootObject 上绑定GetChildren 方法。

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

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

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

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

【问题讨论】:

是的,你是对的。 ObjectDataProvider 确实有一个 ObjectInstance 属性(在特定实例上调用它的方法),但我不认为它是一个依赖属性,所以你不能绑定它(AFAIK)。 是的,我尝试绑定到 ObjectInstance,发现它不是依赖属性。 无论如何我都会把我的答案留在那里,既可以为您的更新提供一些背景信息,也可以帮助其他发现此问题的人遇到足够类似的问题。 你真的需要绑定到ObjectInstance吗? (它会改变)假设您可以创建自己的更改事件处理并在代码中更新 ObjectDataProvider... 刚刚用一些源代码更新了我的答案,一年后。 【参考方案1】:

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

【讨论】:

嗯,...似乎是一个黑客,但我开始认为这可能是唯一的方法。这该死的肯定会是最简单的!【参考方案2】:

不确定它在您的场景中效果如何,但您可以使用ObjectDataProvider 上的MethodName 属性让它调用特定方法(带有您MethodParameters 属性的特定参数)来检索其数据。

这是直接取自 MSDN 页面的 sn-p:

<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 方法,传递两个参数(0TempType.Celsius)。

【讨论】:

【参考方案3】:

你必须绑定到方法吗?

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

public ObservableCollection<ChildObject> Children

   get
   
      return GetChildren();
   

【讨论】:

我认为 Cameron 的评论意味着他正在绑定到一个他无法添加属性的类型。 你应该避免绑定到调用方法的属性,尤其是如果方法可能长时间运行。拥有它属性的这些方法并不是一个好的设计,因为代码的使用者期望一个属性只能访问一个局部变量。 @markmnl 那么直接绑定到函数有什么意义呢?所以OP的问题对你的情况没有任何意义?【参考方案4】:

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

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

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

ICustomTypeDescriptorTypeDescriptionProvider 类型可以让您实现您想要的。根据this article:

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

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

【讨论】:

【参考方案7】:

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

【讨论】:

以上是关于绑定到 WPF 中的方法?的主要内容,如果未能解决你的问题,请参考以下文章

wpf datatrigger绑定到方法

在 C# 中将 WPF 属性绑定到 ApplicationSettings 的最佳方法?

WPF 触发器绑定:将枚举值绑定到可见性的最佳方法是啥?

WPF将单个文本框绑定到集合对象或数组中的元素

WPF。查找绑定到特定属性的控件

WPF DataGrid绑定到数据源的方法