ReadOnlyObservableCollection.CollectionChanged सार्वजनिक क्यों नहीं है?


86

ReadOnlyObservableCollection.CollectionChangedसंरक्षित और सार्वजनिक क्यों नहीं है (जैसा कि संगत ObservableCollection.CollectionChangedहै)?

INotifyCollectionChangedयदि मैं इस CollectionChangedकार्यक्रम तक नहीं पहुँच सकता तो किसी संग्रह को लागू करने का क्या उपयोग है ?


1
जिज्ञासा से बाहर, आप केवल पढ़ने के लिए संग्रह को बदलने की उम्मीद क्यों करेंगे ? निश्चित रूप से तब यह केवल पढ़ा नहीं जाएगा?
workmad3

83
जवाबी सवाल: मैं एक ऑब्जर्वेबल कलैक्शन की उम्मीद क्यों नहीं करूंगा? अगर कुछ भी नहीं बदलने वाला है, तो उसे देखने का क्या फायदा है? वैसे संग्रह सबसे निश्चित रूप से बदलने जा रहा है, लेकिन मेरे पास ऐसे उपभोक्ता हैं जिन्हें केवल इसे देखने की अनुमति है। देख रहे हैं लेकिन छू नहीं रहे ...
Oskar

1
मैं हाल ही में इस मुद्दे पर अस्वस्थ हुआ। मूल रूप से ऑब्ज़र्वेबल कॉलेक्शन, इनोटिफ़ाइकल बदलाव की घटना को ठीक से लागू नहीं कर रहा है। ऐसा क्यों है कि C # एक वर्ग को इंटरफ़ेस इंटरफ़ेस तक पहुँचने की अनुमति देता है लेकिन इंटरफ़ेस विधियों को नहीं?
djskinner

35
मुझे इसके लिए अपना वोट देना होगा। क्यों दुनिया में ReadOnlyObservableCollection मौजूद है भले ही आप CollectionChanged घटनाओं की सदस्यता नहीं ले सकते? डब्ल्यूटीएफ बिंदु है? और हर कोई जो कहता रहता है कि केवल-पढ़ने वाला संग्रह कभी नहीं बदलेगा, आप जो कह रहे हैं उसके बारे में वास्तविक रूप से कठिन सोचें।
मोजोफिल्टर

9
"केवल पढ़ने" का अर्थ "अपरिवर्तनीय" नहीं है जैसा कि कुछ लगता है। इसका मतलब केवल यह है कि कोड जो केवल ऐसी संपत्ति के माध्यम से संग्रह देख सकता है उसे बदलने की अनुमति नहीं है। यह वास्तव में बदला जा सकता है जब कोड अंतर्निहित संग्रह के माध्यम से सदस्यों को जोड़ता या हटाता है। पाठकों को अभी भी यह सूचित करने में सक्षम होना चाहिए कि परिवर्तन हुए हैं, भले ही वे स्वयं संग्रह को बदल न सकें। उन्हें अभी भी खुद को बदलने के लिए प्रतिक्रिया देने की आवश्यकता हो सकती है। मैं संग्रहणीय संपत्ति को प्रतिबंधित करने के लिए कोई वैध कारण नहीं सोच सकता, जैसा कि इस मामले में किया गया है।
गिल

जवाबों:



16

मैं तुम्हारे लिए यह कैसे करना है के लिए एक रास्ता मिल गया है:

ObservableCollection<string> obsCollection = new ObservableCollection<string>();
INotifyCollectionChanged collection = new ReadOnlyObservableCollection<string>(obsCollection);
collection.CollectionChanged += new NotifyCollectionChangedEventHandler(collection_CollectionChanged);

आपको बस INOTifyCollectionChanged इंटरफ़ेस द्वारा अपने संग्रह को स्पष्ट रूप से संदर्भित करने की आवश्यकता है ।


14
कृपया नहीं कि ReadOnlyObservableCollection एक ObservableCollection के आसपास एक आवरण है - जो बदलने वाला है। ReadOnlyObservableCollection के उपभोक्ताओं को केवल इन परिवर्तनों का निरीक्षण करने की अनुमति है, न कि स्वयं कुछ भी बदलने की।
Oskar

आपको इस तथ्य पर भरोसा नहीं करना चाहिए, केवल पढ़ने के लिए संग्रह किसी भी मामले में बदलने वाला नहीं है, क्योंकि इसे "केवल पढ़ने के लिए" कहा जाता है। यह मेरी समझ है।

4
कास्टिंग समाधान के लिए +1। लेकिन जैसा कि यह केवल पढ़ने के लिए संग्रह का निरीक्षण करने के लिए तर्कसंगत नहीं है: यदि आपने केवल एक डेटाबेस तक पहुंच पढ़ी थी तो क्या आप इसे कभी नहीं बदलने की उम्मीद करेंगे?
djskinner

16
मैं नहीं देखता कि यहाँ क्या कठिनाई है। ReadOnlyObservableCollection एक वर्ग है जो एक संग्रह का निरीक्षण करने के लिए केवल एक तरीका प्रदान करता है। यदि मेरी कक्षा के पास, कहना, सत्रों का एक संग्रह है, और मैं नहीं चाहता कि लोग मेरे संग्रह से सत्रों को जोड़ या हटा सकें, लेकिन फिर भी उनका अवलोकन करें, तो ReadOnlyObservableCollection उसके लिए एकदम सही वाहन है। संग्रह केवल मेरी कक्षा के उपयोगकर्ताओं के लिए पढ़ा जाता है, लेकिन मेरे पास अपने उपयोग के लिए पढ़ने / लिखने की प्रति है।
स्कैगनर

1
ब्राउजिंग .Net का कोड ReadOnlyObservableCollectionआपको यह मिलेगा event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged:। घटना का स्पष्ट इंटरफ़ेस कार्यान्वयन।
माइक डी क्लार्क

7

मुझे पता है कि यह पोस्ट पुरानी है, हालांकि, लोगों को टिप्पणी करने से पहले .NET में इस्तेमाल किए गए पैटर्न को समझने के लिए अपना समय लेना चाहिए। एक रीड ओनली कलेक्शन मौजूदा कलेक्शन पर एक रैपर है जो उपभोक्ताओं को सीधे इसे संशोधित करने से रोकता है, ReadOnlyCollectionइसे देखें और आप देखेंगे कि यह एक रैपर है IList<T>जिस पर कोई परिवर्तनशील हो सकता है या नहीं। अपरिवर्तनीय संग्रह एक अलग मामला है और नए अपरिवर्तनीय संग्रह पुस्तकालय द्वारा कवर किया गया है

दूसरे शब्दों में, केवल पढ़ने योग्य अपरिवर्तनीय नहीं है !!!!

एक तरफ, ReadOnlyObservableCollectionइसे संक्षेप में लागू किया जाना चाहिए INotifyCollectionChanged


5

ReadOnlyObservableCollection पर परिवर्तित नोटिफिकेशन को सब्सक्राइब करने के लिए निश्चित रूप से अच्छे कारण हैं । इसलिए, अपने संग्रह को केवल INotifyCollectionChanged के रूप में कास्टिंग करने के विकल्प के रूप में , यदि आप ReadOnlyObservableCollection को उप-वर्ग करना चाहते हैं , तो निम्नलिखित एक CollectionChanged घटना तक पहुँचने के लिए एक अधिक सरल रूप से सुविधाजनक तरीका प्रदान करता है :

    public class ReadOnlyObservableCollectionWithCollectionChangeNotifications<T> : ReadOnlyObservableCollection<T>
{
    public ReadOnlyObservableCollectionWithCollectionChangeNotifications(ObservableCollection<T> list)
        : base(list)
    {
    }

    event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged2
    {
        add { CollectionChanged += value; }
        remove { CollectionChanged -= value; }
    }
}

इसने मेरे लिए पहले भी अच्छा काम किया है।


5

आप Microsoft कनेक्ट पर बग प्रविष्टि के लिए वोट कर सकते हैं जो इस समस्या का वर्णन करता है: https://connect.microsoft.com/VisualStudio/feedback/details/641395/readonlyobservablecollection-t-collectionchanged-event-should-be-public

अपडेट करें:

कनेक्ट पोर्टल Microsoft द्वारा बंद कर दिया गया है। तो ऊपर दिया गया लिंक अब काम नहीं करता है।

मेरा विन एप्लीकेशन फ्रेमवर्क (WAF) लाइब्रेरी एक समाधान प्रदान करता है: ReadOnlyObservableList वर्ग:

public class ReadOnlyObservableList<T> 
        : ReadOnlyObservableCollection<T>, IReadOnlyObservableList<T>
{
    public ReadOnlyObservableList(ObservableCollection<T> list)
        : base(list)
    {
    }

    public new event NotifyCollectionChangedEventHandler CollectionChanged
    {
        add { base.CollectionChanged += value; }
        remove { base.CollectionChanged -= value; }
    }

    public new event PropertyChangedEventHandler PropertyChanged
    {
        add { base.PropertyChanged += value; }
        remove { base.PropertyChanged -= value; }
    }
}

कनेक्ट को सेवानिवृत्त कर दिया गया है। मैं पूरी तरह से होगा मतदान किया
findusl

1

जैसा कि पहले से ही उत्तर दिया गया है, आपके पास दो विकल्प हैं: या तो आप स्पष्ट रूप से कार्यान्वित किए गए ईवेंट का उपयोग ReadOnlyObservableCollection<T>करने के लिए इंटरफ़ेस INotifyCollectionChangedको कास्ट CollectionChangedकर सकते हैं, या आप अपना स्वयं का रैपर क्लास बना सकते हैं, जो एक बार कंस्ट्रक्टर में होता है और केवल लिपटे हुए ईवेंट को हुक करता है ReadOnlyObservableCollection<T>

इस मुद्दे को अभी तक तय नहीं किया गया है:

जैसा कि आप स्रोत कोड से देख सकते हैं , ReadOnlyObservableCollection<T>एक सार्वजनिक, गैर-सील (यानी अंतर्निहित) वर्ग है, जहां घटनाओं को चिह्नित किया जाता है protected virtual

अर्थात्, ऐसी कक्षाओं के साथ संकलित कार्यक्रम हो सकते हैं ReadOnlyObservableCollection<T>, जो ओवरराइड की गई घटनाओं की परिभाषा के साथ हैं, लेकिन protectedदृश्यता के साथ। उन कार्यक्रमों में अमान्य कोड शामिल होगा, जब घटना की दृश्यता को publicआधार वर्ग में बदल दिया जाता है, क्योंकि यह व्युत्पन्न वर्गों में किसी घटना की दृश्यता को प्रतिबंधित करने की अनुमति नहीं है।

इसलिए, दुर्भाग्य से, बाद में होने वाली protected virtualघटनाओं publicमें एक द्विआधारी-ब्रेकिंग परिवर्तन होता है, और इसलिए यह बहुत अच्छे तर्क के बिना नहीं किया जाएगा, जो मुझे डर है "मुझे हैंडलर संलग्न करने के लिए एक बार ऑब्जेक्ट को डालना है" बस नहीं है।

स्रोत: निक गुएर्रा द्वारा गीथहब टिप्पणी, 19 अगस्त, 2015


0

यह Google पर शीर्ष हिट था, इसलिए मुझे लगा कि अन्य लोगों द्वारा इसे देखने की स्थिति में मैं अपना समाधान जोड़ूंगा।

उपरोक्त जानकारी का उपयोग करके ( INotifyCollectionChanged को कास्ट करने की आवश्यकता के बारे में ), मैंने पंजीकरण करने और अपंजीकृत करने के लिए दो विस्तार विधियाँ बनाईं।

मेरा समाधान - विस्तार विधियाँ

public static void RegisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
    collection.CollectionChanged += handler;
}

public static void UnregisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
    collection.CollectionChanged -= handler;
}

उदाहरण

IThing.cs

public interface IThing
{
    string Name { get; }
    ReadOnlyObservableCollection<int> Values { get; }
}

एक्सटेंशन के तरीकों का उपयोग करना

