绑定到WPF的方法?绑定、方法、WPF

2023-09-02 10:17:33 作者:独波大侠°

你如何绑定到物体的方法在这种情况下在WPF?

公共类RootObject {     公共字符串名称{; }     公众的ObservableCollection< ChildObject>的GetChildren(){...} } 公共类ChildObject {     公共字符串名称{; } }

XAML:

 <&GT的TreeView的ItemsSource =的RootObjects一些名单;
    < TreeView.Resources>
        < HierarchicalDataTemplate数据类型={X:类型的数据:RootObject}
                                  的ItemsSource =???>
            < TextBlock的文本={绑定路径=名}/>
        < / HierarchicalDataTemplate>
        < HierarchicalDataTemplate数据类型={X:类型的数据:ChildObject}>
            < TextBlock的文本={绑定路径=名}/>
        < / HierarchicalDataTemplate>
    < /TreeView.Resources>
< /树视图>
 

在这里,我要绑定到每个 RootObject 树的的GetChildren 方法。

修改绑定到的ObjectDataProvider 似乎并没有工作,因为我结合项目的列表,以及的ObjectDataProvider 需要一个静态方法,或者它会创建它自己的实例,并使用了。

WPF 命令绑定的各种方式

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

  

System.Windows.Data错误:33:ObjectDataProvider的不能创建对象; TYPE ='RootObject';错误='错误的参数的构造函数。

     

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

解决方案

这可能为你工作的另一种方法是创建一个自定义的 的IValueConverter 接受一个方法名作为参数,所以,这将是像这样使用:

 的ItemsSource ={结合
    转换器= {的StaticResource MethodToValueConverter},
    ConverterParameter ='的GetChildren'}
 

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

下面是这样一个转换器的源代码的例子:

公共密封类MethodToValueConverter:的IValueConverter {     公共对象转换(对象的值,类型TARGETTYPE,对象参数,CultureInfo的文化)     {         VAR方法名=参数作为字符串;         如果(价值== NULL ||方法名== NULL)             返回值;         。VAR MethodInfo的= value.GetType()GetMethod的(方法名,新型的[0]);         如果(MethodInfo的== NULL)             返回值;         返回methodInfo.Invoke(价值,新的对象[0]​​);     }     公共对象ConvertBack(对象的值,类型TARGETTYPE,对象参数,CultureInfo的文化)     {         抛出新NotSupportedException异常(MethodToValueConverter只能用于一个单向转换。);     } }

和相应的单元测试:

[测试] 公共无效转换() {     VAR转换器=新MethodToValueConverter();     Assert.AreEqual(1234,converter.Convert(1234,typeof运算(字符串)的ToString,NULL));     Assert.AreEqual(ABCD,converter.Convert(ABCD的typeof(串),裁剪,NULL));     Assert.IsNull(converter.Convert(空的typeof(串)的ToString,NULL));     Assert.AreEqual(菠萝,converter.Convert(菠萝的typeof(串),InvalidMethodName,NULL)); }

请注意,此转换器不能执行 TARGETTYPE 参数。

How do you bind to an objects method in this scenario in 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>

Here I want to bind to the GetChildren method on each RootObject of the tree.

EDIT Binding to an ObjectDataProvider doesn't seem to work because I'm binding to a list of items, and the ObjectDataProvider needs either a static method, or it creates it's own instance and uses that.

For example, using Matt's answer I get:

System.Windows.Data Error: 33 : ObjectDataProvider cannot create object; Type='RootObject'; Error='Wrong parameters for constructor.'

System.Windows.Data Error: 34 : ObjectDataProvider: Failure trying to invoke method on type; Method='GetChildren'; Type='RootObject'; Error='The specified member cannot be invoked on target.' TargetException:'System.Reflection.TargetException: Non-static method requires a target.

解决方案

Another approach that might work for you is to create a custom IValueConverter that takes a method name as a parameter, so that it would be used like this:

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

This converter would find and invoke the method using reflection. This requires the method to not have any arguments.

Here's an example of such a converter's source:

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.");
    }
}

And a corresponding unit test:

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

Note that this converter does not enforce the targetType parameter.