2008-09-11 5 views
31

System.Collections.ObjectModel ObservableCollection<T> कक्षा पर विचार कर रहा था। यह एक अजीब बात है क्योंकिएक साथ कई ऑब्जेक्ट्स जोड़ने और अधिसूचित होने के लिए कौन सा .NET संग्रह?

  • यह एक जोड़ें विधि जो एक आइटम केवल लेता है। कोई AddRange या समकक्ष नहीं।
  • अधिसूचना घटना तर्क एक NewItems संपत्ति है, जो एक IList (वस्तुओं की .. नहीं टी)

मेरे जरूरत यहाँ एक संग्रह और श्रोता भी हो जाता है करने के लिए वस्तुओं की एक बैच को जोड़ने के लिए है है अधिसूचना के हिस्से के रूप में बैच। क्या मुझे पर्यवेक्षण चयन के साथ कुछ याद आ रही है? क्या कोई और वर्ग है जो मेरी कल्पना को पूरा करता है?

अपडेट: अपने आप को यथासंभव यथासंभव रोल नहीं करना चाहते हैं। मुझे जोड़ने/निकालने/बदलने आदि में निर्माण करना होगा .. सामान की एक बहुत सारी चीज़ें।


संबंधित प्रश्न:
सूची < टी से https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each

+4

Gishu, सावधान, अगर आप सूचीदृश्य करने के लिए यहाँ कार्यान्वयन के सबसे बाँध को उड़ाने होगा। –

उत्तर

1

इनहेरिट> और ओवरराइड जोड़ें() और AddRange() पद्धतियों एक घटना को बढ़ाने के लिए?

2

यदि आप किसी प्रकार के संग्रह से उत्तराधिकारी बनना चाहते हैं, तो शायद आप System.Collections.ObjectModel.Collection से विरासत से बेहतर हो सकते हैं क्योंकि यह ओवरराइड के लिए वर्चुअल विधियां प्रदान करता है। यदि आप उस मार्ग पर जाते हैं तो आपको सूची से बाहर विधियों को छाया करना होगा।

मैं के बारे में पता नहीं कर रहा हूँ किसी भी अंतर्निहित संग्रह है कि इस सुविधा प्रदान करती हैं, हालांकि मैं ठीक किया जा रहा है :) का स्वागत करता हूँ

18

ऐसा लगता है कि INotifyCollectionChanged इंटरफेस को अद्यतन करने के एक से अधिक आइटम जोड़ा गया था के लिए अनुमति देता है, तो मैं मुझे यकीन नहीं है कि ObservableCollection<T> में AddRange क्यों नहीं है। आप AddRange के लिए एक विस्तार विधि बना सकते हैं, लेकिन इससे जोड़े गए प्रत्येक आइटम के लिए एक ईवेंट का कारण बन जाएगा। बचाव के लिए

public class MyObservableCollection<T> : ObservableCollection<T> 
{ 
    // matching constructors ... 

    bool isInAddRange = false; 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     // intercept this when it gets called inside the AddRange method. 
     if (!isInAddRange) 
      base.OnCollectionChanged(e); 
    } 


    public void AddRange(IEnumerable<T> items) 
    { 
     isInAddRange = true; 
     foreach (T item in items) 
      Add(item); 
     isInAddRange = false; 

     var e = new NotifyCollectionChangedEventArgs(
      NotifyCollectionChangedAction.Add, 
      items.ToList()); 
     base.OnCollectionChanged(e); 
    } 
} 
+0

कोड स्निपेट को कुछ सुधार की आवश्यकता है .. IENumerable में कोई ToList() नहीं है और AddRange को आईसीओलेक्शन को लगातार बनाए रखना चाहिए ... चूंकि मुझे अपने साप्ताहिक लक्ष्य को पूरा करने की मेरी भव्य योजनाओं के लिए इस अस्थायी झटके के माध्यम से स्टीम-रोल करना पड़ा , मेरे कोड नमूना पोस्टिंग .. थोड़ा छोटा। – Gishu

+2

गिशू, ToList() विधि IENumerable पर उपलब्ध एक LINQ एक्सटेंशन विधि है। –

+0

समझ गया ... आपको .NET 3.5 का उपयोग करने के लिए प्रोजेक्ट सेटिंग्स सेट करने और LINQ असेंबली संदर्भ जोड़ने और इसे प्राप्त करने के लिए निर्देश का उपयोग करने की आवश्यकता है। – Gishu

-1

एक्सटेंशन विधि यार: यदि यह स्वीकार्य नहीं है कि आप इस प्रकार ObservableCollection<T> से विरासत में सक्षम होना चाहिए!

/// <summary> 
    /// Adds all given items to the collection 
    /// </summary> 
    /// <param name="collection">The collection.</param> 
    /// <param name="toAdd">Objects to add.</param> 
    public static void AddAll<T>(this IList<T> collection, params T[] toAdd) 
    { 
     foreach (var o in toAdd) 
      collection.Add(o); 
    } 
+0

यह दर्दनाक रूप से धीमा है ... उदाहरण के लिए 3000 आइटम को देखने योग्य में जोड़ने का प्रयास करें संग्रह (3 मिनट के लिए ui को अलविदा कहें) –

+1

यदि आप यूआई के लिए बाध्य हैं, तो सबसे अधिक संभावना है। http://blogs.msdn.com/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx – Will

+0

अन्य समाधानों के लिए अच्छा जोड़ा लेकिन शायद प्रदर्शन तक सबसे अच्छा नहीं है। जब तक आपके स्वयं के संग्रह बनाना एक विकल्प है, मुझे लगता है कि अन्य समाधान शायद लंबे समय तक बेहतर होते हैं। – jpierson

