在 WPF 中更新 ObservableCollection 会导致屏幕闪烁;我该如何预防?

发布于 2024-09-14 01:41:48 字数 217 浏览 6 评论 0原文

我有一个 ObservableCollection 以 MVVM 模式绑定到 WPFToolkit DataGrid。每隔 30 秒,我就会有一个后台线程在服务中查询一些数据。当它返回时,它将其编组到 UI 线程,并通过首先对集合调用 Clear() 然后对每个项目调用 Add() 来更新 ObservableCollection。发生这种情况时,数据会正确更新到屏幕,但是数据网格会闪烁。我怎样才能防止这种情况发生?

I have an ObservableCollection bound to a WPFToolkit DataGrid in an MVVM pattern. Every 30 seconds I have a background thread that is querying a service for some data. When it returns, it marshals it to the UI thread and updates the ObservableCollection by first calling Clear() on the collection and then calling Add() for each item. When this happens, the data is updated properly to the screen, however, the datagrid flickers. How can I prevent this from happening?

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

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

发布评论

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

评论(2

半仙 2024-09-21 01:41:48

如果您一次清除然后添加每一项,那么您似乎只是替换了所有数据。您是否可以简单地将数据网格的项目源设置为包含新项目的新 ObservableCollection,而不是重新使用 ObservableCollection?

It appears you're simply replacing all of your data if you're clearing then adding each item one at a time. Instead of re-using your ObservableCollection, can you simply set your data grid's itemssource to a new ObservableCollection with your new items?

极致的悲 2024-09-21 01:41:48

我为您的问题创建了一个简单但最强大的解决方案:

public class MyCollection<T> : ObservableCollection<T>
{
    private bool _isInEditMode = false;

    public void BeginEdit()
    {
        _isInEditMode = true;
    }

    public void CommitEdit()
    {
        _isInEditMode = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (_isInEditMode == false)
        {
            base.OnCollectionChanged(e);
        }
    }
}

当您处于编辑模式时,我的集合类可防止集合更改事件。在清除项目之前启动“BeginEdit”。然后添加您的新项目。完成后,使用“CommitEdit”,视图将仅刷新一次。

如果用一个简单的列表框测试它,我在其中添加 1.000.000 个字符串项目。试试这个。这很有趣:)

 private void Button_Click(object sender, RoutedEventArgs e)
    {
        MyCollection<string> list = testBox.ItemsSource as MyCollection<string>;
        //list.BeginEdit();
        for (int i = 0; i < 1000000; i++)
        {
            list.Add("test " + i);
        }
        list.CommitEdit();

    }

从 list.BeginEdit() 中删除 // 并查看差异。再次约15秒< 1秒。

问候,

I created a simple but maximum powerfull solution for your problem:

public class MyCollection<T> : ObservableCollection<T>
{
    private bool _isInEditMode = false;

    public void BeginEdit()
    {
        _isInEditMode = true;
    }

    public void CommitEdit()
    {
        _isInEditMode = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (_isInEditMode == false)
        {
            base.OnCollectionChanged(e);
        }
    }
}

The my collection class prevents collection changed events while you are in edit mode. Start "BeginEdit" before clearing the items. Then add your new items. When you are finished, use "CommitEdit" and the view will refresh only once.

If have tested it with a simple listbox, where i add 1.000.000 string items. Try this out. Its funny :)

 private void Button_Click(object sender, RoutedEventArgs e)
    {
        MyCollection<string> list = testBox.ItemsSource as MyCollection<string>;
        //list.BeginEdit();
        for (int i = 0; i < 1000000; i++)
        {
            list.Add("test " + i);
        }
        list.CommitEdit();

    }

Remove the // from list.BeginEdit() and see the difference. Its about 15 seconds agains < 1 second.

Greetings,

Jan

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