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
时没有适当的处理。使用这样的绑定不允许像依赖项 属性 那样提供更新通知。
我正在使用 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
时没有适当的处理。使用这样的绑定不允许像依赖项 属性 那样提供更新通知。