এতে আইটেম পরিবর্তিত হলে পর্যবেক্ষণযোগ্য সংগ্রহের বিষয়টি লক্ষ্য করা যাচ্ছে না (এমনকি আইএনটিফাইপ্রোটার্টি চেঞ্জডও রয়েছে)


167

এই কোডটি কেন কাজ করে না কেউ কি জানে:

public class CollectionViewModel : ViewModelBase {  
    public ObservableCollection<EntityViewModel> ContentList
    {
        get { return _contentList; }
        set 
        { 
            _contentList = value; 
            RaisePropertyChanged("ContentList"); 
            //I want to be notified here when something changes..?
            //debugger doesn't stop here when IsRowChecked is toggled
        }
     }
}

public class EntityViewModel : ViewModelBase
{

    private bool _isRowChecked;

    public bool IsRowChecked
    {
        get { return _isRowChecked; }
        set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
    }
}

ViewModelBaseRaisePropertyChangedইত্যাদির জন্য সমস্ত কিছু ধারণ করে এবং এটি এই সমস্যা ব্যতীত অন্য সব কিছুর জন্য কাজ করছে ..


উত্তর:


119

আপনি যখন সংগ্রহের অভ্যন্তরে কোনও মান পরিবর্তন করেন তখন কন্টেন্টলিস্টের সেট পদ্ধতিটি কল করা হবে না, পরিবর্তে আপনাকে কালেকশনেড ইভেন্টের ফায়ারিং সন্ধান করা উচিত।

public class CollectionViewModel : ViewModelBase
{          
    public ObservableCollection<EntityViewModel> ContentList
    {
        get { return _contentList; }
    }

    public CollectionViewModel()
    {
         _contentList = new ObservableCollection<EntityViewModel>();
         _contentList.CollectionChanged += ContentCollectionChanged;
    }

    public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        //This will get called when the collection is changed
    }
}

ঠিক আছে, আজকের দু'বারে আমাকে এমএসডিএন ডকুমেন্টেশন ভুল বলে দংশিত করেছে। আমি আপনাকে যে লিঙ্কটি দিয়েছি তাতে এটি বলে:

ঘটে যখন কোনও আইটেম যুক্ত করা হয়, অপসারণ করা হয়, পরিবর্তন করা হয়, সরানো হয় বা পুরো তালিকাটি রিফ্রেশ হয়।

কিন্তু কোনও আইটেম পরিবর্তিত হলে এটি আসলে আগুন দেয় না । আমার ধারণা, আপনার আরও একটি ব্রুটফোর্ড পদ্ধতি প্রয়োজন হবে:

public class CollectionViewModel : ViewModelBase
{          
    public ObservableCollection<EntityViewModel> ContentList
    {
        get { return _contentList; }
    }

    public CollectionViewModel()
    {
         _contentList = new ObservableCollection<EntityViewModel>();
         _contentList.CollectionChanged += ContentCollectionChanged;
    }

    public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach(EntityViewModel item in e.OldItems)
            {
                //Removed items
                item.PropertyChanged -= EntityViewModelPropertyChanged;
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach(EntityViewModel item in e.NewItems)
            {
                //Added items
                item.PropertyChanged += EntityViewModelPropertyChanged;
            }     
        }       
    }

    public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //This will get called when the property of an object inside the collection changes
    }
}

আপনি এই অনেক প্রয়োজন যাচ্ছি যদি আপনার নিজস্ব উপশ্রেণী করতে পারেন ObservableCollectionযে ট্রিগার CollectionChangedঘটনা যখন একজন সদস্য তার আরম্ভ করে PropertyChangedস্বয়ংক্রিয়ভাবে ইভেন্টটি (এটা বলে মত ডকুমেন্টেশনে উচিত ...)


দুঃখিত হ্যারিস, তবে বিষয়বস্তুসংযোগের পরিবর্তিত কন্ট্রাকশন যাতে কল হয়ে যায় সে জন্য আমার কী ইভেন্টটি অ্যান্টিভিউমোডেলে গুলি চালাতে হবে?
জোসেফ জুন। মেলিটুকুনেল

36
মনে রাখবেন যে আপনি যদি ইভেন্ট ম্যানেজমেন্টটি নিজে প্রয়োগ করতে না চান তবে আপনি পর্যবেক্ষণযোগ্য সংগ্রহ <এনটিভিভিউমোডেল> এর জায়গায় একটি বন্ডিংলিস্ট <এন্টিভিউমোডেল> ব্যবহার করতে পারেন। এরপরে এটি স্বয়ংক্রিয়ভাবে এন্টিভিউমোডেল P প্রপার্টিচেন্জড ইভেন্টগুলিকে তালিকাচ্যাঞ্জড ইভেন্ট হিসাবে ফরোয়ার্ড করে দেবে যেখানে তালিকাচেন্জড টাইপ == আইটেম চেঞ্জড।
mjeanes

15
এই সমস্ত শব্দটি আপনার বোঝার উপর নির্ভর করে না changed? এর অর্থ এই হতে পারে যে সংগ্রহে থাকা উপাদানগুলির মধ্যে একটির সম্পত্তি পরিবর্তিত হয়েছে (যা আমি মনে করি আপনি এটি ব্যাখ্যা করছেন) বা এর অর্থ হতে পারে যে সংগ্রহের উপাদানগুলির মধ্যে একটির পরিবর্তে এটি অন্যরকম উদাহরণ দিয়ে প্রতিস্থাপন করা হয়েছে ( এটি আমার ব্যাখ্যা)। যদিও সম্পূর্ণরূপে নিশ্চিত নয় - এটি আরও খতিয়ে দেখতে হবে।
বেলুগাবব

