M
mlkenn
Guest
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");
}
}
}
}
Continue reading...
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");
}
}
}
}
Continue reading...