简体   繁体   English

向 Observable Collection 添加批量数据会降低应用程序性能

[英]Adding bulk data to Observable Collection slows down the application performance

I am plotting the graphs using WPF Toolkit and to bind the data to show up the plots i am using observable collection and adding the datapoints to the collection and giving this collection as itemsource for the plot.我正在使用 WPF Toolkit 绘制图形并绑定数据以显示我正在使用的可观察集合并将数据点添加到集合并将此集合作为绘图的项目源。

My problem is when i am adding tooo many data points to my collection, or retriving the data points from the collection and try to show up the plot it is taking loooots of time to show up.我的问题是当我向我的集合中添加太多数据点时,或者从集合中检索数据点并尝试显示它需要花费大量时间才能显示的图。

What can i do for this issue?我可以为这个问题做些什么?

Please suggest me so that the performance can be improved.请建议我,以便提高性能。

Thanks in Advance.提前致谢。

ObservableCollection notifies with every change and that means a lot of events so it affects performance. ObservableCollection 会在每次更改时发出通知,这意味着很多事件会影响性能。 You can use a List instead of ObservableCollection but most people don't recommend it.您可以使用 List 而不是 ObservableCollection 但大多数人不推荐它。

public class MainVm:INotifyPropertyChanged
{
    List<Point> _points;
    public List<Point> Points
    {
        get { return _points; }
        set { _points = value; Notify("Points"); }
    }
    public void Notify(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

In this case you have to manually notify the view of changes made to the list.在这种情况下,您必须手动通知视图对列表所做的更改。 for example anywhere other than the constructor of your view model or view you have to do this:例如,除了视图模型或视图的构造函数之外的任何地方,您都必须这样做:

Points.Add(new Point());
Points.Add(new Point());
Points.Add(new Point());
//View is not notified yet

var tmp = Points;
Points = null;//View is notified and cleared
Points = tmp;//View is notified and updated

I've used the subclass of ObservableCollection from this post to add a .AddRange that batches updates and allows you to add items in bulk without triggering the update notification until the very end.我使用了这篇文章中 ObservableCollection 的子类来添加一个 .AddRange ,它可以批量更新并允许您批量添加项目而不会触发更新通知直到最后。

I've copied the code from the original post for completeness, but please upvote the linked post if you found it useful.为了完整起见,我已经从原始帖子中复制了代码,但是如果您发现它有用,请对链接的帖子点赞。

Imports System.Collections.Specialized
Imports System.ComponentModel
Imports System.Collections.ObjectModel

Public Class ObservableRangeCollection(Of T) : Inherits ObservableCollection(Of T) : Implements INotifyCollectionChanging(Of T)
    ''' <summary>
    ''' Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        MyBase.New()
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection.
    ''' </summary>
    ''' <param name="collection">collection: The collection from which the elements are copied.</param>
    ''' <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception>
    Public Sub New(ByVal collection As IEnumerable(Of T))
        MyBase.New(collection)
    End Sub

    ''' <summary>
    ''' Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
    ''' </summary>
    Public Sub AddRange(ByVal collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Add, collection)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        Dim index = Items.Count - 1
        For Each i In collection
            Items.Add(i)
        Next

        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection, index))
    End Sub


    ''' <summary>
    ''' Inserts the collection at specified index.
    ''' </summary>
    Public Sub InsertRange(ByVal index As Integer, ByVal Collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Add, Collection)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        For Each i In Collection
            Items.Insert(index, i)
        Next

        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
    End Sub


    ''' <summary>
    ''' Removes the first occurence of each item in the specified collection from ObservableCollection(Of T).
    ''' </summary>
    Public Sub RemoveRange(ByVal collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Remove, collection)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        For Each i In collection
            Items.Remove(i)
        Next

        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
    End Sub



    ''' <summary>
    ''' Clears the current collection and replaces it with the specified item.
    ''' </summary>
    Public Sub Replace(ByVal item As T)
        ReplaceRange(New T() {item})
    End Sub

    ''' <summary>
    ''' Clears the current collection and replaces it with the specified collection.
    ''' </summary>
    Public Sub ReplaceRange(ByVal collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Replace, Items)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        Items.Clear()
        For Each i In collection
            Items.Add(i)
        Next
        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
    End Sub

    Protected Overrides Sub ClearItems()
        Dim e As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Reset, Items)
        OnCollectionChanging(e)

        If e.Cancel Then Exit Sub

        MyBase.ClearItems()
    End Sub

    Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As T)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Add, item)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.InsertItem(index, item)
    End Sub

    Protected Overrides Sub MoveItem(ByVal oldIndex As Integer, ByVal newIndex As Integer)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)()
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.MoveItem(oldIndex, newIndex)
    End Sub

    Protected Overrides Sub RemoveItem(ByVal index As Integer)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Remove, Items(index))
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.RemoveItem(index)
    End Sub

    Protected Overrides Sub SetItem(ByVal index As Integer, ByVal item As T)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Replace, Items(index))
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.SetItem(index, item)
    End Sub

    Protected Overrides Sub OnCollectionChanged(ByVal e As Specialized.NotifyCollectionChangedEventArgs)
        If e.NewItems IsNot Nothing Then
            For Each i As T In e.NewItems
                If TypeOf i Is INotifyPropertyChanged Then AddHandler DirectCast(i, INotifyPropertyChanged).PropertyChanged, AddressOf Item_PropertyChanged
            Next
        End If
        MyBase.OnCollectionChanged(e)
    End Sub

    Private Sub Item_PropertyChanged(ByVal sender As T, ByVal e As ComponentModel.PropertyChangedEventArgs)
        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, sender, IndexOf(sender)))
    End Sub

    Public Event CollectionChanging(ByVal sender As Object, ByVal e As NotifyCollectionChangingEventArgs(Of T)) Implements INotifyCollectionChanging(Of T).CollectionChanging
    Protected Overridable Sub OnCollectionChanging(ByVal e As NotifyCollectionChangingEventArgs(Of T))
        RaiseEvent CollectionChanging(Me, e)
    End Sub
End Class


Public Interface INotifyCollectionChanging(Of T)
    Event CollectionChanging(ByVal sender As Object, ByVal e As NotifyCollectionChangingEventArgs(Of T))
End Interface

Public Class NotifyCollectionChangingEventArgs(Of T) : Inherits CancelEventArgs

    Public Sub New()
        m_Action = NotifyCollectionChangedAction.Move
        m_Items = New T() {}
    End Sub

    Public Sub New(ByVal action As NotifyCollectionChangedAction, ByVal item As T)
        m_Action = action
        m_Items = New T() {item}
    End Sub

    Public Sub New(ByVal action As NotifyCollectionChangedAction, ByVal items As IEnumerable(Of T))
        m_Action = action
        m_Items = items
    End Sub

    Private m_Action As NotifyCollectionChangedAction
    Public ReadOnly Property Action() As NotifyCollectionChangedAction
        Get
            Return m_Action
        End Get
    End Property

    Private m_Items As IList
    Public ReadOnly Property Items() As IEnumerable(Of T)
        Get
            Return m_Items
        End Get
    End Property
End Class

man try to use wpf ui virtuallization ,this just Rendering what you can see,so its load the data fastly男人尝试使用 wpf ui 虚拟化,这只是渲染你所看到的,所以它可以快速加载数据

ScrollViewer.CanContentScroll = "True"  
VirtualizingStackPanel.IsVirtualizing = "True"  
VirtualizingStackPanel.VirtualizationMode = "Standard"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM