Группировка WPF с использованием CollectionViewSource и DataBinding

Я привязываю CollectionViewSource к ListView для группировки элементов. Все отлично работает, за исключением случаев, когда я обновляю ObservableCollection, на котором основан CollectionViewSource. Если я обновляю значение объекта в коллекции, пользовательский интерфейс никогда не обновляется. Вот пример:

<ListView x:Name="MyListView" Margin="0,0,0,65">
    <ListView.GroupStyle>
        <GroupStyle>
            <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                    <Setter Property="Margin" Value="0,0,0,5"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                <Expander IsExpanded="true" BorderBrush="#FFA4B97F" BorderThickness="0,0,0,1">
                                    <Expander.Header>
                                        <DockPanel>
                                            <TextBlock FontWeight="Bold" Text="{Binding Name}" Margin="5,0,0,0" Width="80"/>
                                            <TextBlock FontWeight="Bold" Width="60" TextAlignment="Center" Margin="16,0,0,0" Text="{Binding Items, Converter={StaticResource Converter2}}" />
                                        </DockPanel>
                                    </Expander.Header>
                                    <ItemsPresenter />
                                </Expander>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GroupStyle.ContainerStyle>
        </GroupStyle>
    </ListView.GroupStyle>
    <ListView.View>
        <GridView>
            <GridViewColumn Width="300" Header="Amount" >
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Amount}" Margin="80,0,0,0"/>
                    </DataTemplate>
                 </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

Вы заметите, что он вызывает конвертер в группе и передает ему коллекцию элементов. Это делается для того, чтобы преобразователь мог вычислить среднее значение строк и вернуть этот результат:

public class AverageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        IEnumerable<object> rows = (IEnumerable<object>) value;
        double average = rows.Average(a => ((DisplayRow) a).Amount);
        return average;
    }

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

В коде позади я добавляю строки и создаю CollectionViewSource:

частная ObservableCollection только для чтения displayRows = new ObservableCollection();

public Window1()
{
    InitializeComponent();

    displayRows.Add(new DisplayRow { Title = "Sales", Amount=16} );
    displayRows.Add(new DisplayRow { Title = "Marketing", Amount=14} );
    displayRows.Add(new DisplayRow { Title = "Technology", Amount=13} );
    displayRows.Add(new DisplayRow { Title = "Sales", Amount=11} );
    displayRows.Add(new DisplayRow { Title = "Marketing", Amount=13} );
    displayRows.Add(new DisplayRow { Title = "Technology", Amount=12} );
    CollectionViewSource viewSource = new CollectionViewSource { Source = displayRows };
    viewSource.GroupDescriptions.Add(new PropertyGroupDescription("Title"));
    MyListView.ItemsSource = viewSource.View;
}

Объект DisplayRow реализует INotifyPropertyChanged и представляет собой простой класс.

Все работает хорошо, и отображение выглядит так, как я хочу, но если я изменю значение в ObservableCollection, пользовательский интерфейс не изменится.

Если я добавляю элемент в коллекцию, я вижу, как он появляется на экране, но преобразователь никогда не вызывается для пересчета среднего значения. Любые идеи?


person Kelly    schedule 22.10.2009    source источник


Ответы (3)


Я нашел способ обойти эту проблему.

private CollectionViewSource _viewSource;

private void ModifyData()
{
    // Modify some data

    // This will cause the ListView to refresh its data and update the UI
    // and also cause the converter to be called to reformat the data.
    _viewSource.View.Refresh();
}

Надеюсь, это поможет.

person Tri Q Tran    schedule 23.10.2009
comment
Хороший. Да, это помогает. К сожалению, мне нужно обновить все это, но, по крайней мере, это избавляет меня от этой проблемы. Спасибо. - person Kelly; 26.10.2009

Без обновления всего представления с этим все еще можно справиться, я это реализовал.

Создание привязок данных внутри CollectionView позволит получать уведомления об изменениях для групп.

Посетите http://stumblingaroundinwpf.blogspot.com/2009/11/building-smarter-wpf-collectionview-one.html

person Amir Burbea    schedule 23.11.2009

Если источником данных является ObservableCollection, представление будет обновляться всякий раз, когда коллекция изменяется, т. е. когда из нее добавляются или удаляются элементы. Если вы хотите, чтобы представление обновлялось при редактировании базовых данных, этот класс должен реализовать интерфейс INotifyPropertyChanged.

В вашем случае класс DisplayRow должен реализовывать INotifyPropertyChanged, а displayRows должен быть ObservableCollection.

Насколько я понимаю, это официальный способ. Я могу быть не прав.

person Paul Pantea    schedule 23.11.2011