Kafayı yiyecektim arkadaş. Şaka gibi ama, bir liste görselleştirme aracı yazıyordum ve veritabanından 10.000 satırlık bir veri seti çekip WPF DataGrid'ime bağlamam gerekti. Her şey güzel, ObservableCollection kullanıyorum, UI otomatik güncellensin diye. Sonra işler yavaşlamaya başladı...
Performans Duvarına Toplam Çarpış
Add metodunu bir döngüye koydum. Her bir eleman eklendiğinde, koleksiyon CollectionChanged event'ini fırlatıyor ve UI (benim grid'im) kendini güncelliyor. 10.000 kayıt için bu, 10.000 ayrı UI güncellemesi ve yeniden çizimi demek! Bilgisayarımın fanları kalkışa geçti, arayüz tamamen dondu, "Yanıt Vermiyor" yazısını görünce içimden bir şeyler koptu. StackOverflow'da bile direk bir çözüm bulamadım, herkes aynı dertten muzdarip.
Meğerse Sorun Şuradaymış
Araştırdıkça gördüm ki, ObservableCollection sınıfının temel tasarımında AddRange gibi bir metod yok. Microsoft'un kendi dokümantasyonunda bile bu bir "known issue" olarak geçiyor. Her ekleme, bir NotifyCollectionChangedAction.Add event'i tetikliyor ve bu da performansı katlediyor. Özellikle INotifyPropertyChanged implemente etmiş karmaşık objeleriniz varsa, felaketin boyutu katlanıyor.
Denediğim (Biraz) Çözüm Yolları/B]
İlk aklıma gelen, veriyi önce normal bir List'e atmak, sonra tek seferde ObservableCollection'a atamaktı. Ama bu da UI'ı güncellemiyor tabii. O yüzden şöyle bir yol denedim:
Bu, döngü içindeki 10.000 event yerine, sadece ItemsSource değiştiğinde olan 1-2 güncellemeye izin verdi. Performans ciddi anlamda arttı. Ama yine de "collection'ın kendisini tamamen değiştirmek" bana biraz kaba bir çözüm gibi geldi.
Daha temiz bir yol arayanlar için, internetten bulduğum veya uydurduğum birkaç yöntem daha var: CollectionViewSource kullanmak, ya da ObservableCollection'dan türeyen ve AddRange metodu ekleyen kendi koleksiyon sınıfınızı yazmak. Ama her biri ayrı bir dert.
Siz ne yapıyorsunuz? Büyük veri setlerini WPF'de smooth bir şekilde göstermenin sırrı nedir? Kendi yazdığınız bir ExtendedObservableCollection class'ınız var mı, yoksa farklı bir pattern mi kullanıyorsunuz? Yorumlarda teknik isyanımıza ortak olun!
Add metodunu bir döngüye koydum. Her bir eleman eklendiğinde, koleksiyon CollectionChanged event'ini fırlatıyor ve UI (benim grid'im) kendini güncelliyor. 10.000 kayıt için bu, 10.000 ayrı UI güncellemesi ve yeniden çizimi demek! Bilgisayarımın fanları kalkışa geçti, arayüz tamamen dondu, "Yanıt Vermiyor" yazısını görünce içimden bir şeyler koptu. StackOverflow'da bile direk bir çözüm bulamadım, herkes aynı dertten muzdarip.
Araştırdıkça gördüm ki, ObservableCollection sınıfının temel tasarımında AddRange gibi bir metod yok. Microsoft'un kendi dokümantasyonunda bile bu bir "known issue" olarak geçiyor. Her ekleme, bir NotifyCollectionChangedAction.Add event'i tetikliyor ve bu da performansı katlediyor. Özellikle INotifyPropertyChanged implemente etmiş karmaşık objeleriniz varsa, felaketin boyutu katlanıyor.
İlk aklıma gelen, veriyi önce normal bir List'e atmak, sonra tek seferde ObservableCollection'a atamaktı. Ama bu da UI'ı güncellemiyor tabii. O yüzden şöyle bir yol denedim:
C#:
// Önce UI güncellemesini geçici olarak durdur
myDataGrid.ItemsSource = null;
// Verileri hızlıca listeye yükle
var tempList = new List<MyData>(_veritabanindanGelenBuyukListe);
// Tüm listeyi ObservableCollection'a ekle (HALA YAVAŞ!)
myObservableCollection = new ObservableCollection<MyData>(tempList);
// En sonunda ItemsSource'u yeniden bağla
myDataGrid.ItemsSource = myObservableCollection;
Bu, döngü içindeki 10.000 event yerine, sadece ItemsSource değiştiğinde olan 1-2 güncellemeye izin verdi. Performans ciddi anlamda arttı. Ama yine de "collection'ın kendisini tamamen değiştirmek" bana biraz kaba bir çözüm gibi geldi.
Daha temiz bir yol arayanlar için, internetten bulduğum veya uydurduğum birkaç yöntem daha var: CollectionViewSource kullanmak, ya da ObservableCollection'dan türeyen ve AddRange metodu ekleyen kendi koleksiyon sınıfınızı yazmak. Ama her biri ayrı bir dert.
Siz ne yapıyorsunuz? Büyük veri setlerini WPF'de smooth bir şekilde göstermenin sırrı nedir? Kendi yazdığınız bir ExtendedObservableCollection class'ınız var mı, yoksa farklı bir pattern mi kullanıyorsunuz? Yorumlarda teknik isyanımıza ortak olun!