10
আমি যদি প্রার্থনা করি তবে কী হবে _contentList.Clear()? কেউ এর থেকে সাবস্ক্রাইব করবেন না PropertyChanged!
পাওলো মোরেত্তি

2
@ পাওলো: এটি ঠিক, ContentCollectionChangedকেবল অ্যাড / রিমুভাল পরিচালনা করে এবং প্রতিস্থাপন / পুনরায় সেট করা পরিচালনা করে না। আমি পোস্টটি সম্পাদনা করে ঠিক করার চেষ্টা করব। সাইমন তার উত্তরে এটি যেভাবে করে তা সঠিক।
মাইক ফুচস

178

এখানে একটি ড্রপ-ইন ক্লাস রয়েছে যা উপ-শ্রেণীর পর্যবেক্ষণযোগ্য সংগ্রহ এবং যখন তালিকার আইটেমটির কোনও সম্পত্তি পরিবর্তিত হয় তখন আসলে একটি রিসেট ক্রিয়া উত্থাপন করে। এটি প্রয়োগ করার জন্য সমস্ত আইটেম প্রয়োগ করে INotifyPropertyChanged

এখানে সুবিধাটি হ'ল আপনি এই শ্রেণীর সাথে ডেটা বাঁধতে পারেন এবং আপনার সমস্ত বাইন্ডিং আপনার আইটেমের বৈশিষ্ট্যগুলিতে পরিবর্তনের সাথে আপডেট হবে।

public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
    where T : INotifyPropertyChanged
{
    public TrulyObservableCollection()
    {
        CollectionChanged += FullObservableCollectionCollectionChanged;
    }

    public TrulyObservableCollection(IEnumerable<T> pItems) : this()
    {
        foreach (var item in pItems)
        {
            this.Add(item);
        }
    }

    private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (Object item in e.NewItems)
            {
                ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
            }
        }
        if (e.OldItems != null)
        {
            foreach (Object item in e.OldItems)
            {
                ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
            }
        }
    }

    private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {            
        NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
        OnCollectionChanged(args);
    }
}

4
আমি নিজেই অনুরূপ কিছু বাস্তবায়িত করার কারণ পেয়েছি, তবে পরিবর্তে নোটফিডক্লিকেশনচেনজড অ্যাকশন ব্যবহার করুন I পুনরায় সেট করুন .পরিবর্তন করুন: নতুন বিজ্ঞপ্তি-কল্পনাচেন্জডভেন্টআরগস (নোটফ্লেক্লিকেশনচেনজড অ্যাকশন।পরিবর্তন, আইটেম, আইটেম, সূচিপত্র (আইটেম))।
ক্রিস

2
আমার সমস্যার দুর্দান্ত সমাধান - ধন্যবাদ! যারা একটি পর্যবেক্ষণের সাথে তাদের পর্যবেক্ষণযোগ্য সংগ্রহ তৈরি করেছেন তাদের জন্য আপনি এমন একটি নির্মাতা যুক্ত করতে পারেন যা সমস্ত আইটেম এবং প্রপার্টি চেঞ্জড যুক্ত করেও এটি বিভক্ত করে তোলে।
গাভিন

4
এখানে একটি সম্ভাব্য মেমরি ফুটো আছে - সংগ্রহটি উল্লেখযোগ্যভাবে পরিবর্তিত হলে রিসেট ইভেন্ট হয়, যেমন ক্লিয়ার। এটি ঘটলে আপনার আইএনপিসির কোনও হ্যান্ডলার সদস্যতা বাতিল হবে না।
চার্লস ম্যাজার

6
এটি একটি ঠিকঠাক বাস্তবায়ন তবে এটির একটি বড় সমস্যা রয়েছে - এটি NotifyCollectionChangedAction.Replaceএকটি ভাল ধারণা নয়, কারণ তবে আপনি কোনও আইটেম পরিবর্তনের কারণে কোনও আইটেম প্রতিস্থাপন করা বা ইভেন্টের মধ্যে পার্থক্য করতে পারবেন না। এটা অনেক ভালো যখন আপনি সংজ্ঞায়িত পায় public event PropertyChangedEventHandler CollectionItemChanged;এবং তারপর ItemPropertyChangedDothis.CollectionItemChanged?.Invoke(sender, e);
hyankov

4
এই শ্রেণীর ব্যবহারের উদাহরণ কি কেউ পেয়েছে?
ডিকোডার94

23

আমি যা আশা করি তা একত্রে রেখেছি অন্যান্য উত্তরের কয়েকটি কৌশল সহ একটি দুর্দান্ত দৃ rob় সমাধান। এটি থেকে প্রাপ্ত একটি নতুন শ্রেণি ObservableCollection<>, যা আমি কল করছিFullyObservableCollection<>

