2011-12-22 14 views
26

मेरे पास ObservableCollection आइटम है जो मेरे दृश्य में सूची नियंत्रण से जुड़ा हुआ है।एक पर्यवेक्षण योग्यता में मूल्यों की एक श्रृंखला को कुशलतापूर्वक

मेरे पास ऐसी स्थिति है जहां मुझे संग्रह की शुरुआत में मूल्यों का एक हिस्सा जोड़ने की आवश्यकता है। Collection<T>.Insert दस्तावेज प्रत्येक डालने को ओ (एन) ऑपरेशन के रूप में निर्दिष्ट करता है, और प्रत्येक सम्मिलन भी CollectionChanged अधिसूचना उत्पन्न करता है।

इसलिए मैं आदर्श रूप से एक ही कदम में वस्तुओं की पूरी श्रृंखला डालना पसंद करता हूं, जिसका मतलब है अंतर्निहित सूची का केवल एक शफल, और उम्मीद है कि एक CollectionChanged अधिसूचना (संभवतः एक "रीसेट")।

Collection<T> ऐसा करने के लिए किसी भी विधि का खुलासा नहीं करता है। List<T> में InsertRange() है, लेकिन IList<T>, Collection<T> इसकी Items संपत्ति के माध्यम से खुलासा नहीं करता है।

क्या ऐसा करने के लिए कोई रास्ता है?

+0

आप संग्रह संपत्ति के लिए एक समर्थन क्षेत्र है - आप इसे करने के लिए एक नया उदाहरण आवंटित और फिर 'OnPropertyChanged' संग्रह proeprty के लिए बढ़ा सकते हैं मैन्युअल रूप से – sll

+1

संबंधित/संभव डुप्लिकेट: http: // stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each – Adam

+2

+1 यदि 'ObservableCollection' आपको क्वांटम यांत्रिकी और डबल-स्लिट प्रयोग के बारे में सोचता है। – rfmodulator

उत्तर

50

ऑब्जर्जेबल कोलेक्शन एक सुरक्षित Items संपत्ति का खुलासा करता है जो अधिसूचना अर्थशास्त्र के बिना अंतर्निहित संग्रह है। इसका मतलब है आप एक संग्रह का निर्माण कर सकते इनहेरिट ObservableCollection से करता है कि आप क्या चाहते हैं:

class RangeEnabledObservableCollection<T> : ObservableCollection<T> 
{ 
    public void InsertRange(IEnumerable<T> items) 
    { 
     this.CheckReentrancy(); 
     foreach(var item in items) 
      this.Items.Add(item); 
     this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 
} 

उपयोग:

void Main() 
{ 
    var collection = new RangeEnabledObservableCollection<int>(); 
    collection.CollectionChanged += (s,e) => Console.WriteLine("Collection changed"); 
    collection.InsertRange(Enumerable.Range(0,100)); 
    Console.WriteLine("Collection contains {0} items.", collection.Count); 
} 
+6

यह अन्य [उत्तर] (http://stackoverflow.com/questions/13302933/how -से-टालने-फायरिंग-अवलोकन योग्य-संग्रह-संग्रहित-बहु-बार-कब-आर) एक समान प्रश्न के लिए गिनती और अनुक्रमणक गुणों में परिवर्तनों को सूचित करने के लिए निम्नलिखित कोड जोड़ने का सुझाव दिया गया है: 'यह .ऑनप्रॉपर्टी चेंज (नई संपत्ति चेंजएंडअर्ट्स ("गणना")); ' ' यह .ऑनप्रॉपर्टी चेंज (नई संपत्ति चेंजएडएन्ट आर्ट्स ("आइटम []")); – bouvierr

7

ऊपर जवाब उपयोगी बनाने के लिए डब्ल्यू/प्रतिबिंब का उपयोग कर एक नया आधार वर्ग पाने ओ, यहाँ है एक उदाहरण:

public static void InsertRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items) 
{ 
    var enumerable = items as List<T> ?? items.ToList(); 
    if (collection == null || items == null || !enumerable.Any()) 
    { 
    return; 
    } 

    Type type = collection.GetType(); 

    type.InvokeMember("CheckReentrancy", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, collection, null); 
    var itemsProp = type.BaseType.GetProperty("Items", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance); 
    var privateItems = itemsProp.GetValue(collection) as IList<T>; 
    foreach (var item in enumerable) 
    { 
    privateItems.Add(item); 
    } 

    type.InvokeMember("OnPropertyChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, 
    collection, new object[] { new PropertyChangedEventArgs("Count") }); 

    type.InvokeMember("OnPropertyChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, 
    collection, new object[] { new PropertyChangedEventArgs("Item[]") }); 

    type.InvokeMember("OnCollectionChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, 
    collection, new object[]{ new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)}); 
} 
+1

उत्तराधिकारी के साथ क्या गलत है? एक नई कक्षा प्राप्त करने के बजाय प्रतिबिंब का उपयोग क्यों कर रहे हैं? – ventiseis

+3

निश्चित रूप से विरासत के साथ कुछ भी गलत नहीं है। यह सिर्फ इसके लिए एक विकल्प है। यदि आपके पास विरासत कोड का एक टन है और आपका क्रमिकरण (बाइनरी) एक पर्यवेक्षण चयन प्रकार पर निर्भर करता है तो यह उपयोगी साबित हो सकता है। उस मामले में पर्यवेक्षण चयन को बढ़ाने के लिए आसान और एक और अधिक व्यावहारिक विकल्प। – outbred

+0

हाय @outbred। क्षमा करें लेकिन आप अपने उदाहरण का "उपयोग" कैसे करते हैं।धन्यवाद – NevilleDastur

-2

उदाहरण: वांछित चरणों 0,10,20,30,40,50,60,70,80,90,100 -> मिनट = 0, अधिकतम = 100, कदम = 11

static int min = 0; 
    static int max = 100; 
    static int steps = 11; 

    private ObservableCollection<string> restartDelayTimeList = new ObservableCollection<string> (
     Enumerable.Range(0, steps).Select(l1 => (min + (max - min) * ((double)l1/(steps - 1))).ToString()) 
    ); 
3

यह answer मुझे एक डेटा ग्रिड में नई प्रविष्टियां नहीं दिखा था। यह मेरे लिए काम करता है OnCollectionChanged:

public class SilentObservableCollection<T> : ObservableCollection<T> 
{ 
    public void AddRange(IEnumerable<T> enumerable) 
    { 
     CheckReentrancy(); 

     int startIndex = Count; 

     foreach (var item in enumerable) 
      Items.Add(item); 

     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<T>(enumerable), startIndex)); 
     OnPropertyChanged(new PropertyChangedEventArgs("Count")); 
     OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); 
    } 
} 
+0

ये अधिक उपयुक्त परिवर्तन अधिसूचनाओं की तरह लगते हैं। – OttPrime

संबंधित मुद्दे