简体   繁体   中英

ObservableCollection “CollectionChanged” not firing in OutProc Session state

I'm using an ObservableCollection in an asp.net application, By using "CollectionChanged" event i'm able to get added / delted values. For this purpose i store the object in session (InProc) everyting is working fine here.

Now the problem is the moment i changed the session to outproc (DB) , Collection_CollectionChanged stoped firing (Button2_Click). I think something has to be done with serialization. Appricate any help on this.

Usage of the example: Click button1 first & then Button 2 , both button 1 & 2 events are there in aspx code behind

  [Serializable]
    public class School
    {
        public School()
        {
            studentList = new ObservableCollection<Student>();            
            studentList.CollectionChanged += Collection_CollectionChanged;
        }
        public string SchoolName { get; set;}
        public ObservableCollection<Student> studentList { get; set; }
        public void Collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
           if (e.Action == NotifyCollectionChangedAction.Add)
            {
                var result= "add";
            }
           else if (e.Action == NotifyCollectionChangedAction.Remove)
           {
               var result=  "del";
           }
        }
    }

    [Serializable]
    public class Student
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    //Code in .aspx.cs Page
    protected void Button1_Click(object sender, EventArgs e)
    {
        School school = new School();
        school.SchoolName = "Benie";
        school.studentList.Add(new Student() { FirstName = "a", LastName = "a1" });
        school.studentList.Add(new Student() { FirstName = "b", LastName = "b1" });
        Session["school"] = school;
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        School school = Session["school"] as School;
        //Not working in Out Proc session, Working in InProc session
        school.studentList.RemoveAt(1);
    }

I suspect that the CollectionChanged event is not hooked because the object is beeing created via serialization (strange but possible I think) or the Button1_Click is not hooked after serialization (higher possibility because you don't do this in the constructor, but I read your question otherwise)

To solve this you can try to implement ISerializable for your School-class (don't forget the constructor) and hook the event in the serialization-constructor too.

I agree that the problem is definitely serialization, specifically the fact that the Student object is wrapped by ObservableCollection. If you want to continue using that approach you can implement custom serialization yourself.

Kent Bogart has a post regarding this exact scenario and how to implement custom serialization on ObservableCollections. Take a look at it here.

The problem is, that the CollectionChanged event is not marked as "non-serializable". Therefore, after deserialization the CollectionChanged is null . The solution frome here

[Serializable]
public class SObservableCollection<T> : ObservableCollection<T>, 
    INotifyPropertyChanged
{
    [field:NonSerialized]
    public override event NotifyCollectionChangedEventHandler CollectionChanged;

    [field: NonSerialized]
    private PropertyChangedEventHandler _propertyChangedEventHandler;

    event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
    {
        add
        {
            _propertyChangedEventHandler = Delegate.Combine(_propertyChangedEventHandler, value) as PropertyChangedEventHandler;
        }
        remove
        {
            _propertyChangedEventHandler = Delegate.Remove(_propertyChangedEventHandler, value) as PropertyChangedEventHandler;
        }
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler handler = CollectionChanged;

        if (handler != null)
        {
            handler(this, e);
        }
    }

    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = _propertyChangedEventHandler;

        if (handler != null)
        {
            handler(this, e);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM