web-dev-qa-db-fra.com

Un meilleur moyen de forcer WPF ListBox lié aux données à mettre à jour?

J'ai WPF ListBox qui est lié à un ObservableCollection, Lorsque la collection change, tous les éléments mettent à jour leur position.

La nouvelle position est stockée dans la collection mais l'interface utilisateur ne se met pas à jour . J'ai donc ajouté ce qui suit:

    void scenarioItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        ToolboxListItem.UpdatePositions();
        lstScenario.ItemsSource = null;
        lstScenario.ItemsSource = ToolboxListItem.ScenarioItems;
        this.lstScenario.SelectedIndex = e.NewStartingIndex;
    }

En définissant la propriété ItemsSource sur null, puis en la liant à nouveau, l'interface utilisateur est mise à jour,

mais c'est probablement très mauvais codage: p

Suggestions?

29
TimothyP

J'ai une Listbox liée à une propriété d'objet de type List<MyCustomType>() et j'ai vérifié que le code suivant met à jour la listbox lorsque la liste est mise à jour.

void On_MyObjProperty_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
   MyListBox.Items.Refresh();
}

Si le problème persiste, analysez la fenêtre de sortie VS IDE (Ctrl + W, O) et voyez si vous pouvez repérer les erreurs de liaison signalées.

74
Gishu

WPF lie une liste/une collection d’éléments à un ListBox, mais l’UI n’a pas d'actualisation après la mise à jour des éléments, résolu .

Je suis juste bête. Bien que j'aie beaucoup lu sur l'utilisation de ObservableCollection<> au lieu de List<>, j'ai simplement continué à ignorer cette suggestion et à suivre d'autres suggestions, sans succès. Revenez à mes livres et relisez. Il est très bien expliqué que ObservableCollection<> est une utilisation incontournable car List<> ne fournit pas l'interface INotifyCollectionChange nécessaire pour que ListBox puisse mettre à jour son affichage lorsque les éléments changent dans la collection.

Ceci est le code mis à jour:

private ObservableCollection<StringWrapper> m_AppLog;
ObservableCollection<StringWrapper> Log { get { return m_AppLog; } }

Assez simple, et ne nécessite rien d'autre (par exemple, Refresh ()). ObservableCollection se chargeant de déclencher l'événement change, j'ai pu supprimer l'appel inutile:

// notify bound objects
OnPropertyChanged("Log");

ObservableCollection ne supporte pas une mise à jour par un thread qui ne l'a pas créée. Étant donné que ma liste (un journal visuel affichant les erreurs/informations récentes) peut être mise à jour à partir de différents threads, j'ajoute pour ajuster mon code de cette manière afin de s'assurer que la mise à jour a été effectuée avec le répartiteur de la liste:

public void AddToLog(string message) {
    if (Thread.CurrentThread != Dispatcher.Thread) {
        // Need for invoke if called from a different thread
        Dispatcher.Invoke(
            DispatcherPriority.Normal, (ThreadStart)delegate() { AddToLog(message); });
    }
    else {
        // add this line at the top of the log
        m_AppLog.Insert(0, new StringWrapper(message));
        // ...

Notez également que ObservableCollection<> ne prend pas en charge RemoveRange() contrairement à List<>. Cela fait partie des ajustements possibles requis lors du passage de List à ObservableCollection.

9
rolling

Je peux avoir un problème similaire à ce que vous rencontrez, mais je ne suis pas sûr.

J'avais un ObservableCollection<MyEntity> et un ListBox liés à celui-ci. Mais pour quelque étrange raison, ma ListBox n'était pas mise à jour lorsque j'ai modifié les propriétés des objets MyEntity de la liste.

Après avoir cherché pendant un moment, j'ai trouvé la page suivante et je devais vous le faire savoir:

http://www.wblum.org/listbind/net3/index.html

C’est une très bonne description de ce que vous devez faire pour obtenir une ListBox à mettre à jour lorsque la liste ou les objets qu’elle contient changent. En espérant que vous en bénéficierez.

6

J'ai eu le même problème hier, et c'est une merde complète :) ... Je ne veux pas que le mien devienne nul alors. Dans mon scénario, je le configure sur MyList.ToArray () (après chaque ajout à la liste).

J'ai vu plusieurs "oh, vous devez utiliser un ObservableList" <- merde complète.

J'ai vu plusieurs "oh, appelle 'Refresh'" <- merde complète.

S'il vous plaît, pardonnez-moi ma colère, mais je m'attendrais aussi à ce que cela fonctionne :)

4
Timothy Khouri

C'est du vieux matériel, mais utilisez une ObservableCollection. SI vous souhaitez que l'interface utilisateur affiche les mises à jour des propriétés dans les objets de l'observableCollection, vous devez implémenter INotifyPropertyChanged dans la définition de classe de cet objet. Ensuite, relevez l'événement de propriété modifiée dans le créateur de chaque propriété.

Public Class Session
Implements INotifyPropertyChanged

Public Event PropertyChanged As PropertyChangedEventHandler _
   Implements INotifyPropertyChanged.PropertyChanged

Private Sub NotifyPropertyChanged(ByVal info As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub

Private _name As String = "No name"
''' <summary>
''' Name of Session
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Name() As String
    Get
        Return _name
    End Get
    Set(ByVal value As String)
        _name = value
        NotifyPropertyChanged("Name")
    End Set
End Property
2
KP.

Pour moi, cela ressemble plus à un bogue dans ListBox et ListView. Je suis lié à un ObservableCollection, les éléments de la collection implémentent INotifyPropertyChanged. L'interface utilisateur n'affiche aucun élément ajouté lorsque j'appuie dynamiquement sur le bouton "Ajouter un élément", mais j'ai un contrôle de compteur lié à MyCollection.Count. Ce contrôle de compteur s’incrémente chaque fois que j’appuie sur le bouton «Ajouter un élément». Si je redimensionne la vue, la zone de liste affiche tous mes éléments ajoutés. Ainsi, la liaison ItemSource sur le contrôle ListBox est cassée. J'ai également pris soin de ne pas créer de nouvelle MyCollection à aucun moment, ce qui briserait la liaison. Boo hoo.

0
flobadob

Si vous avez une liste d'objets observable et que vous modifiez des propriétés à l'intérieur de ces objets, la notification ne s'applique pas car la collection ne change pas directement. J'ai forcé la notification après avoir modifié les propriétés de mon objet en utilisant Insert () pour rajouter mon objet modifié à la collection, puis RemoveAt () pour supprimer l'ancienne copie. Ce n'est pas joli, mais ça marche.

0
Peter