এটিতে নিম্নলিখিত বৈশিষ্ট্য রয়েছে:

  • এটি একটি নতুন ইভেন্ট যুক্ত করে ItemPropertyChanged,। আমি ইচ্ছাকৃতভাবে এটিকে বিদ্যমান থেকে পৃথক করে রেখেছি CollectionChanged:
    • পিছিয়ে সামঞ্জস্যতা সহায়তা।
    • নতুন এর ItemPropertyChangedEventArgsসাথে আরও প্রাসঙ্গিক বিবরণ দেওয়া যেতে পারে : PropertyChangedEventArgsসংগ্রহের মধ্যে মূল এবং সূচক।
  • এটা তোলে থেকে সব কনস্ট্রাকটর প্রতিলিপি ObservableCollection<>
  • এটি ObservableCollection<>.Clear()সম্ভাব্য মেমরি ফুটো এড়িয়ে তালিকাকে পুনরায় সেট করা ( ) সঠিকভাবে পরিচালনা করে ।
  • এটি ইভেন্টটির OnCollectionChanged()আরও সংস্থান-নিবিড় সাবস্ক্রিপশনের পরিবর্তে বেস শ্রেণীর উপরের পরিবর্তনগুলি করে CollectionChanged

কোড

সম্পূর্ণ .csফাইল নিম্নলিখিত। মনে রাখবেন যে সি # 6 এর কয়েকটি বৈশিষ্ট্য ব্যবহৃত হয়েছে তবে এটির ব্যাকপোর্ট করা মোটামুটি সহজ হওয়া উচিত:

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

namespace Utilities
{
    public class FullyObservableCollection<T> : ObservableCollection<T>
        where T : INotifyPropertyChanged
    {
        /// <summary>
        /// Occurs when a property is changed within an item.
        /// </summary>
        public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;

        public FullyObservableCollection() : base()
        { }

        public FullyObservableCollection(List<T> list) : base(list)
        {
            ObserveAll();
        }

        public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
        {
            ObserveAll();
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove ||
                e.Action == NotifyCollectionChangedAction.Replace)
            {
                foreach (T item in e.OldItems)
                    item.PropertyChanged -= ChildPropertyChanged;
            }

            if (e.Action == NotifyCollectionChangedAction.Add ||
                e.Action == NotifyCollectionChangedAction.Replace)
            {
                foreach (T item in e.NewItems)
                    item.PropertyChanged += ChildPropertyChanged;
            }

            base.OnCollectionChanged(e);
        }

        protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
        {
            ItemPropertyChanged?.Invoke(this, e);
        }

        protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
        {
            OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
        }

        protected override void ClearItems()
        {
            foreach (T item in Items)
                item.PropertyChanged -= ChildPropertyChanged;

            base.ClearItems();
        }

        private void ObserveAll()
        {
            foreach (T item in Items)
                item.PropertyChanged += ChildPropertyChanged;
        }

        private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            T typedSender = (T)sender;
            int i = Items.IndexOf(typedSender);

            if (i < 0)
                throw new ArgumentException("Received property notification from item not in collection");

            OnItemPropertyChanged(i, e);
        }
    }

    /// <summary>
    /// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
    /// </summary>
    public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
    {
        /// <summary>
        /// Gets the index in the collection for which the property change has occurred.
        /// </summary>
        /// <value>
        /// Index in parent collection.
        /// </value>
        public int CollectionIndex { get; }

        /// <summary>
        /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
        /// </summary>
        /// <param name="index">The index in the collection of changed item.</param>
        /// <param name="name">The name of the property that changed.</param>
        public ItemPropertyChangedEventArgs(int index, string name) : base(name)
        {
            CollectionIndex = index;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
        public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
        { }
    }
}

ইউনাইট টেস্ট

সুতরাং আপনি যে পরিবর্তনগুলি করতে পারেন তা পরীক্ষা করতে পারেন (এবং আমি প্রথম স্থানে কী পরীক্ষা করেছি দেখুন!), আমি আমার নুনিট পরীক্ষার ক্লাসটিও অন্তর্ভুক্ত করেছি। স্পষ্টতই, নিচের কোডটি কেবল FullyObservableCollection<T>আপনার প্রকল্পে ব্যবহারের জন্য প্রয়োজনীয় নয়

এনবি পরীক্ষার শ্রেণি BindableBaseপ্রয়োগের জন্য PRISM থেকে ব্যবহার করে INotifyPropertyChanged। মূল কোড থেকে PRISM এর উপর কোনও নির্ভরতা নেই।

using NUnit.Framework;
using Utilities;
using Microsoft.Practices.Prism.Mvvm;
using System.Collections.Specialized;
using System.Collections.Generic;

namespace Test_Utilities
{
    [TestFixture]
    public class Test_FullyObservableCollection : AssertionHelper
    {
        public class NotifyingTestClass : BindableBase
        {
            public int Id
            {
                get { return _Id; }
                set { SetProperty(ref _Id, value); }
            }
            private int _Id;

            public string Name
            {
                get { return _Name; }
                set { SetProperty(ref _Name, value); }
            }
            private string _Name;

        }

        FullyObservableCollection<NotifyingTestClass> TestCollection;
        NotifyingTestClass Fred;
        NotifyingTestClass Betty;
        List<NotifyCollectionChangedEventArgs> CollectionEventList;
        List<ItemPropertyChangedEventArgs> ItemEventList;

