Quantcast
Channel: Windows Forms Data Controls and Databinding forum
Viewing all articles
Browse latest Browse all 2535

BindingSource and INotifyPropertyChanged memory leak

$
0
0

I am having issue with memory leak with BindingSource and INotifyPropertyChanged.  I have simplified the issue to the following example.  I have 2 classes, ClassA and ClassB, which each implement INotifyPropertyChanged.  ClassA has ClassB as propertyB.  I have 2 BindingSources, bindingSource1 and bindingSource2.  BindingSource1 datasource is ClassA, and BindingSource2 datasource is bindingSource1, datamember propertyB.  When I change the value of a property on ClassA, this seems to have the side effect of an event subscription to the PropertyChangedEvent on ClassB (see TestLoop method below).  I think these are never released, in the real app the UI hung and I had a million System.ComponentModel.PropertyChangedEventHandler objects shown with !DumpHeap -stat.  In the real app, bindingSource1 datasource is a bindinglist for a combobox instead of just the single classA object, and when you change the combobox selection then the controls bound to bindinglist2 also update, I just simplified to single object here to show the problem.  What am I doing wrong? 

Here is the code:

    public partial class Form1 : Form
    {
        private ClassA m_a;
        public Form1()
        {
            InitializeComponent();
            TestSetup();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            TestLoop();
        }

        private void TestSetup()
        {
            m_a = new ClassA();
            m_a.propertyB = new ClassB();
            bindingSource1.DataSource = m_a;
            bindingSource2.DataSource = bindingSource1;
            bindingSource2.DataMember = "propertyB";
        }

        private void TestLoop()
        {
            for (int n = 0; n < 10; n++)
            {
                m_a.property1 = n;
            }
            Console.WriteLine("InvocationListLength = {0}", m_a.propertyB.GetInvocationListLength());
        }

        public class ClassA : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged(string sPropertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(sPropertyName));
                }
            }
            private int m_property1 = 0;
            private ClassB m_propertyB = new ClassB();
            public ClassA()
            {
            }
            public ClassB propertyB
            {
                get { return m_propertyB; }
                set
                {
                    m_propertyB = value;
                    NotifyPropertyChanged("propertyB");
                }
            }
            public int property1
            {
                get { return m_property1; }
                set
                {
                    m_property1 = value;
                    NotifyPropertyChanged("property1");
                }
            }
        }

        public class ClassB : INotifyPropertyChanged
        {
            private bool m_propertyx = false;
            public ClassB()
            {
            }
            public event PropertyChangedEventHandler PropertyChanged
            {
                add { _handler += value; }
                remove { _handler -= value; }
            }
            private PropertyChangedEventHandler _handler;
            private void NotifyPropertyChanged(string sPropertyName)
            {
                if (_handler != null)
                {
                    _handler(this, new PropertyChangedEventArgs(sPropertyName));
                }
            }
            public int GetInvocationListLength()
            {
                if (_handler == null)
                {
                    return 0;
                }
                else
                {
                    Delegate[] aList = _handler.GetInvocationList();
                    return aList.Length;
                }
            }
            public bool propertyx
            {
                get { return m_propertyx; }
                set
                {
                    m_propertyx = value;
                    NotifyPropertyChanged("propertyx");
                }
            }
        }
    }


Viewing all articles
Browse latest Browse all 2535

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>