Hi all,
I've been trying to write some classes, so when I have a parent-child
relationship, such as with Folders in my application, I don't have to
remember to add a parent reference, as well as adding to the child
collection, eg:
parent.Children.Add(child);
child.Parent = parent;
And I've come up with the below (I've included my test, and three classes).
It seems to work, but I have two questions....
1. Does this look like the best way of doing this?
2. I now want to extend this to support multiple lists (eg, my folders can
contain both folders, and messages. Messages can have child messages, and
therefore have both a parent folder, and a parent message), eg.
folder.ChildFolders // Returns List<TreeItem<Folder>>
folder.Messages // Returns List<TreeItem<Message>>
message.ParentMessage // Returns TreeItem<Message>
message.ParentFolder // Returns TreeItem<Folder>
Or should I create a base class that represents the entire tree (Folders and
Messages)? Though this way, I'd have a single child list, and would need to
add properties, like .ChildFolders, which would filter the .Children list!
I know it looks like a lot of code here, but it's just 3 classes and my
command line test. If you paste it into VS, it'll look dead simple :)
Any thoughts or suggestions?
Thanks,
Danny Tuppeny
namespace MyApplication
{
class Program
{
static void Main(string[] args)
{
Test1();
Test2();
}
static void Test1()
{
Folder parent = new Folder();
Folder child = new Folder();
child.Parent = parent;
if (parent.Children.Contains(child))
{
Console.WriteLine("Test succeeded");
}
else
{
Console.WriteLine("Test failed");
}
}
static void Test2()
{
Folder parent = new Folder();
Folder child = new Folder();
parent.Children.Add(child);
if (parent == child.Parent)
{
Console.WriteLine("Test succeeded");
}
else
{
Console.WriteLine("Test failed");
}
}
}
public class ChildList<T> : List<T>
{
public event EventHandler<ChildListEventArgs<T>> Added;
public event EventHandler<ChildListEventArgs<T>> Removed;
public class ChildListEventArgs<T> : EventArgs
{
public T Item;
public ChildListEventArgs(T item)
{
Item = item;
}
}
public new void Add(T item)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
added(this, new ChildListEventArgs<T>(item));
base.Add(item);
}
public new void AddRange(IEnumerable<T> collection)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
{
foreach (T item in collection)
{
added(this, new ChildListEventArgs<T>(item));
}
}
base.AddRange(collection);
}
public new void Insert(int index, T item)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
added(this, new ChildListEventArgs<T>(item));
base.Insert(index, item);
}
public new void InsertRange(int index, IEnumerable<T> collection)
{
EventHandler<ChildListEventArgs<T>> added = Added;
if (added != null)
{
foreach (T item in collection)
{
added(this, new ChildListEventArgs<T>(item));
}
}
base.InsertRange(index, collection);
}
public new bool Remove(T item)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
removed(this, new ChildListEventArgs<T>(item));
return base.Remove(item);
}
public new void RemoveAll(Predicate<T> match)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
{
foreach (T item in base.FindAll(match))
{
removed(this, new ChildListEventArgs<T>(item));
}
}
base.RemoveAll(match);
}
public new void RemoveAt(int index)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
removed(this, new ChildListEventArgs<T>(base[index]));
base.RemoveAt(index);
}
new void RemoveRange(int index, int count)
{
EventHandler<ChildListEventArgs<T>> removed = Removed;
if (removed != null)
{
foreach (T item in base.GetRange(index, count))
{
removed(this, new ChildListEventArgs<T>(item));
}
}
base.RemoveAt(index);
}
}
public class TreeItem<T>
{
TreeItem<T> parent;
ChildList<TreeItem<T>> children;
public TreeItem()
{
children = new ChildList<TreeItem<T>>();
children.Added += delegate(object sender,
ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent =
this; };
children.Removed += delegate(object sender,
ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent =
null; };
}
public TreeItem<T> Parent
{
get { return parent; }
set
{
if (parent != value)
{
if (parent != null)
{
// This automagically unsets the internal parent
parent.children.Remove(this);
}
if (value != null)
{
// This automagically sets the internal parent
value.children.Add(this);
}
}
}
}
public ChildList<TreeItem<T>> Children
{
get { return children; }
}
}
public class Folder : TreeItem<Folder>
{
string name;
public Folder()
{
}
public string Name
{
get { return name; }
set { name = value; }
}
}
} 4 4392
um... HOw 'bout a nice simple:
parent.AddChild(child);
where AddChild is defined as
public AddChild(IChild pChild)
{
this.Children.Add(child);
child.Parent = this;
}
--
Truth,
James Curran
[erstwhile VC++ MVP]
Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
"Danny Tuppeny" <gr****@dannytuppeny.commmmmm> wrote in message
news:43***********************@ptn-nntp-reader04.plus.net... Hi all,
I've been trying to write some classes, so when I have a parent-child relationship, such as with Folders in my application, I don't have to remember to add a parent reference, as well as adding to the child collection, eg:
parent.Children.Add(child); child.Parent = parent;
And I've come up with the below (I've included my test, and three
classes). It seems to work, but I have two questions....
1. Does this look like the best way of doing this?
2. I now want to extend this to support multiple lists (eg, my folders can contain both folders, and messages. Messages can have child messages, and therefore have both a parent folder, and a parent message), eg.
folder.ChildFolders // Returns List<TreeItem<Folder>> folder.Messages // Returns List<TreeItem<Message>>
message.ParentMessage // Returns TreeItem<Message> message.ParentFolder // Returns TreeItem<Folder>
Or should I create a base class that represents the entire tree (Folders
and Messages)? Though this way, I'd have a single child list, and would need
to add properties, like .ChildFolders, which would filter the .Children list!
I know it looks like a lot of code here, but it's just 3 classes and my command line test. If you paste it into VS, it'll look dead simple :)
Any thoughts or suggestions?
Thanks,
Danny Tuppeny
namespace MyApplication { class Program { static void Main(string[] args) { Test1(); Test2(); }
static void Test1() { Folder parent = new Folder(); Folder child = new Folder();
child.Parent = parent;
if (parent.Children.Contains(child)) { Console.WriteLine("Test succeeded"); } else { Console.WriteLine("Test failed"); } }
static void Test2() { Folder parent = new Folder(); Folder child = new Folder();
parent.Children.Add(child);
if (parent == child.Parent) { Console.WriteLine("Test succeeded"); } else { Console.WriteLine("Test failed"); } } }
public class ChildList<T> : List<T> { public event EventHandler<ChildListEventArgs<T>> Added; public event EventHandler<ChildListEventArgs<T>> Removed;
public class ChildListEventArgs<T> : EventArgs { public T Item; public ChildListEventArgs(T item) { Item = item; } }
public new void Add(T item) { EventHandler<ChildListEventArgs<T>> added = Added; if (added != null) added(this, new ChildListEventArgs<T>(item));
base.Add(item); }
public new void AddRange(IEnumerable<T> collection) { EventHandler<ChildListEventArgs<T>> added = Added; if (added != null) { foreach (T item in collection) { added(this, new ChildListEventArgs<T>(item)); } }
base.AddRange(collection); }
public new void Insert(int index, T item) { EventHandler<ChildListEventArgs<T>> added = Added; if (added != null) added(this, new ChildListEventArgs<T>(item));
base.Insert(index, item); }
public new void InsertRange(int index, IEnumerable<T> collection) { EventHandler<ChildListEventArgs<T>> added = Added; if (added != null) { foreach (T item in collection) { added(this, new ChildListEventArgs<T>(item)); } }
base.InsertRange(index, collection); }
public new bool Remove(T item) { EventHandler<ChildListEventArgs<T>> removed = Removed; if (removed != null) removed(this, new ChildListEventArgs<T>(item));
return base.Remove(item); }
public new void RemoveAll(Predicate<T> match) { EventHandler<ChildListEventArgs<T>> removed = Removed; if (removed != null) { foreach (T item in base.FindAll(match)) { removed(this, new ChildListEventArgs<T>(item)); } }
base.RemoveAll(match); }
public new void RemoveAt(int index) { EventHandler<ChildListEventArgs<T>> removed = Removed; if (removed != null) removed(this, new ChildListEventArgs<T>(base[index]));
base.RemoveAt(index); }
new void RemoveRange(int index, int count) { EventHandler<ChildListEventArgs<T>> removed = Removed; if (removed != null) { foreach (T item in base.GetRange(index, count)) { removed(this, new ChildListEventArgs<T>(item)); } }
base.RemoveAt(index); } }
public class TreeItem<T> { TreeItem<T> parent; ChildList<TreeItem<T>> children;
public TreeItem() { children = new ChildList<TreeItem<T>>(); children.Added += delegate(object sender, ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent
= this; }; children.Removed += delegate(object sender, ChildList<TreeItem<T>>.ChildListEventArgs<TreeItem <T>> e) { e.Item.parent
= null; }; }
public TreeItem<T> Parent { get { return parent; } set { if (parent != value) { if (parent != null) { // This automagically unsets the internal parent parent.children.Remove(this); } if (value != null) { // This automagically sets the internal parent value.children.Add(this); } } } }
public ChildList<TreeItem<T>> Children { get { return children; } } }
public class Folder : TreeItem<Folder> { string name;
public Folder() { }
public string Name { get { return name; } set { name = value; } }
} }
"James Curran" <ja*********@mvps.org> wrote in message
news:ON**************@TK2MSFTNGP09.phx.gbl... um... HOw 'bout a nice simple:
parent.AddChild(child);
where AddChild is defined as
public AddChild(IChild pChild) { this.Children.Add(child); child.Parent = this; }
Because that relies on remember not to use .Children.Add :)
If I can do some extra work now, which reduces the number of bugs my
software might include, it's worth it! :)
Though I guess, returning Children as a ReadOnlyList (or whatever it's
called) and then having an Add method would work.. I don't think it's as
nice though :)
OK, plan 2 (A bit stripped down, but you should get the idea)
interface IParent
{
}
interface IChild
{
IParent Parent;
}
public class ChildList<T> : List<T>
{
private IParent oOwner;
public ChildList(IParent pOwner) : base()
{
oOwner = pOwner;
}
public new void Add(T item)
{
base.Add(item);
item.Parent = oOwner;
}
}
public class Folder : IParent, IChild
{
private IParent oParent;
prinvate ChildList<Folder> children;
public Folder()
{
children = ChildList<Folder>(this);
}
}
--
Truth,
James Curran
[erstwhile VC++ MVP]
Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
"Danny Tuppeny" <gr****@dannytuppeny.commmmmm> wrote in message
news:43***********************@ptn-nntp-reader03.plus.net... "James Curran" <ja*********@mvps.org> wrote in message news:ON**************@TK2MSFTNGP09.phx.gbl... um... HOw 'bout a nice simple:
parent.AddChild(child);
where AddChild is defined as
public AddChild(IChild pChild) { this.Children.Add(child); child.Parent = this; }
Because that relies on remember not to use .Children.Add :)
If I can do some extra work now, which reduces the number of bugs my software might include, it's worth it! :)
Though I guess, returning Children as a ReadOnlyList (or whatever it's called) and then having an Add method would work.. I don't think it's as nice though :)
"James Curran" <ja*********@mvps.org> wrote in message
news:%2****************@TK2MSFTNGP14.phx.gbl... OK, plan 2 (A bit stripped down, but you should get the idea)
<snip>
That's better - thanks :-) This discussion thread is closed Replies have been disabled for this discussion. Similar topics
3 posts
views
Thread by Volodymyr Sadovyy |
last post: by
|
3 posts
views
Thread by Arvie |
last post: by
|
reply
views
Thread by gs-code-review-bounces |
last post: by
|
6 posts
views
Thread by andrew blah |
last post: by
|
3 posts
views
Thread by Filippo |
last post: by
|
239 posts
views
Thread by Eigenvector |
last post: by
|
3 posts
views
Thread by JeanDean |
last post: by
|
10 posts
views
Thread by Jo |
last post: by
| |
reply
views
Thread by corey |
last post: by
| | | | | | | | | | |