绑定WPF中的一种方法? [英] Bind to a method in WPF?

查看:123
本文介绍了绑定WPF中的一种方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  public class RootObject 
{
public string Name {get; }

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

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

XAML:

 < TreeView ItemsSource =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 似乎不起作用,因为我绑定到一个项目列表,而$ code> ObjectDataProvider 需要静态方法,或者它创建它自己的实例并使用它。



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


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



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



解决方案

另一种可能适用于您的方法是创建一个自定义的 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)
返回值;
var methodInfo = value.GetType()。GetMethod(methodName,new Type [0]);
if(methodInfo == null)
返回值;
return methodInfo.Invoke(value,new object [0]);
}

public object ConvertBack(object value,Type targetType,object parameter,CultureInfo culture)
{
throw new NotSupportedException(MethodToValueConverter只能用于一个方式转换);
}
}

相应的单元测试:

  [测试] 
public void Convert()
{
var converter =新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 参数。


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.

这篇关于绑定WPF中的一种方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