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

发布于 2024-07-07 20:25:10 字数 573 浏览 7 评论 0原文

我有 WPF ListBox,它绑定到 ObservableCollection, 当集合发生变化时,所有项目都会更新其位置。

新位置存储在集合中,但 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;
    }

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

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

建议?

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

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

    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,

but this is probably very bad coding :p

Suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

半夏半凉 2024-07-14 20:25:11

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

我只是个傻子。 虽然我读了很多关于使用 ObservableCollection<> 而不是 List<> 的内容,但我只是继续忽略此建议并遵循其他建议,但无济于事。 回到我的书并重读。 很好地解释了 ObservableCollection<> 是必须使用的,因为 List<> 不提供 INotifyCollectionChange 接口所需的 < code>ListBox 以在集合中的项目发生更改时更新其显示。

这是更新后的代码:

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

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

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

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

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

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

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 INotifyCollectionChange interface needed for the ListBox to update its display when the items change in the collection.

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:

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

ObservableCollection doesn'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:

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.

笑饮青盏花 2024-07-14 20:25:11

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

我有一个 ObservableCollection 和一个绑定到它的 ListBox。 但由于某些奇怪的原因,当我更改列表中 MyEntity 对象的属性时,我的 ListBox 并未更新。

搜索了一段时间后,我发现了以下页面,我只想让您知道:

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

这是一个很好的描述,说明了要获得< code>ListBox 以在列表或其中的对象发生更改时进行更新。 希望您能从中受益。

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

I had an ObservableCollection<MyEntity> and a ListBox bound to it. But for some strange reason my ListBox was not being updated when I changed the properties of the MyEntity objects in the list.

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

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

熊抱啵儿 2024-07-14 20:25:11

我昨天也遇到了同样的问题,这完全是一派胡言:) ...不过,我不会再将我的问题设置为 null 了。 在我的场景中,我将其设置为 MyList.ToArray() (每次添加到列表后)。

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

我见过很多“哦,调用‘刷新’”<——完全是垃圾。

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

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

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

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

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

无声情话 2024-07-14 20:25:11

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

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

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

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 this awesome article.

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

CollectionViewSource.GetDefaultView(this.myObservableCollection).Refresh();
╄→承喏 2024-07-14 20:25:11

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

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

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.

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
浅紫色的梦幻 2024-07-14 20:25:11

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

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.

愿得七秒忆 2024-07-14 20:25:11

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

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.

横笛休吹塞上声 2024-07-14 20:25:10

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

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

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

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文