        [SetUp]
        public void Init()
        {
            Fred = new NotifyingTestClass() { Id = 1, Name = "Fred" };
            Betty = new NotifyingTestClass() { Id = 4, Name = "Betty" };

            TestCollection = new FullyObservableCollection<NotifyingTestClass>()
                {
                    Fred,
                    new NotifyingTestClass() {Id = 2, Name = "Barney" },
                    new NotifyingTestClass() {Id = 3, Name = "Wilma" }
                };

            CollectionEventList = new List<NotifyCollectionChangedEventArgs>();
            ItemEventList = new List<ItemPropertyChangedEventArgs>();
            TestCollection.CollectionChanged += (o, e) => CollectionEventList.Add(e);
            TestCollection.ItemPropertyChanged += (o, e) => ItemEventList.Add(e);
        }

        // Change existing member property: just ItemPropertyChanged(IPC) should fire
        [Test]
        public void DetectMemberPropertyChange()
        {
            TestCollection[0].Id = 7;

            Expect(CollectionEventList.Count, Is.EqualTo(0));

            Expect(ItemEventList.Count, Is.EqualTo(1), "IPC count");
            Expect(ItemEventList[0].PropertyName, Is.EqualTo(nameof(Fred.Id)), "Field Name");
            Expect(ItemEventList[0].CollectionIndex, Is.EqualTo(0), "Collection Index");
        }


        // Add new member, change property: CollectionPropertyChanged (CPC) and IPC should fire
        [Test]
        public void DetectNewMemberPropertyChange()
        {
            TestCollection.Add(Betty);

            Expect(TestCollection.Count, Is.EqualTo(4));
            Expect(TestCollection[3].Name, Is.EqualTo("Betty"));

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Add), "Action (add)");
            Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
            Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
            Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Betty), "NewItems[0] dereference");

            CollectionEventList.Clear();      // Empty for next operation
            ItemEventList.Clear();

            TestCollection[3].Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count");

            Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count");
            Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Betty), "Collection Index dereference");
        }


        // Remove member, change property: CPC should fire for removel, neither CPC nor IPC should fire for change
        [Test]
        public void CeaseListentingWhenMemberRemoved()
        {
            TestCollection.Remove(Fred);

            Expect(TestCollection.Count, Is.EqualTo(2));
            Expect(TestCollection.IndexOf(Fred), Is.Negative);

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Remove), "Action (remove)");
            Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
            Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");
            Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");

            CollectionEventList.Clear();      // Empty for next operation
            ItemEventList.Clear();

            Fred.Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
        }


        // Move member in list, change property: CPC should fire for move, IPC should fire for change
        [Test]
        public void MoveMember()
        {
            TestCollection.Move(0, 1);

            Expect(TestCollection.Count, Is.EqualTo(3));
            Expect(TestCollection.IndexOf(Fred), Is.GreaterThan(0));

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Move), "Action (move)");
            Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
            Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
            Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");
            Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Fred), "NewItems[0] dereference");

            CollectionEventList.Clear();      // Empty for next operation
            ItemEventList.Clear();

            Fred.Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");

            Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count (post change)");
            Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Fred), "Collection Index dereference");
        }


        // Clear list, chnage property: only CPC should fire for clear and neither for property change
        [Test]
        public void ClearList()
        {
            TestCollection.Clear();

            Expect(TestCollection.Count, Is.EqualTo(0));

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Reset), "Action (reset)");
            Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
            Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");

            CollectionEventList.Clear();      // Empty for next operation
            ItemEventList.Clear();

            Fred.Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
        }
    }
}

1
আমি কী ভুল করছি তা আমি জানি না, তবে এটি আমার পক্ষে কার্যকর হয় না। আমি আমার তালিকাভিউটিকে আপনার সংগ্রহে আবদ্ধ করছি তবে আমি যখন ভিতরে থাকা আইটেমগুলির বৈশিষ্ট্যগুলি আপডেট করি তখন তালিকাগুলি আপডেট হয় না, এমনকি 'আমি সমস্ত ঘটনা গুলি চালানো দেখতে পাচ্ছি। আমি PRISM গ্রন্থাগারটিও ব্যবহার করছি ...
রেনাটো পরেরিরা

@ রেনাটো, নতুন ইভেন্টে আপনি কিছু করেছেন? ইভেন্টগুলিতে ListViewপ্রতিক্রিয়া জানাবে CollectionChangedকারণ এটি তাদের সম্পর্কে জানে। ItemPropertyChangedএটি একটি মানহীন সংযোজন, সুতরাং আপনার এটি সম্পর্কে এটি শেখানো দরকার। দ্রুত এবং নোংরা ফিক্স হিসাবে, আপনি কেবল CollectionChangedইভেন্টটিকে গুলি করার চেষ্টা করতে পারেন (বা তার পরিবর্তে ) ItemPropertyChangedOnItemPropertyChanged()। উত্তরে বর্ণিত কারণে আমি তাদের পৃথক করে রেখেছি, তবে আপনার ব্যবহারের ক্ষেত্রে এটি আপনার প্রয়োজন অনুসারে কেবল সম্ভব করতে পারে।
বব সামার্স

20

এটি উপরোক্ত ধারণাগুলি ব্যবহার করে তবে এটি একটি 'বেশি সংবেদনশীল' সংগ্রহ তৈরি করেছে:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections;

namespace somethingelse
{
    public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
    {
        // this collection also reacts to changes in its components' properties

        public ObservableCollectionEx() : base()
        {
            this.CollectionChanged +=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCollectionEx_CollectionChanged);
        }

