|
-
Aug 20th, 2011, 12:17 PM
#1
[Ideas wanted] Options view control - child options
Hi,
I am in need of a form that shows various options, exactly like the Options in Visual Studio. Since there are so many options I too want them categorized, with a TreeView to the left taking care of showing the right category.
The usual 'easy' approach here would be to just place a TreeView control on the form, add some nodes, and give those nodes a tag or key that corresponds to a panel or UserControl with the options for that category.
Since there will be a lot of options however, this is not really feasible design-wise; the form would be cluttered with possibly 50 panels, all of which I would need to select and bring to front from time to time to add controls to them that represent the options.
So I decided to create a custom control that does exactly that. The control is very similar to my Wizard usercontrol, users can add OptionsPanels at design time, which inherit Panel and simply represent one panel of options. When they do, the panel is added to a container panel, and at the same time a TreeNode is added to a TreeView. The control uses a custom ControlDesigner to handle design-time clicks in the Treeview, selecting a different node would select and bring to front the corresponding panel, allowing the user to add the controls he wants.
Due to the design time support the problem of having 50 panels is no longer present, only one panel will be visible at a time and selecting the right panel is as simple as selecting the corresponding TreeNode, just as during run-time.
Anyway, I got all this working, but only for a single 'level' of categories. As you can see in the Visual Studio options, there can be multiple levels of categories. For example, the Environment node has a bunch of children, where each child represents one 'options panel'. There can even be deeper nesting, see the Text Editor node for example.
I am having trouble designing this feature and would appreciate some help or ideas.
Let me begin by drawing out the basics of how my control works so far.
The main control is an OptionsView control, which contains a SplitContainer with a TreeView to the left and a OptionsPanelContainer to the right. The OptionsPanelContainer is merely a Panel to which only OptionsPanel controls can be added, and which raises events when this happens, as well as when OptionsPanels are removed from it.
An OptionsPanel also inherits Panel, and these are the actual panels the users will see in the control, one for each option category.
For now, each OptionsPanel has exactly one corresponding TreeNode (and vice versa). In the Visual Studio options, each 'parent' category usually has a 'General' node as the first child, and the parent and this General node show the same option panel, but I am ignoring that for the moment.
The OptionsView control has a property Panels that returns the ControlCollection (Controls property) of the OptionsPanelContainer (in other words: it returns a collection of OptionsPanels that are in this container panel).
vb.net Code:
<Editor(GetType(Designers.OptionsPanelCollectionEditor), GetType(UITypeEditor))> _ <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _ Public ReadOnly Property Panels As Control.ControlCollection Get Return Me.PanelContainer.Controls End Get End Property
A custom CollectionEditor for this property takes care of the designer: even though the property type is ControlCollection, the CollectionEditor knows it should create instances of the OptionsPanel control instead of just Controls.
When it does this, a corresponding TreeNode is also created and its Tag property is set to the OptionsPanel. Vice versa, the Node property of the OptionsPanel is set to the node. Hence the node and panel both know their corresponding object.
vb.net Code:
Public Class OptionsPanelCollectionEditor Inherits System.ComponentModel.Design.CollectionEditor Public Sub New(type As Type) MyBase.New(type) End Sub Protected Overrides Function CreateCollectionItemType() As System.Type Return GetType(OptionsPanel) End Function Protected Overrides Function CreateInstance(ByVal itemType As System.Type) As Object If itemType Is GetType(OptionsPanel) Then ' Use the IDesignerHost service to create a new component ' This way it's editable during design-time Dim designerHost = DirectCast(Me.GetService(GetType(IDesignerHost)), IDesignerHost) Dim panel = DirectCast(designerHost.CreateComponent(GetType(OptionsPanel)), OptionsPanel) Dim view = DirectCast(Me.Context.Instance, OptionsView) ' Also set some properties panel.Owner = view panel.Dock = DockStyle.Fill Dim node As New TreeNode(panel.Name) node.Tag = panel panel.SetNode(node) Return panel End If Return MyBase.CreateInstance(itemType) End Function End Class
Finally, when an OptionsPanel is added to the OptionsPanelContainer, it raises an event and its TreeNode is added to the TreeView. The same goes for removing. When a TreeNode is selected, its Panel is set as the SelectedPanel. Setting the SelectedPanel merely hides all panels except the selected one:
vb.net Code:
Private Sub container_PanelAdded(sender As System.Object, e As OptionsViewLibrary.OptionsPanelContainer.OptionsPanelEventArgs) Handles container.PanelAdded Me.TreeView.Nodes.Add(e.Panel.Node) End Sub Private Sub container_PanelRemoved(sender As System.Object, e As OptionsViewLibrary.OptionsPanelContainer.OptionsPanelEventArgs) Handles container.PanelRemoved Me.TreeView.Nodes.Remove(e.Panel.Node) End Sub Private Sub tvw_AfterSelect(sender As System.Object, e As System.Windows.Forms.TreeViewEventArgs) Handles tvw.AfterSelect If e.Node IsNot Nothing Then Dim panel = TryCast(e.Node.Tag, OptionsPanel) If panel IsNot Nothing Then Me.SelectedPanel = panel End If End If End Sub
So far so good, this all works fine. I can add Panels via the designer and when I do a new TreeNode appears in the TreeView. I can select this node and the panel becomes visible (comes to the front).
Now, I am a little stuck. How do I implement child option panels? And more importantly: how do I let the user add child panels?
The most logical choice I think is to let each OptionsPanel have a property (ChildPanels or something) that returns the child OptionsPanels for that panel. Once the user selects an OptionsPanel then, he can look in the property grid to find its ChildPanels property and add child panels to that.
There is a problem though: what would this property return? It must return a ControlCollection of some container (this is, I think, a requirement for the designer features to work, otherwise panels are not added to the Form.Designer.vb file).
But there is no container. I cannot add them to the OptionsPanel itself, that would make no sense because the parent OptionsPanel has its own set of controls (the options itself...), there cannot be another (fully docked) Panel on top of those obviously.
The container of the main OptionsView then? That is not an option either, its Controls collection holds ALL OptionsPanels, not just the children of the selected panel. I cannot 'select' only the right panels either, that would require me to return a new instance of ControlCollection, it would be impossible to return the actual ControlsCollection that holds merely a small selection of its controls.
I realize this post might be hard to understand, but if you have any idea at all just let me know, perhaps I can work with it.
Thanks!
-
Aug 21st, 2011, 11:52 AM
#2
Re: [Ideas wanted] Options view control - child options
So you want the user to be able to add additional panels that are childs of the current panel? I've re-read the entire post a few times and I still haven't come to a conclusion about what it is you're exactly trying to accomplish.
-
Aug 21st, 2011, 12:42 PM
#3
Re: [Ideas wanted] Options view control - child options
Well, yes and no. The additional panels will not be children of the current panel, at least not in .NET terms. All panels should be parented by the one OptionsPanelContainer control, which is just a panel on the right side of a split container. However, for each panel there is a corresponding TreeNode in the treeview, and this TreeNode can be parent by other TreeNodes to create a hierarchy of options, exactly like the Visual Studio options screen (and many more like it).
So the user might create a hierarchy like this
Code:
[-] General Options
--- Loading & Saving
--- [+] Fonts
--- [-] Colors
--- Abc
--- Def
[-] Text Editor
--- VB.NET
--- C#.NET
--- Javascript
[-] Misc
--- License
Each node corresponds to one Panel, and selecting one node brings that panel to the front.
There might seem to be two options for adding the nodes:
- Add the nodes, and then add the corresponding panel
- Add the Panel, and then add the corresponding node
Option 1 would be ideal, but is not possible as far as I know due to design-time issues. For the panels to be actually added during design-time as well as remembered (serialized in the Designer file) they have to be added to the ControlCollection of the container. So, option 2 is the only way. Once a panel is added, I add the corresponding TreeNode to the TreeView.
The problem now is adding child nodes. I can only add 'parent' nodes/panels at the moment because only the main usercontrol has a Panels property (the one that returns the ControlCollection of the container) to which panels can be added.
This leaves no possibility to add child panels.
Ideally, each OptionsPanel would have another Panels property, just like a TreeNode has another Nodes property that returns the child nodes. But that seems impossible because the OptionsPanel.Panels property must still return the ControlCollection of the container (design-time issue) but that is impossible because it contains all other panels as well, not just the child panels.
So what I'm looking for is another clever way for the user to add child panels. As far as I can see, a Panels property on each OptionsPanel is impossible... I fear this is going to be harder than I first thought 
The only thing I can think of right now, and I have no idea if that would work, is to let the OptionsPanel have a ParentNode property. When the user is adding panels, he gets a collection editor (just like any other collection editor during design-time) with a list of panels to the left and a propertygrid to the right. The user could then use that property grid to select a TreeNode to be used as the parent node. It's not very user friendly but it might work...
-
Aug 21st, 2011, 02:43 PM
#4
Re: [Ideas wanted] Options view control - child options
Ok, after quite some work* that seems to work ok. I can select parent nodes for each panel and this way the user can build the hierarchy. It's not ideal though, so if anyone has a better idea, please...
I did have another idea, to create my own collection editor form for the Panels property and not use the built in collection editor, but I haven't really thought about that yet.
*It seems you cannot edit nor select properties of type TreeNode in a property grid. I had to write my own UITypeEditor for the ParentNode property that creates a ListBox, fills it with the TreeNodes currently in the TreeView and displays that.
-
Aug 22nd, 2011, 03:09 PM
#5
Re: [Ideas wanted] Options view control - child options
This actually sounds like it would be a really neat control to have, would you mind sending it my way when you've got it (mostly) done?
-
Aug 22nd, 2011, 04:40 PM
#6
Re: [Ideas wanted] Options view control - child options
I'll post it up in the codebank once it works. Still one major issue to overcome, but getting closer
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|