Группировка WPF с использованием CollectionViewSource и DataBinding - PullRequest
2 голосов
/ 22 октября 2009

Я связываю 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, пользовательский интерфейс не изменится.

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

Ответы [ 3 ]

4 голосов
/ 23 октября 2009

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

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();
}

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

2 голосов
/ 23 ноября 2009

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

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

Выезд http://stumblingaroundinwpf.blogspot.com/2009/11/building-smarter-wpf-collectionview-one.html

1 голос
/ 23 ноября 2011

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

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

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

...