2015-02-09 710 views
0

我使用WPF Toolkit繪製圖形並綁定數據以顯示我使用observable集合的圖並將數據點添加到集合並將此集合作爲itemsource爲情節。將批量數據添加到Observable Collection會降低應用程序的性能

我的問題是當我向我的收藏中添加很多數據點時,或者從收藏中重新獲取數據點並嘗試顯示它正在花費時間顯示的情節。

我能爲這個問題做些什麼?

請給我建議,以便提高性能。

在此先感謝。

+0

大約有多少數據點導致該問題?另外檢查是否[this SO post](http://stackoverflow.com/questions/11958375/how-to-add-thousands-of-items-to-a-- bindded-collection-without-locking-gui)或[this ](http://updatecontrols.net/doc/tips/common_mistakes_observablecollection)或[this](http://tliangnet.blogspot.in/2013/04/observablecollection-performance-issue.html)可以幫助你。 – 2015-02-09 12:49:13

+0

我有大約16000點左右(我必須從csv文件中讀取)。我可以閱讀所有內容,但只繪製性能問題。 – Balerina 2015-02-11 05:28:05

回答

0

ObservableCollection通知每一個變化,這意味着很多事件,因此它影響性能。您可以使用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; 
} 

在這種情況下,您必須手動通知對列表所做更改的視圖。例如在任何地方比你的視圖模型的構造等,或查看你必須這樣做:

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 
0

我用的ObservableCollection的子類從this後添加一個批處理更新,並允許您添加一個.AddRange直到最後才批量觸發更新通知。

爲了保持完整性,我已經複製了原始帖子中的代碼,但是如果您發現它很有用,請加快鏈接的帖子。

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 
+0

我實現了上面建議的方式,即從Observable集合中獲取一個類,並使用AddRange函數添加數據。但我仍然沒有發現性能上的重大差異。我正在使用WPF工具包進行繪圖。這對性能是否重要?如此,請給我建議改善表現的方法。提前致謝 – Balerina 2015-03-02 14:01:43