WPF 绑定到带有列表视图列参数的方法的结果

WPF binding to result of method with parameter for listview column

我正在使用 C#、WPF、.NET Standard,Visual Studio。所有最新或几乎最新的版本。

这是我的数据上下文模型(在名为 ProgrammingManagerAPI 的独立库中创建):

public class MainModel
{
    public List<Project> Projects { get; set; }
    ...
}

其中包含这样定义的项目类型的对象列表(也在单独的库 ProgrammingManagerAPI 中,在目录模型中)、一些属性和一些方法:

public class Project
{
    public int Id { get; set; }
    ...
    public TimeSpan? TotalWorkedTime(bool subtasksIncluded = true)
    {
        if (Id < 0)
            return null;
        else 
            return new TimeSpan(...);
    }
    ...
}

在 mainWindow 中我有一个 ListView,我想用它来列出项目及其属性。
我有很多属性和一些方法,它们根据布尔参数返回值。

我读到在这种情况下我应该使用 ObjectDataProvider,所以我尝试如下:

xmlns:s="clr-namespace:System;assembly=mscorlib" 
xmlns:API.Models="clr-namespace:ProgrammingManagerAPI.Models;assembly=ProgrammingManagerAPI"

<Window.Resources>
    <ObjectDataProvider x:Key="yourStaticData"
            ObjectType="{x:Type API.Models:Project}"
            MethodName="TotalWorkedTime" >
        <ObjectDataProvider.MethodParameters>
            <s:Boolean>false</s:Boolean>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

 <Grid Grid.Row="1" Grid.Column="0" Margin="10">
     <ListView Margin="10" ItemsSource="{Binding Projects}" HorizontalAlignment="Center" HorizontalContentAlignment="Center">
         <ListView.View>
             <GridView>
                <GridViewColumn HeaderContainerStyle="{StaticResource ListViewStyle}" Header="Id" DisplayMemberBinding="{Binding Id}" />
                <GridViewColumn HeaderContainerStyle="{StaticResource ListViewStyle}" Header="TotalWorkedTime" DisplayMemberBinding="{Binding Path=., Source={StaticResource yourStaticData}}" />
             </GridView>
         </ListView.View>
     </ListView>
 </Grid>

对函数 TotalWorkedTime 的调用被触发,因为命中断点。但是被击中一次,而我已经创建了 4 个对象进行测试。 此外,它像静态函数一样被命中,不像其他属性那样针对对象的每个实例。在立即 window 中,我试图查看其他属性是什么,那些是空值。当 Id 列被点击时,所有属性都可用于项目的每个实例。 此外,我观察到它在调用 Id 属性 getter 之前被命中。

我试过很多版本,比如没有路径,有绑定等等很多其他方式。

谁能指出我的错误?

ObjectDataProvider 当您有一个要绑定的对象实例(或静态 class),但您使用的是 ItemsControl (ListView), 这让事情变得有点复杂。

你需要的是 IValueConverter。这需要一个对象,并通过调用一个函数并返回结果 "converts" 它。老实说,我希望能够通过谷歌搜索找到一个,但我没能找到。我想我迟早会用到这样的东西,所以我继续做了一个。这支持任何类型的对象,任何函数名称采用任意数量的参数。

    public class FunctionConverter : IValueConverter
    {
        public string FunctionName { get; set; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value.GetType().GetMethod(FunctionName).Invoke(value, (object[])parameter);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Binding.DoNothing;
        }
    }

下面是您可以如何使用它的示例:

MainWindow.xaml.cs:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            TestInstance = new Test();
            InitializeComponent();
        }

        public Test TestInstance { get; set; }

    }

    public class Test
    {
        public string Foo(string bar)
        {
            return bar;
        }
    }

MainWindow.xaml:

    <Grid>
        <Grid.Resources>
            <KHS:FunctionConverter x:Key="FuncCon" FunctionName="Foo"/>
        </Grid.Resources>

        <TextBlock>
            <TextBlock.Text>
                <Binding Path="TestInstance" Converter="{StaticResource FuncCon}">
                    <Binding.ConverterParameter>
                        <x:Array Type="sys:Object">
                            <sys:String>Hello World</sys:String>
                        </x:Array>
                    </Binding.ConverterParameter>
                </Binding>
            </TextBlock.Text>
        </TextBlock>
    </Grid>

您将转换器声明为资源,就像您对 ObjectDataProvider 所做的那样,并将 FunctionName 设置为您要调用的函数的名称。然后转换器使用 MethodInfo.Invoke(Object, Object[]) 到 运行 该函数和 returns 结果。

您通过绑定的 ConverterParameter 属性 为函数传递参数,这样您就可以为列表中的不同项目传递不同的值。在示例中,我将字符串 "Hello World" 传递给函数 Foo,这正是传递的 returns。

最后几点说明:此转换器只能以一种方式工作。提供的转换器不检查 null 并且在未找到 FunctionName 时没有适当的处理。使用这样的绑定不允许像依赖项 属性 那样提供更新通知。