使用CollectionViewSource和DataBinding进行WPF分组

时间:2009-10-22 15:26:19

标签: wpf data-binding collectionviewsource

我将CollectionViewSource绑定到ListView以对项目进行分组。这一切都很有效,除非我更新基于ObservableCollection的{​​{1}}。如果我更新集合中对象的值,则永远不会更新UI。这是一个例子:

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

private readonly ObservableCollection displayRows = new ObservableCollection();

CollectionViewSource

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中的值,则UI不会改变。

如果我在集合中添加一个元素,我可以看到它出现在屏幕上但是从不调用转换器来重新计算平均值。有什么想法吗?

3 个答案:

答案 0 :(得分:4)

我找到了解决这个问题的方法。

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

希望有所帮助。

答案 1 :(得分:2)

如果不刷新整个视图,仍然可以处理,我实现了这一点。

在CollectionView中创建数据绑定将允许组的更改通知。

查看http://stumblingaroundinwpf.blogspot.com/2009/11/building-smarter-wpf-collectionview-one.html

答案 2 :(得分:1)

如果数据源是ObservableCollection,则每当更改集合时,即当存在添加或删除项目时,将更新视图。如果希望在编辑基础数据时更新视图,则该类必须实现INotifyPropertyChanged接口。

在你的情况下,DisplayRow类必须实现INotifyPropertyChanged,displayRows应该是一个ObservableCollection。

根据我的理解,这是正式的方法。我可能错了。