I have a TreeNode class which derives from TreeNode, a TreeView class which derives from TreeView, and a custom tree nodes collection. When I try to add nodes through the code, the nodes are added and displayed properly but when I try to add nodes through the designer collection editor the desiger generates the code but it doesn't show the changes immediately. I have to build the project in order for it to display them, but the nodes counter is getting reset. I obviously want it to display the changes right when I click the OK button in the collection editor.
Also, when it hits the BtnOK_click
event, it executes the line base.Items = array;
which sets base.EditValue
value to array
and then triggers OnEditValueChanged()
. However, in the BtnOK_click
event the value of base.EditValue
changes, and when it hits OnEditValueChanged()
, the value of base.EditValue
is null for some reason.
When I try to execute a line like base.EditValue = array;
, it throws the exception: Object reference not set to an instance of an object
Here's the relevant collection editor methods:
//This is the event which triggers when the user presses the OK button in the collection editor
private void BtnOK_click(object sender, EventArgs e) {
object[] array = new object[this.treeView1.Nodes.Count];
for (int i = 0; i < array.Length; i++)
array[i] = this.treeView1.Nodes[i].Clone();
base.Items = array;
this.treeView1.Dispose();
this.treeView1 = null;
}
protected override void OnEditValueChanged() {
if (base.EditValue != null) {
object[] items = base.Items;
this.propertyGrid1.Site = new PropertyGridSite(base.Context, this.propertyGrid1);
MyTreeNode[] array = new MyTreeNode[items.Length];
for (int i = 0; i < items.Length; i++)
array[i] = (MyTreeNode)((MyTreeNode)items[i]).Clone();
this.treeView1.Nodes.Clear();
this.treeView1.Nodes.AddRange(array);
this.curNode = null;
this.btnAddChild.Enabled = false;
this.btnDelete.Enabled = false;
MyTreeView treeView = this.TreeView;
if (treeView != null)
this.SetImageProps(treeView);
if (items.Length > 0 && array[0] != null)
this.treeView1.SelectedNode = array[0];
}
}
And here is the TreeNode class Clone Method and it's relevant methods and class (I don't know if that causes the problem since this method seems to work fine):
private const string si_children = "children";
private const string si_propBag = "PropBag";
public override object Clone() {
MyTreeNode node;
SerializationInfo si;
SerializationInfo siDemo = new SerializationInfo(typeof(MyTreeNode), new MyTreeNodeFormatterConverter());
StreamingContext sc = new StreamingContext();
bool hasPropBag = false;
this.Serialize(siDemo, sc);
try {
siDemo.GetValue(si_propBag, typeof(OwnerDrawPropertyBag));
hasPropBag = true;
}
catch {
}
if (this._nodes.Count > 0 || hasPropBag) {
si = new SerializationInfo(typeof(MyTreeNode), new MyTreeNodeFormatterConverter());
foreach (SerializationEntry se in siDemo) {
if (se.Name.StartsWith(si_children))
si.AddValue(se.Name, ((MyTreeNode)se.Value).Clone(), typeof(MyTreeNode));
else if (se.Name == si_propBag)
si.AddValue(se.Name, OwnerDrawPropertyBag.Copy((OwnerDrawPropertyBag)se.Value), typeof(OwnerDrawPropertyBag));
else
si.AddValue(se.Name, se.Value, se.ObjectType);
}
node = new MyTreeNode(si, sc);
}
else
node = new MyTreeNode(siDemo, sc);
return node;
}
private class MyTreeNodeFormatterConverter : FormatterConverter {
public MyTreeNodeFormatterConverter()
: base() {
}
public new object Convert(object value, Type type) {
Type value_type;
if (value == null)
throw new ArgumentNullException("value");
value_type = value.GetType();
//Since I'm only adding nodes of type MyTreeNode, TreeNode nodes can be safely cast back to their original type MyTreeNode
if (value_type == typeof(MyTreeNode) || value_type == typeof(TreeNode))
return value as MyTreeNode;
else if (value_type == typeof(OwnerDrawPropertyBag))
return value as OwnerDrawPropertyBag;
else
return base.Convert(value, type);
}
}
protected MyTreeNode(SerializationInfo si, StreamingContext sc)
: base(si, sc) {
}
protected override void Deserialize(SerializationInfo si, StreamingContext sc) {
MyTreeNode[] children;
int base_nodes_count;
base.Deserialize(si, sc);
base_nodes_count = base.Nodes.Count;
this.Init();
if (base_nodes_count > 0) {
children = new MyTreeNode[base_nodes_count];
for (int i = 0; i < base_nodes_count; i++)
children[i] = (MyTreeNode)si.GetValue(si_children + i, typeof(MyTreeNode));
this._nodes.AddRangeBase(children);
}
}
private void Init() {
this._nodes = new MyTreeNodeCollection(this, base.Nodes);
}
I got it to display the added nodes by adding to the TreeViewDesginer the lines: