Привязка WPF к результату метода с параметром для столбца списка просмотра - PullRequest
0 голосов
/ 12 января 2020

Я использую C#, WPF,. NET Standard, Visual Studio. Все последние или почти самые последние версии.

Это моя модель datacontext (которая создается в отдельной библиотеке под названием 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, который я хочу использовать для вывода списка проектов со своими свойствами.
I У меня много свойств и некоторые методы, которые возвращают значение в зависимости от логического параметра.

Я прочитал, что в этом случае я должен использовать 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 объекта для теста. Более того, он срабатывает как функция stati c, не для каждого экземпляра объекта, как другие свойства . В ближайшем окне я пытаюсь увидеть, каковы другие свойства, и это пустые. Пока столбец для идентификатора находится в нажатом состоянии, все свойства доступны для каждого экземпляра проекта. Более того, я заметил, что он срабатывает до вызова метода получения свойства Id.

Я пробовал много версий, например, без Path, в Binding и многих других.

Каждый может указать мне моя ошибка?

1 Ответ

0 голосов
/ 13 января 2020

ObjectDataProvider полезен, когда у вас есть один экземпляр объекта (или класс * stati c), к которому вы хотите привязаться, но вы используете ItemsControl (ListView), который делает вещи немного сложнее.

Вам нужен IValueConverter. Это берет объект и «конвертирует» его, вызывая функцию и возвращая результат. Честно говоря, я ожидал, что смогу найти его с помощью Google, но не смог. Я подумал, что рано или поздно смогу использовать что-то подобное, поэтому я решил создать его. Это поддерживает любой тип объекта с любым именем функции, принимающим любое количество параметров.

    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 не найден. Использование такой привязки не позволяет получать уведомления об обновлениях, как это обеспечивает свойство зависимости.

...