        void ObservableCollectionEx_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach(T item in e.OldItems)
                {
                    //Removed items
                    item.PropertyChanged -= EntityViewModelPropertyChanged;
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach(T item in e.NewItems)
                {
                    //Added items
                    item.PropertyChanged += EntityViewModelPropertyChanged;
                }     
            }       
        }

        public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //This will get called when the property of an object inside the collection changes - note you must make it a 'reset' - dunno why
            NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            OnCollectionChanged(args);
        }
    }
}

12

পর্যবেক্ষণযোগ্য সংগ্রহ সংগ্রহ সংগ্রহের ইভেন্ট হিসাবে স্বতন্ত্র আইটেম পরিবর্তনের প্রচার করবে না। আপনাকে প্রতিটি ইভেন্টে সাবস্ক্রাইব করতে হবে এবং ম্যানুয়ালি এটিকে ফরোয়ার্ড করতে হবে, অথবা আপনি বাইন্ডিংলিস্ট [টি] শ্রেণিটি পরীক্ষা করতে পারেন , যা এটি আপনার জন্য করবে।


আপনি কেবলমাত্র কেন এটির উল্লেখ করেছেন? +1
এটিজস

7

সত্যই অবজারভেশন সংগ্রহ সংযোজন ইভেন্ট "আইটেমপ্রোটার্টি চেঞ্জড" এ যুক্ত হয়েছে:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; // ObservableCollection
using System.ComponentModel; // INotifyPropertyChanged
using System.Collections.Specialized; // NotifyCollectionChangedEventHandler
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObservableCollectionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // ATTN: Please note it's a "TrulyObservableCollection" that's instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main.
            // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
            TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>();
            Trades.Add(new Trade { Symbol = "APPL", Qty = 123 });
            Trades.Add(new Trade { Symbol = "IBM", Qty = 456});
            Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 });

            Trades.CollectionChanged += Trades_CollectionChanged;
            Trades.ItemPropertyChanged += PropertyChangedHandler;
            Trades.RemoveAt(2);

            Trades[0].Qty = 999;

            Console.WriteLine("Hit any key to exit");
            Console.ReadLine();

            return;
        }

        static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
        {
            Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty);
            return;
        }

        static void Trades_CollectionChanged(object sender, EventArgs e)
        {
            Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
            return;
        }
    }

    #region TrulyObservableCollection
    public class TrulyObservableCollection<T> : ObservableCollection<T>
        where T : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler ItemPropertyChanged;

        public TrulyObservableCollection()
            : base()
        {
            CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
        }

        void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (Object item in e.NewItems)
                {
                    (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
                }
            }
            if (e.OldItems != null)
            {
                foreach (Object item in e.OldItems)
                {
                    (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
                }
            }
        }

        void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            OnCollectionChanged(a);

            if (ItemPropertyChanged != null)
            {
                ItemPropertyChanged(sender, e);
            }
        }
    }
    #endregion

    #region Sample entity
    class Trade : INotifyPropertyChanged
    {
        protected string _Symbol;
        protected int _Qty = 0;
        protected DateTime _OrderPlaced = DateTime.Now;

        public DateTime OrderPlaced
        {
            get { return _OrderPlaced; }
        }

        public string Symbol
        {
            get
            {
                return _Symbol;
            }
            set
            {
                _Symbol = value;
                NotifyPropertyChanged("Symbol");
            }
        }

        public int Qty
        {
            get
            {
                return _Qty;
            }
            set
            {
                _Qty = value;
                NotifyPropertyChanged("Qty");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
#endregion
}

আপনি সরাসরি পর্যবেক্ষণযোগ্য সংগ্রহ থেকে প্রপার্টি চেঞ্জড ব্যবহার করতে পারেন, যেহেতু এটি INotifyPropertyChanged প্রয়োগ করে।
ডিয়েটার মীমকেন

6

আমি আমার নিজের ওসি বাস্তবায়নের জন্য জ্যাক কেনিয়োনস উত্তরটি ব্যবহার করেছি, তবে এটি কার্যকর করার জন্য আমাকে যে পরিবর্তন করতে হয়েছিল তা আমি উল্লেখ করতে চাই। পরিবর্তে:

    if (e.Action == NotifyCollectionChangedAction.Remove)
    {
        foreach(T item in e.NewItems)
        {
            //Removed items
            item.PropertyChanged -= EntityViewModelPropertyChanged;
        }
    }

আমি এটি ব্যবহার করেছি:

    if (e.Action == NotifyCollectionChangedAction.Remove)
    {
        foreach(T item in e.OldItems)
        {
            //Removed items
            item.PropertyChanged -= EntityViewModelPropertyChanged;
        }
    }

দেখে মনে হচ্ছে "e.NewItems" যদি ক্রিয়া হয় তবে শূন্য উত্পাদন করে em


আমি মনে করি ই-অ্যাকশন == প্রতিস্থাপন
জে কে

6

এই বিষয়টিতে আমার 2 সেন্ট যোগ করুন। পর্যবেক্ষণযোগ্য সংগ্রহের সাথে দেখা হিসাবে সত্যই অবজার্ভেশন সংগ্রহের জন্য অন্য দুটি নির্মাণকারীর দরকার পড়েছিল:

public TrulyObservableCollection()
        : base()
    {
        HookupCollectionChangedEvent();
    }

    public TrulyObservableCollection(IEnumerable<T> collection)
        : base(collection)
    {
        foreach (T item in collection)
            item.PropertyChanged += ItemPropertyChanged;

        HookupCollectionChangedEvent();
    }

    public TrulyObservableCollection(List<T> list)
        : base(list)
    {
        list.ForEach(item => item.PropertyChanged += ItemPropertyChanged);

        HookupCollectionChangedEvent();
    }

    private void HookupCollectionChangedEvent()
    {
        CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollectionChanged);
    }

5

আমি জানি যে এই দলের জন্য আমি অনেক দেরি করেছি, তবে সম্ভবত - এটি কারওর পক্ষে সহায়তা করবে ..

এখানে আপনি আমার পর্যবেক্ষণযোগ্য সংগ্রহ সংগ্রহ বাস্তবায়ন করতে পারেন। এর কিছু বৈশিষ্ট্য রয়েছে:

  • এটি পর্যবেক্ষণযোগ্য সংগ্রহ থেকে সমস্ত কিছু সমর্থন করে
  • এটি থ্রেড নিরাপদ
  • এটি আইটেমপ্রপার্টি চেঞ্জড ইভেন্টটিকে সমর্থন করে (আইটেম.প্রपर्টিচেন্জড আইটেমটি বহিস্কারের সময় এটি উত্থাপিত হয়)
  • এটি ফিল্টারগুলিকে সমর্থন করে (সুতরাং, আপনি পর্যবেক্ষণযোগ্য সংগ্রহ সংগ্রহ তৈরি করতে পারেন, এর উত্স হিসাবে অন্য সংগ্রহটি পাস করতে পারেন, এবং সহজ প্রিকিকেট দিয়ে ফিল্টার করুন P আরও বেশি - ফিল্টার INotifyPropertyChanged ইন্টারফেসের মাধ্যমে আইটেমের পরিবর্তনগুলি ট্র্যাক করে।

অবশ্যই, কোনও মন্তব্য প্রশংসা করা হয়;)


1
Спасибо спасибо! ভাগ করে নেওয়ার জন্য অনেক ধন্যবাদ! আমার নিজের প্রয়োগ না লিখে আপনি আমাকে কয়েক ঘন্টা বাঁচিয়েছেন! :)
আলেকজান্ডার