public void AddThing(IThing thing)
{
    //...
    thing.Values.RegisterCollectionChanged(this.HandleThingCollectionChanged);
}

public void RemoveThing(IThing thing)
{
    //...
    thing.Values.UnregisterCollectionChanged(this.HandleThingCollectionChanged);
}

ओपी का समाधान

public void AddThing(IThing thing)
{
    //...
    INotifyCollectionChanged thingCollection = thing.Values;
    thingCollection.CollectionChanged += this.HandleThingCollectionChanged;
}

public void RemoveThing(IThing thing)
{
    //...
    INotifyCollectionChanged thingCollection = thing.Values;
    thingCollection.CollectionChanged -= this.HandleThingCollectionChanged;
}

वैकल्पिक 2

public void AddThing(IThing thing)
{
    //...
    (thing.Values as INotifyCollectionChanged).CollectionChanged += this.HandleThingCollectionChanged;
}

public void RemoveThing(IThing thing)
{
    //...
    (thing.Values as INotifyCollectionChanged).CollectionChanged -= this.HandleThingCollectionChanged;
}

0

समाधान

ReadOnlyObservableCollection.CollectionChanged को उजागर नहीं किया गया है (अन्य उत्तरों में उल्लिखित वैध कारणों के लिए), तो चलिए अपना स्वयं का रैपर वर्ग बनाते हैं जो इसे उजागर करता है:

/// <summary>A wrapped <see cref="ReadOnlyObservableCollection{T}"/> that exposes the internal <see cref="CollectionChanged"/>"/>.</summary>
public class ObservableReadOnlyCollection<T> : ReadOnlyObservableCollection<T>
{
    public new NotifyCollectionChangedEventHandler CollectionChanged;

    public ObservableReadOnlyCollection(ObservableCollection<T> list) : base(list) { /* nada */ }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) => 
        CollectionChanged?.Invoke(this, args);
}

व्याख्या

लोगों ने पूछा है कि आप केवल-पढ़ने के लिए संग्रह में बदलाव क्यों करना चाहते हैं, इसलिए मैं कई मान्य स्थितियों में से एक को समझाऊंगा; जब केवल पढ़ने के लिए संग्रह एक निजी आंतरिक संग्रह लपेटता है जो बदल सकता है।

यहाँ एक ऐसा परिदृश्य है:

मान लीजिए कि आपके पास एक सेवा है जो सेवा के बाहर से आंतरिक संग्रह में आइटम जोड़ने और हटाने की अनुमति देती है। अब मान लीजिए कि आप संग्रह के मूल्यों को उजागर करना चाहते हैं, लेकिन आप उपभोक्ताओं को सीधे संग्रह में हेरफेर नहीं करना चाहते हैं; इसलिए आप आंतरिक संग्रह को एक में लपेटते हैं ReadOnlyObservableCollection

ध्यान दें कि आंतरिक संग्रह के साथ आंतरिक संग्रह को लपेटने के लिए निर्माणकर्ता द्वारा ReadOnlyObservableCollectionप्राप्त करने के लिए मजबूर किया जाता ObservableCollectionहै ReadOnlyObservableCollection

अब मान लीजिए कि आप आंतरिक संग्रह में परिवर्तन होने पर (और इसलिए जब ReadOnlyObservableCollectionपरिवर्तन होता है) सेवा के उपभोक्ताओं को सूचित करना चाहते हैं । अपने खुद के कार्यान्वयन रोलिंग के बजाय आप सिर्फ बेनकाब करना चाहते हैं CollectionChangedकी ReadOnlyObservableCollection। के कार्यान्वयन के बारे में एक धारणा बनाने के लिए उपभोक्ता को मजबूर करने के बजाय ReadOnlyObservableCollection, आप बस ReadOnlyObservableCollectionइस रिवाज के साथ स्वैप करते हैं ObservableReadOnlyCollection, और आप कर रहे हैं।

इसके साथ ObservableReadOnlyCollectionछुपाता है ReadOnlyObservableCollection.CollectionChanged, और बस सभी संग्रह को बदलकर किसी भी संलग्न ईवेंट हैंडलर में बदल जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.