0

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

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

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

它具有像这样定义的 Project 类型的对象列表(也在单独的库 ProgrammingManagerAPI 中,在目录 Models 中),一些属性和一些方法:

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 个对象进行测试。此外,它像静态函数一样被命中,而不是像其他属性一样针对对象的每个实例。在即时窗口中,我试图查看其他属性是什么,那些是空值。当 Id 列被击中时,所有属性都可用于每个 Project 实例。此外,我观察到它在调用 Id 属性 getter 之前被击中。

我已经尝试了很多版本,比如没有路径、绑定和许多其他方式。

谁能指出我的错误?

4

1 回答 1

0

ObjectDataProvider当您有一个要绑定的对象(或静态类)的单个实例但您使用的是ItemsControl( ListView) 时,这很有用,这会使事情变得更复杂一些。

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

    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[])用于运行该函数并返回结果。

您可以通过绑定的ConverterParameter属性为函数传递参数,这将允许您为列表中的不同项目传递不同的值。在示例中,我将字符串传递"Hello World"给函数Foo,它只返回传递的内容。

最后几点说明:此转换器仅以一种方式工作。所提供的转换器不会检查null并且没有针对何时FunctionName找不到的处理。使用这样的绑定不允许像依赖属性提供的更新通知。

于 2020-01-13T05:48:22.963 回答