@ আলেকজান্ডার আপনি খুব ভাল আছেন :)
7'13

@ চপিকাডজে, আমি আপনার পর্যবেক্ষণযোগ্য সংগ্রহের সিএস ফাইল ডাউনলোড করতে অক্ষম আপনি দয়া করে এটি ঠিক করতে পারেন। ধন্যবাদ
শেক্স

লিঙ্কটি মারা গেছে।

5

আমি যদি জানি যদি কেবলমাত্র আমরা আমাদের সংগ্রহে আইটেমগুলি যুক্ত / মোছা বা সরাতে পারি তখনই পর্যবেক্ষণযোগ্য সংগ্রহটি ইভেন্টটি তৈরি করে। যখন আমরা সংগ্রহ আইটেম সংগ্রহের কিছু সম্পত্তি এক সাথে আপডেট করি তখন এটি সম্পর্কে সিগন্যাল দেয় না এবং ইউআই আপডেট হবে না will

আপনি একই সাথে আপনার মডেল শ্রেণিতে INotifyPropertyChange প্রয়োগ করতে পারেন । এবং সংগ্রহের আইটেমে কিছু প্রাইটি আপডেট করার পরে এটি স্বয়ংক্রিয়ভাবে ইউআই আপডেট করবে।

public class Model:INotifyPropertyChange
{
//...
}

এবং চেয়ে

public ObservableCollection<Model> {get; set;}

আমার ক্ষেত্রে আমি এই সংগ্রহের জন্য তালিকাভিউ থেকে বাঁধাই ব্যবহার করেছি এবং আইটেম্পেম্পলেটে মডেল সম্পত্তিতে বাইন্ডিং সেট করেছিলাম এবং এটি ভাল কাজ করে।

এখানে কিছু স্নিপেট আছে

উইন্ডোজ এক্সএএমএল:

<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ListView 
        Margin="10"
        BorderBrush="Black"
        HorizontalAlignment="Center"
        SelectedItem="{Binding SelectedPerson}"
        ItemsSource="{Binding Persons}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Label Content="{Binding Name}"/>
                    <Label Content="-"/>
                    <Label Content="{Binding Age}"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <Grid 
        Grid.Row="1"
        VerticalAlignment="Center"
        HorizontalAlignment="Center">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Label 
            VerticalAlignment="Center"
            Content="Name:"/>
        <TextBox
            Text="{Binding SelectedPerson.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
            Margin="10"
            Grid.Column="1" 
            Width="100"/>
        <Label 
            VerticalAlignment="Center"
            Grid.Row="1"
            Content="Age:"/>
        <TextBox
            Text="{Binding SelectedPerson.Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
            Margin="10"
            Grid.Row="1"
            Grid.Column="1" 
            Width="100"/>


    </Grid>
</Grid>

মডেল কোড উদাহরণ:

public class PersonModel:INotifyPropertyChanged
{
    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public int Age
    {
        get => _age;
        set
        {
            _age = value;
            OnPropertyChanged();
        }
    }

    private string _name;
    private int _age;
    //INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

এবং ভিউমোডেল বাস্তবায়ন:

