Iím hoping someone out there can point me in the right direction with a task I need to do. Iíve spent the last few hours googling for solutions, Iíve learned a lot, but Iím missing a big piece of the picture still. I wouldnít say Iím a beginner, the bulk of my experience in programming has been with c# web applications, but Iím now building my first windows app using c# .Net 2 (2005).
I need to build a view which is basically a family tree. Each node could have 0, 1 or 2 child nodes. Individual nodes need to be able to have their text formatted independently from other nodes, for instance if I click a button only one particular node should have its text changed to red. Individual nodes need to be able to handle click events. And nodes need to be connected with a plain black line, one line pointing to each child node, except for the last generation where the nodes are a one to one relationship and the nodes are in line with each other with just a single straight line in between them.
I know this can be done, Iíve seen it done before. I have a basic idea on how to build the data structure, but getting it to display on the screen has stumped me. I canít think of any existing controls that I could adapt for this except for the treeview control. But the way it shows the relationships wonít suit the job. Unless that aspect of it can be customised? Iíve been told itís a recursive binary tree, there are plenty of sample classes on the web but they only handle the storing and searching of the data. Iím more concerned with displaying it in the family tree structure. Iíve included an example attached to this thread.
Does your tree need only to be displayed, with basic select capabilities, or it needs to support additional behavior (like TreeView, or even more complex)?
In any case, you'd want to take a look at the Graphics class, you can use it to draw all kinds of stuff, including text. However, if you would draw the text by yourself, you would also need to write a complicated message/event handling system, so it might be better to use existing controls.
For example, if the simpler approach would do, you can create a Page control that derives from UserControl, and use your data to add (this.Controls.Add()) some Label-s to it - with custom fonts, appropriate locations, etc. Then you would override the OnPaint() method of your Page user control and use the Graphics class (accessible through the PaintEventArgs parameter) to draw the lines, or iconic images, or whatever.
(P.S. I was talking about System.Window.Forms, but I guess it's more or less similar with WPF - OnRender() instead of OnPaint(), and DrawingContext class instead of Graphics.)
Last edited by TheGreatCthulhu; August 17th, 2010 at 07:16 AM.
I got a bit interested with what can you do with WPF TreeView control, and I found this article - apparently, this is just what you need, if WPF is OK.
It seems that you can do pretty much what ever you can think of. (It certainly beats what I suggested above, since it would eliminate a lot of extra work and optimizations.)
Last edited by TheGreatCthulhu; August 17th, 2010 at 07:46 AM.
Just got some more insight: windows forms TreeView can apparently be customized in any way by setting it's DrawMode property a to TreeViewDrawMode.OwnerDrawAll.
You can derive from TreeView, set the property and then override OnPaint(), use Graphics to paint the lines, etc.
You might also want to call SetStyle in the constructor setting the UserPaint and AllPaintingInWmPaint flags.
Thanks heaps for your feedback. I've now had a look into the Drawing class, and having another think about GDI+ a bit more I'v had a bit of a noob epiphany and another piece of the puzzle has fit together. Every control that I've been using would use GDI+ to display itself or something similar. I also now need to have like text box functionality where you can ckick on a node and start typing in the name. So I should just build my own node control to hold the data and display it in a position relative to the parent node with a connecting line between them. e.g. this is what i have to hold the data in a tree structure (not really tested yet and needs othe changes).
private TreeNode leftBranch;
private TreeNode rightBranch;
private string storedValue;
public TreeNode(string valueToStore)
storedValue = valueToStore;
public void addLeftBranch(string valueToStore)
leftBranch = new TreeNode(valueToStore);
public void addRightBranch(string valueToStore)
rightBranch = new TreeNode(valueToStore);
public void show()
//do drawing here and call the childrens show()
Have i got the right idea? I dont know how I would get the paint event to get the graphics object from to draw on. I want to do this in the node class as i just want to call its show() and have it populate any child nodes itself and display them. So in the form i would just do something like this;
TreeNode node = new Node(34123);
it would then use that entity id and check if the entity has children, if so add the children to the node, the children would do the same and so on untill there are no more children. Then I would call the show();
it would then draw the name of the entity, call its childrens draw() to do the same and so on.
I hope i am not getting more lost.
To get the Graphics object I would just pass it to the class from the form. I'm a little lost on how to implement the event handling in the Node class.
OK, you opted to create your own tree structure. This is maybe better, because I've experimented a bit with owner-drawn windows forms TreeView, and it turns out it's a bit complicated because there are several drawing methods that interact in a way that is not well documented at MSDN, so it would take a great amount of time to get it right (at least when you draw all, and not just the text).
As for the Graphics class, you have two options - you can either (1) treat your tree as purely a data-structure, and make drawing the responsibility of the Form that displays it, or you can (2) consider the tree to be a full fledged windows forms control, that can be nested in other forms and container controls.
Going with (1), you would use the Graphics class obtained through the Form instance. The best way is probably to override the OnPaint() method, like this:
This way, you can access the form's graphics instance through the event arguments:
If you choose the approach (2), you would derive from UserControl (which is basically a fully working, customizable panel), and also it's OnPaint(). The advantage of this approach is that you can also override all the relevant OnEvent() methods to customize the tree control's response to clicks and such, and use the corresponding events from client classes, thus effectively reusing existing functionality. Container controls, such is the UserControl class, can contain other controls (the same way a form can contain buttons, labels...), so you can use this to your advantage, by using the existing Label class to draw tree nodes (it will automatically show if added as a child control), and also to handle clicks without having to check for mouse location, or to handle edit requests by putting a TextBox over a label for the duration of the edit. Or something along those lines.
You can also configure your tree user control so that it doesn't accept other controls at design time, when used in the app, potentially by another developer.
I think that UserControl will also automatically handle scroll bar placement, or at least it can be configured to do so.
As for graphical representation, what will require careful planing though, is the algorithm used to position all the nodes in an reasonably elegant manner, and the one used to draw all the connecting lines.
IMO, from what I've seen in the WPF TreeView tutorial mentioned above, WPF makes it waaaay more easier to customize, so I'd recommend going that way if possible.
I've made some progress. I went down the path of creating my own structure, but it became messy and slow very quickly. I've gone with the option of having just a simple array to hold the data, and labels in a table layoput panel. It works quite well, and resizes nicely. Event handeling is working, I have bretty much done what I need to do except for the connections lines.
My issue is that when I paint the lines they end up under the controls. I've tried a couple of diferent methods I've found on the web but cant get them to work as I'd expect them to. The only luck I've had is with drawing directly to the desktop. It seems mesy though, the lines dissapear again whenever the mouse is moved, and it's out of whack because the control positions that I use to get my drawing point are relative to the form, and not the screen.
I hope someone can give me some advise please on how to get my lines on top of all the labels, while still being able to handel click events.