强制数据绑定 WPF ListBox 更新的更好方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/253036/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 19:45:13  来源:igfitidea点击:

A better way of forcing data bound WPF ListBox to update?

wpfdata-bindinglistboxobservablecollection

提问by TimothyP

I have WPF ListBox which is bound to a ObservableCollection, when the collection changes, all items update their position.

我有一个绑定到 ObservableCollection 的 WPF ListBox,当集合更改时,所有项目都会更新它们的位置。

The new position is stored in the collection but the UI does not update. So I added the following:

新位置存储在集合中,但 UI 不会更新。所以我添加了以下内容:

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

By setting the ItemsSource to null and then binding it again, the UI is updated,

通过将 ItemsSource 设置为 null 然后再次绑定它,UI 被更新,

but this is probably very bad coding :p

但这可能是非常糟糕的编码:p

Suggestions?

建议?

回答by Gishu

I have a Listbox bound to an object property which is of type List<MyCustomType>()and I verified that the following code updates the listbox when the List is updated.

我有一个绑定到一个对象属性的列表框,该属性是类型List<MyCustomType>(),我验证了以下代码在更新列表时更新列表框。

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

If you're still facing issues, scan the VS IDE output window (Ctrl+W, O) and see if you can spot any binding errors reported.

如果您仍然遇到问题,请扫描 VS IDE 输出窗口(Ctrl+W、O)并查看是否可以发现任何报告的绑定错误。

回答by rolling

WPF binding a list / collection of items to a ListBox, but UI not refreshing after items updated, Solved.

WPF 将项目的列表/集合绑定到 ListBox,但在项目更新后 UI 不刷新,已解决

I'm just stupid. While I'd read a lot about using ObservableCollection<>instead of List<>, I just continued to ignore this suggestion and went following other suggestions, to no avail. Got back to my books and reread. It's pretty well explained that ObservableCollection<>is a must use because List<>doesn't provide the INotifyCollectionChangeinterface needed for the ListBoxto update its display when the items change in the collection.

我只是愚蠢。虽然我阅读了很多关于使用ObservableCollection<>而不是List<>,但我只是继续忽略这个建议并遵循其他建议,但无济于事。回到我的书并重读。很好地解释了这ObservableCollection<>是必须使用的,因为当集合中的项目更改时,它List<>没有提供更新其显示INotifyCollectionChange所需的界面ListBox

This is the updated code:

这是更新后的代码:

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

Pretty simple, and doesn't require anything else (e.g. Refresh()). Because ObservableCollection takes care itself of triggering the change event, I was able to remove the unnecessary call:

非常简单,不需要其他任何东西(例如 Refresh())。因为 ObservableCollection 负责触发更改事件,所以我能够删除不必要的调用:

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

ObservableCollectiondoesn't support an update by a thread which didn't create it. Because my list (a visual log to show the recent errors/info messages) can be updated from different threads, I add to adjust my code this way to ensure the update was done with the list's own dispatcher:

ObservableCollection不支持由未创建它的线程进行更新。因为我的列表(显示最近错误/信息消息的可视化日志)可以从不同的线程更新,所以我添加以这种方式调整我的代码,以确保更新是使用列表自己的调度程序完成的:

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));
        // ...

Also note that ObservableCollection<>doesn't support RemoveRange()contrary to List<>. This is part of the possible adjustments required when switching from List to ObservableCollection.

另请注意,ObservableCollection<>不支持RemoveRange()List<>. 这是从 List 切换到 ObservableCollection 时可能需要进行的调整的一部分。

回答by Alfred B. Thordarson

I may be having a similar problem to what you are having, but I'm not sure.

我可能遇到与您遇到的问题类似的问题,但我不确定。

I had an ObservableCollection<MyEntity>and a ListBoxbound to it. But for some strange reasonmy ListBoxwas not being updated when I changed the properties of the MyEntityobjects in the list.

我有一个ObservableCollection<MyEntity>和一个ListBox绑定。但对于一些奇怪的原因,ListBox没有被我改变的属性更新MyEntity列表中的对象。