 public class ViewModel:INotifyPropertyChanged
{
    public ViewModel()
    {
        Persons = new ObservableCollection<PersonModel>
        {
            new PersonModel
            {
                Name = "Jack",
                Age = 30
            },
            new PersonModel
            {
                Name = "Jon",
                Age = 23
            },
            new PersonModel
            {
                Name = "Max",
                Age = 23
            },
        };
    }

    public ObservableCollection<PersonModel> Persons { get;}

    public PersonModel SelectedPerson
    {
        get => _selectedPerson;
        set
        {
            _selectedPerson = value;
            OnPropertyChanged();
        }
    }

    //INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private PersonModel _selectedPerson;
}

2

আমি ব্যবহার করেছি স্ট্যান্ডার্ড পর্যবেক্ষণযোগ্য সংগ্রহের সহজ সমাধান:

আপনার সম্পত্তিতে যুক্ত করবেন না বা এর অভ্যন্তরীণ আইটেমগুলি সরাসরি পরিবর্তন করুন, পরিবর্তে, এর মতো কিছু অস্থায়ী সংগ্রহ তৈরি করুন

ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>();

এবং আইটেম যুক্ত বা tmpList পরিবর্তন করুন,

tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example
tmpList[0].IsRowChecked= true; //Example
...

তারপরে এ্যাসাইনমেন্টের মাধ্যমে এটিকে আপনার আসল সম্পত্তিতে দিন।

ContentList=tmpList;

এটি পুরো সম্পত্তি পরিবর্তন করবে যা আপনার প্রয়োজন অনুসারে INotifyPropertyChanged বিজ্ঞপ্তির কারণ ঘটবে।


1

আমি এই সমাধানটি চেষ্টা করে দেখি, তবে যখন সংগ্রহ পরিবর্তন হয়, তখন প্রতিটি আইটেম যুক্ত করা বা পরিবর্তিত হয় তা কেবল রাইসপ্রপার্টি চেঞ্জ ("উত্সগ্রুপগ্রিডভিউ") এর মতো আমার জন্য কাজ করে।

সমস্যাটি হ'ল:

public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
     NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
    OnCollectionChanged(args);
}

বিজ্ঞপ্তি সংকলন পরিবর্তন করুন han এই ক্রিয়াকলাপটি পুনরায় সেট করুন গোষ্ঠীভুক্ত সমস্ত আইটেমের একটি সম্পূর্ণ রিবাইন্ড তৈরি করুন, রাইসপ্রপার্টিচেনজডের সমতুল্য। আপনি যখন এটি ব্যবহার করেন গ্রিডভিউয়ের সমস্ত গ্রুপ সতেজ করা।

যদি আপনি, কেবলমাত্র নতুন আইটেমের গ্রুপ ইউআইতে রিফ্রেশ করতে চান, আপনি রিসেট ক্রিয়াটি ব্যবহার করবেন না, আপনাকে এরকম কিছু দিয়ে পুনরাবৃত্তিতে একটি অ্যাড ক্রিয়া অনুকরণ করতে হবে:

void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{         
    var index = this.IndexOf((T)sender);

    this.RemoveAt(index);
    this.Insert(index, (T)sender);

    var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
    OnCollectionChanged(a);
}

আমার ইংরাজির দ্বারা দুঃখিত, এবং বেস কোডের জন্য ধন্যবাদ :), আমি আশা করি এটি কাউকে helps _ ^ সহায়তা করবে ^

Enjoi !!


1

উপরের সমাধানের জন্য এখানে একটি এক্সটেনশন পদ্ধতি ...

public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list)
     where T : INotifyPropertyChanged
{
    var newList = new TrulyObservableCollection<T>();

    if (list != null)
    {
        list.ForEach(o => newList.Add(o));
    }

    return newList;
}  

আপনি উত্তরটি ব্যাখ্যা করতে চাইতে পারেন
geedubb

1
এখানে একটি লিঙ্ক রয়েছে যা এক্সটেনশন পদ্ধতিগুলি বর্ণনা করে। ডকস.মাইক্রোসফট.ওন
ডটনেট /

1

একটি পর্যবেক্ষণযোগ্য সংগ্রহ বা ট্রুয়ালি অবজারভেবল কালেকশনের পরিবর্তে, একটি বাইন্ডলিস্ট ব্যবহার করে রিসেটবাইন্ডিংস পদ্ধতিটি কল করার বিষয়ে বিবেচনা করুন।

উদাহরণ স্বরূপ:

private BindingList<TfsFile> _tfsFiles;

public BindingList<TfsFile> TfsFiles
{
    get { return _tfsFiles; }
    set
    {
        _tfsFiles = value;
        NotifyPropertyChanged();
    }
}

একটি ইভেন্ট দেওয়া হয়েছে, যেমন একটি ক্লিক ক্লিক করে আপনার কোডটি দেখতে পাবেন:

foreach (var file in TfsFiles)
{
    SelectedFile = file;
    file.Name = "Different Text";
    TfsFiles.ResetBindings();
}

আমার মডেলটি এরকম দেখাচ্ছে:

namespace Models
{
    public class TfsFile 
    {
        public string ImagePath { get; set; }

        public string FullPath { get; set; }

        public string Name { get; set; }

        public string Text { get; set; }

    }
}

