你如何绑定到物体的方法在这种情况下在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
需要一个静态方法,或者它会创建它自己的实例,并使用了。
例如,使用马特的答案,我得到:
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.