After searching for a while I found the following page and I just had to let you know:

搜索了一段时间后,我找到了以下页面,我只需要让您知道:

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

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

It is a very good description of what you have to do to get a ListBoxto update when the list, or the objects within it, changes. Hoping you will benefit from this.

这是一个非常好的描述,ListBox当列表或其中的对象发生变化时,您必须做什么才能更新。希望您能从中受益。

回答by Timothy Khouri

I had the same problem yesterday, and it's a complete piece of crap :) ... I'm not setting mine to null anymore though. In my scenario, I am setting it to MyList.ToArray() (after every time I add to the list).

我昨天遇到了同样的问题,这是一个完整的废话:) ...不过我不再将我的设置为空。在我的场景中,我将它设置为 MyList.ToArray() (每次我添加到列表之后)。

I've seen multiple "oh, you need to use an ObservableList" <-- complete crap.

我见过多个“哦,你需要使用 ObservableList”<-- 完全是废话。

I've seen multiple "oh, call 'Refresh'" <-- complete crap.

我见过多个“哦,叫‘刷新’”<--完全是废话。

Please forgive my upsettedness, but I also would expect this to work :)

请原谅我的不安,但我也希望这能奏效:)

回答by KP.

This is old stuff but, use an ObservableCollection. IF you want the UI to see updates to properties in the Objects of the ObservableCollection you need to implement INotifyPropertyChanged in the class defenition for that object. Then raise the property changed event in the setter of each property.

这是旧的东西,但是,使用 ObservableCollection。如果您希望 UI 看到 ObservableCollection 的对象中属性的更新,您需要在该对象的类定义中实现 INotifyPropertyChanged。然后在每个属性的 setter 中引发属性更改事件。

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

回答by Berger

I know it's already a bit older but today I faced the same issue. I updated an property of an object inside an ObservableCollection and the View did not update, but then I found thisawesome article.

我知道它已经有点老了,但今天我遇到了同样的问题。我更新了 ObservableCollection 中对象的属性,但 View 没有更新,但后来我发现了这篇很棒的文章。

I think it's a very clean solution to manually trigger the update of an ObservableCollection:

我认为手动触发 ObservableCollection 更新是一个非常干净的解决方案:

CollectionViewSource.GetDefaultView(this.myObservableCollection).Refresh();

回答by flobadob

To me, it looks more like a bug in ListBox and ListView. I am binding to an ObservableCollection, the items in the collection implement INotifyPropertyChanged. The UI shows no added items when I dynamically press my 'add item' button however I have a counter control that is bound to MyCollection.Count. This counter control increments each time I press my 'add item' button. If I resize the view, the list box shows all my added items. So, the ItemSource binding on the ListBox control is broken. I also took care not to create a new MyCollection at any point, which would break the binding. Boo hoo.

对我来说,它看起来更像是 ListBox 和 ListView 中的一个错误。我绑定到一个 ObservableCollection,集合中的项目实现 INotifyPropertyChanged。当我动态按下“添加项目”按钮时,UI 没有显示任何添加的项目,但是我有一个绑定到 MyCollection.Count 的计数器控件。每次我按下“添加项目”按钮时,此计数器控件都会增加。如果我调整视图大小,列表框会显示我添加的所有项目。因此,ListBox 控件上的 ItemSource 绑定被破坏。我还注意不要在任何时候创建新的 MyCollection,这会破坏绑定。呜呜。

回答by flobadob

If you have an ObservableList of objects, and you're changing properties inside those objects, the notification doesn't apply since the collection is not changing directly. I have been forcing notification after changing my object properties by using Insert() to re-add my changed object to the collection, then RemoveAt() to remove the old copy. It's not pretty, but it works.

如果您有一个 ObservableList 对象,并且您正在更改这些对象内的属性,则通知不适用,因为该集合没有直接更改。在更改对象属性后,我一直在通过使用 Insert() 将更改的对象重新添加到集合中,然后使用 RemoveAt() 删除旧副本来强制通知。它不漂亮,但它有效。