1
এই পদ্ধতির বিষয়ে ভাল তথ্য BindingList, তবে এই পদ্ধতির একটি সীমাবদ্ধতা রয়েছে যা অন্যান্য উত্তরগুলি পরাস্ত করে: এই কৌশলটি কোডে পরিবর্তিত হওয়া মান এবং যেখানে একটি কল যুক্ত করা ResetBindings()যায় তার উপর নির্ভর করে । অপরিবর্তনীয় কোডের মতো বা অন্য একটি নিয়ন্ত্রণে বাঁধাইয়ের মাধ্যমে তালিকার বস্তুগুলি অন্য উপায়ে পরিবর্তিত হলে অন্যান্য উত্তরগুলির বেশিরভাগই কাজ করবে।
বব সমারস

1

পর্যবেক্ষণযোগ্য সংগ্রহের তালিকায় অন-চেঞ্জ ট্রিগার করতে

  1. নির্বাচিত আইটেমের সূচক পান
  2. পিতা-মাতার কাছ থেকে আইটেমটি সরান
  3. প্যারেন্টে একই সূচীতে আইটেমটি যুক্ত করুন

উদাহরণ:

int index = NotificationDetails.IndexOf(notificationDetails);
NotificationDetails.Remove(notificationDetails);
NotificationDetails.Insert(index, notificationDetails);

0

বাস্তবায়নটির আমার সংস্করণটি এখানে। এটি একটি ত্রুটি যাচাই করে এবং নিক্ষেপ করে, যদি তালিকার মধ্যে থাকা বস্তুগুলি INotifyPropertyChanged প্রয়োগ করে না, তাই বিকাশকালে সমস্যাটি ভুলতে পারবেন না। বাইরে আপনি তালিকার আইটেম চেঞ্জড ইভেন্টটি ব্যবহার করেন তা তালিকা বা তালিকার আইটেম নিজেই পরিবর্তন হয়েছে কিনা তা নির্ধারণ করে।

public class SpecialObservableCollection<T> : ObservableCollection<T>
{
    public SpecialObservableCollection()
    {
        this.CollectionChanged += OnCollectionChanged;
    }

    void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        AddOrRemoveListToPropertyChanged(e.NewItems,true); 
        AddOrRemoveListToPropertyChanged(e.OldItems,false); 
    }

    private void AddOrRemoveListToPropertyChanged(IList list, Boolean add)
    {
        if (list == null) { return; }
        foreach (object item in list)
        {
            INotifyPropertyChanged o = item as INotifyPropertyChanged;
            if (o != null)
            {
                if (add)  { o.PropertyChanged += ListItemPropertyChanged; }
                if (!add) { o.PropertyChanged -= ListItemPropertyChanged; }
            }
            else
            {
                throw new Exception("INotifyPropertyChanged is required");
            }
        }
    }

    void ListItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        OnListItemChanged(this, e);
    }

    public delegate void ListItemChangedEventHandler(object sender, PropertyChangedEventArgs e);

    public event ListItemChangedEventHandler ListItemChanged;

    private void OnListItemChanged(Object sender, PropertyChangedEventArgs e)
    {
        if (ListItemChanged != null) { this.ListItemChanged(this, e); }
    }


}

0

কোড 2 লাইন সহজ সমাধান। শুধু কপি নির্মাণকারী ব্যবহার করুন। ট্রুয়েলঅবার্সেবল কালেকশন ইত্যাদি লেখার দরকার নেই

উদাহরণ:

        speakers.list[0].Status = "offline";
        speakers.list[0] = new Speaker(speakers.list[0]);

অনুলিপি নির্মাণকারী ছাড়া অন্য পদ্ধতি। আপনি সিরিয়ালাইজেশন ব্যবহার করতে পারেন।

        speakers.list[0].Status = "offline";
        //speakers.list[0] = new Speaker(speakers.list[0]);
        var tmp  = JsonConvert.SerializeObject(speakers.list[0]);
        var tmp2 = JsonConvert.DeserializeObject<Speaker>(tmp);
        speakers.list[0] = tmp2;

0

প্রাসঙ্গিক সংগ্রহগুলিতে আইটেম সম্পত্তি পরিবর্তনের জন্য কোনও হ্যান্ডলারকে সহজেই নিবন্ধকরণ করতে আপনি এই এক্সটেনশন পদ্ধতিটিও ব্যবহার করতে পারেন। এই পদ্ধতিটি আইএনটিফাইডকলেকশন পরিবর্তনকারী সমস্ত সংগ্রহগুলিতে স্বয়ংক্রিয়ভাবে যুক্ত হবে যা আইএনটিফাইপ্রোটার্টি চেঞ্জড প্রয়োগ করে এমন আইটেম ধারণ করে:

public static class ObservableCollectionEx
{
    public static void SetOnCollectionItemPropertyChanged<T>(this T _this, PropertyChangedEventHandler handler)
        where T : INotifyCollectionChanged, ICollection<INotifyPropertyChanged> 
    {
        _this.CollectionChanged += (sender,e)=> {
            if (e.NewItems != null)
            {
                foreach (Object item in e.NewItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged += handler;
                }
            }
            if (e.OldItems != null)
            {
                foreach (Object item in e.OldItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged -= handler;
                }
            }
        };
    }
}

ব্যবহারবিধি:

public class Test
{
    public static void MyExtensionTest()
    {
        ObservableCollection<INotifyPropertyChanged> c = new ObservableCollection<INotifyPropertyChanged>();
        c.SetOnCollectionItemPropertyChanged((item, e) =>
        {
             //whatever you want to do on item change
        });
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.