web-dev-qa-db-fra.com

Comment implémenter une liste des cases à cocher dans WPF?

Bien que quelque peu expérimenté avec l'écriture des applications WinFormes, ... "l'imprécision" du WPF me échappe toujours en termes de meilleures pratiques et de modèles de conception.

Malgré une collecte de ma liste au moment de l'exécution, ma liste de liste apparaît vide.

J'ai suivi les instructions simples de cet article utile en vain. Je soupçonne que je manque une sorte de DataBind() méthode où je dis à la liste de liste que j'ai faite modifier la liste sous-jacente.

Dans mon mainwindow.xaml, j'ai:

    <ListBox ItemsSource="{Binding TopicList}" Height="177" HorizontalAlignment="Left" Margin="15,173,0,0" Name="listTopics" VerticalAlignment="Top" Width="236" Background="#0B000000">
        <ListBox.ItemTemplate>
            <HierarchicalDataTemplate>
                <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
            </HierarchicalDataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Dans mon code - derrière, j'ai:

    private void InitializeTopicList( MyDataContext context )
    {
        List<Topic> topicList = ( from topic in context.Topics select topic ).ToList();

        foreach ( Topic topic in topicList )
        {
            CheckedListItem item = new CheckedListItem();
            item.Name = topic.DisplayName;
            item.ID = topic.ID;
            TopicList.Add( item );
        }
    }

Ce qui, en traçant, je sais, c'est être peuplé de quatre articles.

ÉDITER

J'ai changé TopicList à un ObservableCollection. Ça ne marche toujours pas.

    public ObservableCollection<CheckedListItem> TopicList;

Éditer n ° 2

J'ai fait deux changements qui aident:

Dans le fichier .xaml:

ListBox ItemsSource="{Binding}"

Dans le code source après que je peuplie la liste:

listTopics.DataContext = TopicList;

Je reçois une liste, mais cela ne met pas à jour automatiquement la case à cocher les états lorsque je rafraîchis ceux-ci. Je soupçonne un peu de lecture supplémentaire de ma part de résoudre ce problème.

21
Bob Kaufman

Utilisez ObservableCollection<Topic> Au lieu de List<Topic>

éditer

il implémente une interface inofinyCollectionChanged pour laisser WPF savoir lorsque vous ajoutez/supprimer/modifier des éléments

éditer 2

Depuis que vous définissez TopicList en code, il devrait s'agir d'une propriété de dépendance, pas un champ commun

    public ObservableCollection<CheckedListItem> TopicList {
        get { return (ObservableCollection<CheckedListItem>)GetValue(TopicListProperty); }
        set { SetValue(TopicListProperty, value); }
    }
    public static readonly DependencyProperty TopicListProperty =
        DependencyProperty.Register("TopicList", typeof(ObservableCollection<CheckedListItem>), typeof(MainWindow), new UIPropertyMetadata(null));

éditer

Pour voir les changements d'éléments

  1. implémente INotifyPropertyChanged interface dans CheckedListItem (chaque réglage doit appeler PropertyChanged(this, new PropertyChangedEventArgs(<property name as string>)) événement)
  2. ou dériver CheckedListItem de DependencyObject et convertir Name, ID, IsChecked à des propriétés de dépendance
  3. ou les mettre à jour totalement (topicList[0] = new CheckedListItem() { Name = ..., ID = ... })
5
Mykola Bogdiuk

En supposant que TopicList n'est pas un ObservableCollection<T> Par conséquent, lorsque vous ajoutez des éléments no INotifyCollection _ modifié est en cours de cuisson pour indiquer au moteur de liaison de mettre à jour la valeur.

Changez votre TopicList à un ObservableCollection<T> qui résoudra le problème actuel. Vous pouvez également remplir le List<T> à l'avance et puis la liaison fonctionnera via une toutefois ObservableCollection<T> est une approche plus robuste.

Edit :

Votre TopicList doit être une propriété non une variable membre; Les liaisons nécessitent des propriétés. Il fait non doit être un DependencyProperty.

Edit 2 :

Modifier votre ItemTemplate tel qu'il n'a pas besoin d'être un HierarchicalDataTemplate

   <ListBox.ItemTemplate>
     <DataTemplate>
       <StackPanel>
         <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
       </StackPanel>
     </DataTemplate>
   </ListBox.ItemTemplate>
8
Aaron McIver

D'autres ont déjà fait des suggestions utiles (utilisent une collection observable pour obtenir une notification de la liste de changement, rendre la collection une propriété plutôt qu'un champ). Voici deux ils n'ont pas:

1) Chaque fois que vous rencontrez un problème de liaison de données, consultez la fenêtre de sortie pour vous assurer que vous n'obtenez aucune erreur de liaison. Vous pouvez passer beaucoup de temps à essayer de résoudre le mauvais problème si vous ne le faites pas.

2) Comprendre les jeux de notification de changement de rôle dans la liaison. Les modifications apportées à votre source de données ne peuvent et ne seront pas propagées à l'interface utilisateur, à moins que la source de données implémente la notification de changement. Il existe deux façons de le faire pour les propriétés normales: rendre la source de données dérive de DependencyObject et rendez la propriété liée à une propriété de dépendance ou de mettre en œuvre la source de données INotifyPropertyChanged et augmentez le PropertyChanged événement lorsque la valeur de la propriété change. Lors de la liaison d'un ItemsControl à une collection, utilisez une classe de collecte qui implémente INotifyCollectionChanged (comme ObservableCollection<T>), afin que cela change sur le contenu et l'ordre de la collection se propagera au contrôle limité. (Notez que si vous souhaitez des modifications aux éléments IN la collection à se propager aux commandes liées, ces éléments doivent également mettre en œuvre une notification de changement.)

3
Robert Rossney