.net 绑定到 WPF 中的方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/502250/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 11:08:26  来源:igfitidea点击:

Bind to a method in WPF?

.netwpfdata-bindingxaml

提问by Cameron MacFarland

How do you bind to an objects method in this scenario in WPF?

在这种情况下,你如何绑定到 WPF 中的对象方法?

public class RootObject
{
    public string Name { get; }

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

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

XAML:

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 GetChildrenmethod on each RootObjectof the tree.

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

EDITBinding to an ObjectDataProviderdoesn't seem to work because I'm binding to a list of items, and the ObjectDataProviderneeds either a static method, or it creates it's own instance and uses that.

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

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.

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

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

回答by Drew Noakes

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

另一种可能对您IValueConverter有用的方法是创建一个将方法名称作为参数的自定义,以便像这样使用它:

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 targetTypeparameter.

请注意,此转换器不强制执行该targetType参数。

回答by Matt Hamilton

Not sure how well it will work in your scenario, but you can use the MethodNameproperty on ObjectDataProviderto have it call a specific method (with specific parameters of you MethodParametersproperty) to retrieve its data.

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

Here's a snippet taken directly from the MSDN page:

这是直接取自 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>

So that's an ObjectDataProviderthat's calling a ConvertTempmethod on an instance of a TemperatureScaleclass, passing two parameters (0and TempType.Celsius).

所以这是在类的实例ObjectDataProvider上调用ConvertTemp方法TemperatureScale,传递两个参数(0TempType.Celsius)。

回答by Michael Prewecki

Do you have to bind to the method?

你必须绑定到方法吗?

Can you bind to a property who's getter is the method?

你能绑定到一个属性上,getter 是方法吗?

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

回答by Nir

Unless you can add a property to call the method (or create a wrapper class that adds that property) the only way I know of is using a ValueConverter.

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

回答by Graham Ambrose

ObjectDataProvider also has an ObjectInstance property that can be used instead of ObjectType

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

回答by Drew Noakes

You can use System.ComponentModelto define properties for a type dynamically (they're not part of the compiled metadata). I used this approach in WPF to enable binding to a type that stored its values in fields, as binding to fields is not possible.

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

The ICustomTypeDescriptorand TypeDescriptionProvidertypes might allow you to achieve what you want. According to this article:

ICustomTypeDescriptorTypeDescriptionProvider类型可能让你实现你想要的。根据这篇文章

TypeDescriptionProviderallows you to write a separate class that implements ICustomTypeDescriptorand then to register this class as the provider of descriptions for other types.

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

I haven't tried this approach myself, but I hope it's helpful in your case.

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

回答by Austin_Anderson

To bind to an object's method in your WPF scenario, you can bind to a property that returns a delegate.

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