Столбец WPF ListView с агрегированным значением и обратным порядком ProgreessBar - PullRequest
1 голос
/ 02 мая 2020

У меня есть ListView с колонками Price, Size и Total. Столбцы «Цена» и «Размер» являются привязками к элементам моего

public ObservableCollection<MyItem> Book { get; } = new ObservableCollection<MyItem>();

в ViewModel. Столбец итога должен суммировать размеры по разным ценам и содержать результат и индикатор выполнения, который изменяется до 100% по последнему пункту. Например:

Price,Size,Total

10,2,59 (progress bar 100%)

9,6,57 (progress bar 97%)

8,5,51 (progress bar 86%)

6,34,46 (progress bar 78%)

2,12,12 (progress bar 20%)

Цены заказаны и уникальны. Но проблема в том, что итоги должны начинаться снизу. Самая низкая цена, которая должна быть первым элементом при агрегировании, является последним элементом в ListView. Таким образом, агрегация должна использовать обратный порядок строк, которые я рассчитываю.

Если бы ListView агрегировался из первого элемента в ListView, то я мог бы использовать что-то вроде этого:

Пример:

Price,Size,Total

10,2,2 (progress bar 3%)

9,6,8 (progress bar 14%)

8,5,13 (progress bar 22%)

6,34,47 (progress bar 80%)

2,12,59 (progress bar 100%)
<local:SumQuantityConverter x:Key="SumQuantityConverter"/>
<DataTemplate DataType="{x:Type local:MyItem}" x:Key="MyItem.Template.ListView.Sum">
            <Grid>
                <ProgressBar x:Name="pBar" Opacity="0.3" Width="140"
                                             Minimum="0"
                                             Maximum="{Binding DataContext.Sum, ElementName=wind}">
                    <ProgressBar.Value>
                        <MultiBinding  Converter="{StaticResource SumQuantityConverter}">
                            <Binding ElementName="wind" Path="DataContext.Book" Mode="OneWay"/>
                            <Binding Path="Price" Mode="OneWay"/>
                            <Binding ElementName="wind" Path="DataContext.Sum" Mode="OneWay"/>
                        </MultiBinding>
                    </ProgressBar.Value>
                </ProgressBar>
                <TextBlock Text="{Binding Value, ElementName=pBar, Mode=OneWay}" />
            </Grid>
</DataTemplate>

и

<ListView ItemsSource="{Binding Book}">
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Price}" Header="Price" Width="50"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Quantity}" Header="Size" Width="60"/>
                    <GridViewColumn CellTemplate="{Binding Mode=OneWay, Source={StaticResource MyItem.Template.ListView.Sum}}" Header="Total" Width="140"/>
                </GridView>
            </ListView.View>
</ListView>

Конвертер:

public class SumQuantityConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(values?.Length > 2))
                return null;

            if (!(values[0] is IEnumerable<MyItem> book))
                return null;

            if (!(values[1] is long price))
                return null;

            double sum = (double)book.TakeWhile(ord => ord.Price >= price).Sum(ord => ord.Quantity);

            return sum;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Этот подход не работает, когда итоги должны начинаться с последнего элемента в ListView, потому что мы go из первого элемента ListView и не может вернуться к предыдущему элементу.

Не могли бы вы дать совет, как реализовать мою задачу?

1 Ответ

0 голосов
/ 02 мая 2020

Для обратного ProgressBar вы можете сделать следующее

(и я несколько упростил код)

public class SumQuantityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values?.Length > 2 && values[0] is IEnumerable<MyItem> book && values[1] is long price && values[2] is long sum)
        {
            double result = (double)book.TakeWhile(ord => ord.Price > price).Sum(ord => ord.Quantity);

            return sum - result;
        }
        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => null;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...