2009-10-22 14 views
2

Je lie un CollectionViewSource à un ListView pour regrouper des éléments. Tout fonctionne très bien sauf quand je mets à jour le ObservableCollection sur lequel est basé CollectionViewSource. Si je mets à jour une valeur d'un objet dans la collection, l'interface utilisateur n'est jamais mise à jour. Voici un exemple:Groupement WPF à l'aide de CollectionViewSource et DataBinding

<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> 

Vous remarquerez qu'il appelle un convertisseur dans le groupe et en lui donnant la collection d'éléments. Il en est ainsi le convertisseur peut calculer la moyenne des lignes et retourner ce résultat:

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

Dans le code derrière ajouter les lignes et créer le CollectionViewSource:

readonly privé 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; 
} 

L'objet DisplayRow implémente INotifyPropertyChanged, et est juste une simple classe.

Tout fonctionne bien et l'affichage est comme je veux, mais si je change une valeur dans le ObservableCollection l'interface utilisateur ne change pas.

Si j'ajoute un élément à la collection je peux le voir apparaître sur l'écran mais le convertisseur n'est jamais appelé pour recalculer la moyenne. Des idées?

Répondre

4

J'ai trouvé un moyen de contourner ce problème.

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

Espérons que ça aide.

+0

Nice. Oui, ça aide. Malheureusement, j'ai besoin de mettre à jour le tout, mais au moins, cela me cause ce problème. Merci. – Kelly

1

Si la source de données est un ObservableCollection, la vue sera mis à jour chaque fois que la collection est modifiée à savoir quand il y a des éléments ajoutés ou supprimés. Si vous souhaitez que la vue soit mise à jour lorsque les données sous-jacentes sont modifiées, cette classe doit implémenter l'interface INotifyPropertyChanged.

Dans votre cas, la classe DisplayRow doit implémenter INotifyPropertyChanged et displayRows doit être une ObservableCollection.

C'est la façon officielle de le faire, d'après ce que je comprends. J'ai peut être tort.

Questions connexes