4

इतना ही नहीं System.Collections.ObjectModel.Collection<T> एक अच्छा शर्त है, लेकिन मदद डॉक्स में वहाँ कैसे आदेश सूचना प्राप्त करने के लिए इसके विभिन्न संरक्षित तरीकों को ओवरराइड करने के an example है। (उदाहरण के लिए नीचे स्क्रॉल करें 2.)

+0

धन्यवाद - उपयोगी लिंक ... एक मानसिक नोट बनाया। – Gishu

6

वैसे यह विचार fryguybob के समान है - थोड़े अजीब है कि ऑब्जर्जेबल कोलेक्शन थोडा-पूरा किया गया है। इस बात के लिए घटना args भी जेनेरिक्स .. का उपयोग नहीं करते मुझे एक IList (कि इतने है .. कल :) परीक्षण स्निपेट इस प्रकार का उपयोग कर रही है ...

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Collections.Specialized; 

namespace MyNamespace 
{ 
    public class ObservableCollectionWithBatchUpdates<T> : ObservableCollection<T> 
    { 
     public void AddRange(ICollection<T> obNewItems) 
     { 
      IList<T> obAddedItems = new List<T>(); 
      foreach (T obItem in obNewItems) 
      { 
       Items.Add(obItem); 
       obAddedItems.Add(obItem); 
      } 
      NotifyCollectionChangedEventArgs obEvtArgs = new NotifyCollectionChangedEventArgs(
       NotifyCollectionChangedAction.Add, 
       obAddedItems as System.Collections.IList); 
      base.OnCollectionChanged(obEvtArgs); 
     } 

    } 
} 
+4

मैंने पहले इस दृष्टिकोण की कोशिश की। दुर्भाग्य से यह WPF बाइंडिंग के लिए काम नहीं करेगा, क्योंकि कई वस्तुओं के लिए अधिसूचना समर्थित नहीं हैं। देखें [यह बग] (https://connect.microsoft.com/WPF/feedback/details/514922/range-actions-not-supported-in-collectionview) एमएस कनेक्ट –

4

आप ऊपर कार्यान्वयन कि भेजने के किसी भी उपयोग करते हैं एक ऐड रेंज कमांड और अवलोकन योग्यता को एक सूचीदृश्य में बांधें जिससे आपको यह ग़लत त्रुटि मिल जाएगी।

 
NotSupportedException 
    at System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e) 
    at System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) 
    at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) 

कार्यान्वयन मैं के साथ चले गए हैं रीसेट घटना में है कि अधिक समान रूप से WPF ढांचे के आसपास कार्यान्वित किया जाता है का उपयोग करता है:

public void AddRange(IEnumerable<T> collection) 
    { 
     foreach (var i in collection) Items.Add(i); 
     OnPropertyChanged("Count"); 
     OnPropertyChanged("Item[]"); 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 
+0

पर आप प्रत्येक आइटम के लिए एक ऐड के साथ जा सकते हैं, लेकिन आपका यूआई –

+0

असल में रुक जाएगा, नहीं, यह नहीं होगा - पोस्टमेसेज के रूप में, डब्ल्यूपीएफ यूआई बैचों में प्रस्तुत करता है। रीफ्रेश के लिए यूआई की जांच करने से पहले यह फ़ंक्शन समाप्त हो जाएगा। – cunningdave

+0

किसी ने भी xceeds WPF डेटाग्रिड के साथ यह कोशिश की? – springy76

0

तेजी से आप इस्तेमाल कर सकते हैं जोड़ने के लिए:

((List<Person>)this.Items).AddRange(NewItems); 
3

मैं सवाल इस तरह की कई बार देखा है, और मुझे आश्चर्य है कि क्यों यहां तक ​​कि Microsoft ObservableCollection हर जगह बढ़ावा दे रहा है और कहाँ पहले से ही एक बेहतर संग्रह उपलब्ध है thats है ..

BindingList<T>

आप सूचनाएं बंद और थोक ओपेरा करने की अनुमति देता कौन सा tions और फिर अधिसूचनाओं को चालू करें।

+1

'बाइंडिंगलिस्ट ' के बारे में बहुत अच्छी बात है लेकिन दुर्भाग्य से यह 'IObservable ' के बजाय 'IBindingList ' लागू करता है ... बाद में एमवीवीएम का उपयोग करके डब्ल्यूपीएफ अनुप्रयोगों के लिए आवश्यक है। – RonnBlack

1

एक अन्य समाधान है कि CollectionView पैटर्न के समान है:

public class DeferableObservableCollection<T> : ObservableCollection<T> 
{ 
    private int deferLevel; 

    private class DeferHelper<T> : IDisposable 
    { 
     private DeferableObservableCollection<T> owningCollection; 
     public DeferHelper(DeferableObservableCollection<T> owningCollection) 
     { 
      this.owningCollection = owningCollection; 
     } 

     public void Dispose() 
     { 
      owningCollection.EndDefer(); 
     } 
    } 

    private void EndDefer() 
    { 
     if (--deferLevel <= 0) 
     { 
      deferLevel = 0; 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
     } 
    } 

    public IDisposable DeferNotifications() 
    { 
     deferLevel++; 
     return new DeferHelper<T>(this); 
    } 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (deferLevel == 0) // Not in a defer just send events as normally 
     { 
      base.OnCollectionChanged(e); 
     } // Else notify on EndDefer 
    } 
} 
संबंधित मुद्दे