|
|
|
|
|
|
|
When using Visual Studio .NET you will have noticed that it offers an alternative to the traditional SDI
or MDI user interface. The Tabbed MDI mode presents a tab control appearance with an individual tab per
open document. It also allows the creation of additional groups, either vertically or horizontally. The TabbedGroups
control is intended to offer this same method of organising documents.User Interface
Right-clicking a selected tab with cause a context menu to be shown. This menu has all the options needed by the user to
manage the collection of groups and open documents. Options exist to create new groups and to move the currently selected
page to the next or previous group. You can also use the close command to request the current tab page be closed. This can
also be initiated by using the close button available directly from the tab control header.Proportional Spacing
When more than one group is present you can use the resizing bar between groups in order to change the relative spacing of
the displayed groups. As you resize your application this proportional spacing is honoured. If you have a complex display
of different groups then the user can reset the spacing by the using the context menu displayed on right-clicking one of
the tabs. Choosing the Rebalance option will give each group an even share of the available space. For example, if
four groups are displayed in sequence then each group will be assigned 25% of the space. If you prefer to set the correct
spacing programmatically then you can use the ResizeBarLock property to prevent the user from resizing the spacing
between groups.
When the user is concentrating on a single document they can use the Prominent option available from the tabs context
menu. This make the group containing the tab become maximized within the available space. All the other groups are reduced down
to their minimum sizes so that the user can work with the selected group more easily. Seleting the same option again with remove
the maximized state and restore the proportional sizing that existed previously.DragProvider
You can rearrange the contents of the control using drag and drop of the tab pages. This is not however a true drag and drop
operation but a purely internal implementation. If you need to actually drag an external source and drop it into the control
then you can use the ExternalDrop event. When the event occurs you can then perform whatever application specific action
is required. Typically this will involve creating a new page and showing a new document.
The source of the drag operation needs to instantiate an instance of the DragProvider class that exists in the namespace
of the TabbedGroups control. You provide this new object in the call to the DoDragDrop method. When the cursor moves
over the TabbedGroups control this format is recognised and the appropriate drop indicator drawn. Then the drop occurs the
ExternalDrop event is generated passing this DragProvider instance as one of the parameters. This allows pertinent
information to be passed from the source to the destination to allow the correct application specific actions to occur. As the
information passed across is going to vary from application to application the DragProvider has just a single property
called Tag of type object. At its simpliest you might box a string into the parameter, but you could create a new
object instance and pass that instead.
|
|
|
|
|
|
|
TabGroupLeaf
This class implements an instance of the TabControl and as the name implies, instances should only ever occur as leaf nodes
from the root sequence. To add new pages to an instance of this class you need only interact with the TabGroupLeaf.TabPages
property which exposes the collection of tab pages from the underlying TabControl instance.
If you need to access the actual TabControl directly then you need to cast the TabGroupLeaf.GroupControl property to the
TabControl type. This is because the property is defined in the common base class called TabGroupBase as returned a
Control instance. For the TabGroupLeaf this is an instance of a TabControl but for the TabGroupSequence this
is a Panel instance used to organise its child groups.TabGroupSequence
This class contains a collection of leafs. There is only a single instance of this class which hold all the created leaf nodes. TabGroupBase
Both of the above classes derive from the base class called TabGroupBase. At times you may have a reference to the base class and
need to discover the actual derived class it represents. A quick way of doing this is to use the properties TabGroupBase.IsLeaf and
TabGroupBase.IsSequence and then cast the reference as appropriate.
The starting point for the hierarchy of nodes is the TabbedGroups.RootSequence property which exposes the top level sequence of
groups from the control instance. When you want to create a new leaf you should never create them directly. Instead you should call the
helper methods exposed by TabGroupSequence. For following code shows how to create two new leafs at the root sequence.C#
// Create new leaf at end of current sequence
TabGroupLeaf leaf1 = _control.RootSequence.AddNewLeaf();
// Create new leaf and insert at start of sequence
TabGroupLeaf leaf2 = _control.RootSequence.InsertNewLeaf(0);
// Add a tab page to each new leaf
leaf1.TabPages.Add(new TabPage("Page1", new RichTextBox());
leaf2.TabPages.Add(new TabPage("Page2", new RichTextBox());
VB.NET
' Create new leaf at end of current sequence
Dim leaf1 as TabGroupLeaf = _control.RootSequence.AddNewLeaf()
' Create new leaf and insert at start of sequence
Dim leaf2 as TabGroupLeaf = _control.RootSequence.InsertNewLeaf(0)
' Add a tab page to each new leaf
leaf1.TabPages.Add(New TabPage("Page1", new RichTextBox())
leaf2.TabPages.Add(New TabPage("Page2", new RichTextBox())
The Active Leaf
As long as there is at least one TabGroupLeaf instance then there will always be an active leaf. The active leaf
is the one that last had the focus. You can use the TabbedGroups.ActiveLeaf property to discover which leaf is
the currently active one and hook in the ActiveLeafChanged event for notification when it changes. This is useful
when you need to create and add a new document to the control. In this situation you should add the new page to the
currently active leaf rather than always using the first leaf that you can find.Navigation
Moving around the set of leaf elements is made easier by the provision of the following set of useful helper methods. You
can use TabbedGroups.FirstLeaf and TabbedGroups.LastLeaf in return a reference to the first and last
leaf instances in the hierarchy. When you already have a leaf reference you can use TabbedGroups.NextLeaf and
TabbedGroups.PreviousLeaf to move to the next and previous leaf respectively. Note that these last two methods do
not wrap and so will return null/ when they reach either the start or end as appropriate. You can construct a simple
loop to process each leaf node in the hierarchy . For example.C#
// Get first leaf
TabGroupLeaf leaf = _control.FirstLeaf();
while(leaf != null)
{
// Process leaf
// Move to next leaf
leaf = _control.NextLeaf(leaf);
}
VB.NET
' Get first leaf
Dim leaf as TabGroupLeaf = _control.FirstLeaf()
While No (leaf is Nothing)
' Process leaf
' Move to next leaf
leaf = _control.NextLeaf(leaf)
End While
|
|
|
|
|
|
|
Custom Information
There are two places in the persistence mechanism that you can hook into the process and provide your own information. At
the global level you can hook into the TabbedGroups.GlobalSaving and TabbedGroups.GlobalLoading events. This
allows extra XML information to be associated with the saved/loaded stream. You can also provide information on a per-page
level. Do this by hooking into the TabbedGroups.PageSaving and TabbedGroups.PageLoading events. You could use
this to save the name of the document the page represents or even the entire document text. For example, if you were to use
a simple RichTextBox per page in order to display a document you could save and load the contents in the following
way.C#
private void HookEvents()
{
_tabbedGroup.PageSaving += new PageSavingHandler(OnPageSaving);
_tabbedGroup.PageLoading += new PageLoadingHandler(OnPageLoading);
}
private void OnPageSaving(Crownwood.Magic.Controls.TabbedGroups tg,
Crownwood.Magic.Controls.TGPageSavingEventArgs e)
{
e.XmlOut.WriteCData((e.TabPage.Control as RichTextBox).Text);
}
private void OnPageLoading(Crownwood.Magic.Controls.TabbedGroups tg,
Crownwood.Magic.Controls.TGPageLoadingEventArgs e)
{
(e.TabPage.Control as RichTextBox).Text = e.XmlIn.ReadString();
}
VB.NET
Private Sub HookEvents()
AddHandler _tabbedGroup.PageSaving, AddressOf OnPageSaving
AddHandler _tabbedGroup.PageLoading, AddressOf OnPageLoading
End Sub
Private Sub OnPageSaving(ByVal tg As TabbedGroups, _
ByVal e As TGPageSavingEventArgs)
e.XmlOut.WriteCData(CType(e.TabPage.Control, RichTextBox).Text)
End Sub
Private Sub OnPageLoading(ByVal tg As TabbedGroups, _
ByVal e As TGPageLoadingEventArgs)
CType(e.TabPage.Control, RichTextBox).Text = e.XmlIn.ReadString()
End Sub
Control Persistence
By default the control provides a very simple level of control persistence. It does NOT save the contents of any
control but will save the type name of the TabPage.Control assigned to each TabPage instance. It will attempt
to recreate the specified control at load time. This works fine when you can a relatively simple control assigned to each of
your tab pages, such as a RichTextBox. If however you have a more complex situation then you are advised to turn of the
SaveControl property and to recreate the correct control at load time within the PageLoading event.
|
|
|
|
|
|
|
The events related to persistence have already been described in the previous section. There are however three other events
of special note that you will probably want to hook into and process. The first is the TabControlCreated event that is
fired whenever a new TabControl is created for a TabGroupLeaf instance. Any associated event handlers will be
called with the control already setup with the appropriate default properties but you can the modify these to customize the
appearance as needed. For example, you might alter the TabControl.PositionAtTop so that the tabs are always displayed
at the bottom of the group rather than defaulted to be at the top.
Next is the PageCloseRequested event that is fired in one of two ways. If the user presses the close button on the tab
control itself then the event is fired, or if the close command from the context menu associated with a page is selected. Either
way you have the chance to perform custom processing. Such as asking the user if they need to save the document because it has
changed since being opened. Note that you can cancel the request and not allow the page to be closed.
Another crucial event is the PageContextMenu that is fired when the context menu for a tab page is about to be displayed.
This gives you the chance to add or remove commands from the PopupMenu instance or even to cancel the menu entirely. Note that
the standard commands are always present in the menu commands collection and so it is safe to insert or remove entries by index value.
Any events removed will have been reinserted then next time the event is fired.
|
|
|
|
|
|
|
public void Rebalance()
Restore equal proportional spacing to all groups recursively.public void Rebalance(bool recurse)
Restore equal proportional spacing to top level sequence and if specified, all children.public TabGroupLeaf FirstLeaf()
Return reference to first leaf group.public TabGroupLeaf LastLeaf()
Return reference to last leaf group.public TabGroupLeaf NextLeaf(TabGroupLeaf current)
Return reference to next leaf group in hierarchy starting from specified leaf.public TabGroupLeaf PreviousLeaf(TabGroupLeaf current)
Return reference to previous leaf group in hierarchy starting from specified leaf.public byte[] SaveConfigToArray()
Saves layout information into an array of bytes using Encoding.Unicode.public byte[] SaveConfigToArray(Encoding encoding)
Saves layout information into an array of bytes using caller provided
encoding object.public void SaveConfigToFile(string filename)
Saves layout information into a named file using Encoding.Unicodepublic void SaveConfigToFile(string filename, Encoding encoding)
Saves layout information into a named file using caller provided encoding
object.public void SaveConfigToStream(Stream stream, Encoding encoding)
Saves layout information into a stream object using caller provided
encoding object.public void LoadConfigFromArray(byte[] buffer)
Loads layout information from given array of bytes.public void LoadConfigFromFile(string filename)
Loads layout information from given filename.public void LoadConfigFromStream(Stream stream)
Loads layout information from given stream object.public void OnTabControlCreated(Controls.TabControl tc)
Defines the default properties of the specified TabControl and generates event.public void OnPageCloseRequested(TGCloseRequestEventArgs e)
Generates PageCloseRquested event.public void OnPageContextMenu(TGContextMenuEventArgs e)
Generates PageContextMenu event.public void OnGlobalSaving(XmlTextWriter xmlOut)
Generates GlobalSaving event.public void OnGlobalLoading(XmlTextReader xmlIn)
Generates GlobalLoading event.public void OnPageSaving(TGPageSavingEventArgs e)
Generates PageSaving event.public void OnPageLoading(TGPageLoadingEventArgs e)
Generates PageLoading event.public void OnProminentLeafChanged(EventArgs e)
Generates ProminentLeafChanged event.public void OnActiveLeafChanged(EventArgs e)
Generates ActiveLeafChanged event.public void OnDirtyChanged(EventArgs e)
Generates DirtyChanged event.public void OnExternalDrop(TabGroupLeaf tgl, TabControl tc, DragProvider dp)
Generates ExternalDrop event.
|
|
|
|
|
|
|
public VisualStyle Style
Has two possible values.
- VisualStyle.IDE shows in Visual Studio .NET style
- VisualStyle.Plain shows in a simpler Visual C++ v6 style
Default: VisualStyle.IDEpublic TabGroupSequence RootSequence
Provides access to the top-level sequence of groups.public int ResizeBarVector
Defines the width of the resizing bars that separate different groups.
A value of -1 requests that the default vector for the current Style value be used.
Default: -1public Color ResizeBarColor
Defines the color to use when drawing the resizing bar.
Default: this.BackColorpublic bool ResizeBarLock
When defined this will lock the resizing bars so that the proportional spacing cannot be changed.
Default: falsepublic TabGroupLeaf ProminentLeaf
Define which tab group should be maximized.
Default: nullpublic int DefaultGroupMinimumWidth
Define the minimum width a group can be resized to become.
Default: 4public int DefaultGroupMinimumHeight
Define the minimum height a group can be resized to become.
Default: 4public ImageList ImageList
Default ImageList to be used by all leaf nodes.
Default: nullpublic DisplayTabModes DisplayTabMode
Has five possible values.
- HideAll do not show any tab headers
- ShowAll show all tab headers
- ShowActiveLeaf only show active leaf tab header
- ShowMouseOver show tab header when mouse over
- ShowActiveAndMouseOver show when active or mouse over
Default: DisplayTabModes.ShowAllpublic bool SaveControls
When defined and saving the configuration it will attempt to save the name of the Control instance
associated with each TabPage. On reloading it attempts to recreate the named control and so recreate
the saved setup. Note this will not save the properties or contents of the named control.
Default: truepublic bool Dirty
Used by the developer to determine if the control is dirty and needs saving.public bool AutoCalculateDirty
When this is defined the control will automatically update the value of the Dirty flag whenever any
change occurs to the structure of the control. Otherwise the developer is left to update the flag manually.
Default: truepublic TabGroupLeaf ActiveLeaf
Defines which leaf node is the currently active one.
Default: nullpublic bool AtLeastOneLeaf
When defined the control will ensure there is at least one leaf node in existence at all times. Otherwise it is
possible that removing the last page from a leaf will cause compacting to remove that leaf and leave the control
with no leafs at all.
Default: truepublic bool AutoCompact
Should the structure be automatically compacted to ensure the most efficient hierarchy is maintained at all times.
Default: truepublic string CloseMenuText
Text to use on TabPage context menu for close command.
Default: Closepublic string ProminentMenuText
Text to use on TabPage context menu for prominent command.
Default: Prominentpublic string RebalanceMenuText
Text to use on TabPage context menu for rebalance command.
Default: Rebalancepublic string MovePreviousMenuText
Text to use on TabPage context menu for move previous command.
Default: Move to Previous Tab Grouppublic string MoveNextMenuText
Text to use on TabPage context menu for move next command.
Default: Move to Next Tab Grouppublic string NewVerticalMenuText
Text to use on TabPage context menu for new vertical command.
Default: New Vertical Tab Grouppublic string NewHorizontalMenuText
Text to use on TabPage context menu for new horizontal command.
Default: New Horizontal Tab Grouppublic Shortcut CloseShortcut
Shortcut combination to invoke the close command.
Default: Shortcut.CtrlShiftCpublic Shortcut ProminentShortcut
Shortcut combination to invoke the prominent command.
Default: Shortcut.CtrlShiftTpublic Shortcut RebalanceShortcut
Shortcut combination to invoke the rebalance command.
Default: Shortcut.CtrlShiftRpublic Shortcut MovePreviousShortcut
Shortcut combination to invoke the move previous command.
Default: Shortcut.CtrlShiftPpublic Shortcut MoveNextShortcut
Shortcut combination to invoke the move next command.
Default: Shortcut.CtrlShiftNpublic Shortcut SplitVerticalShortcut
Shortcut combination to invoke the new vertical command.
Default: Shortcut.CtrlShiftVpublic Shortcut SplitHorizontalShortcut
Shortcut combination to invoke the new horizontal command.
Default: Shortcut.CtrlShiftH
|
|
|
|
|
|
|
public event EventHandler ProminentLeafChanged
Fired whenever the ProminentLeaf property value has changed.public event EventHandler ActiveLeafChanged
Fired whenever the ActiveLeaf property value has changed.public event EventHandler DirtyChanged
Fired whenever the Dirty property value has changed.public event PageCloseRequestHandler PageCloseRequest
Fired when the user requests a page be closed via either the TabControl close button or by
selecting the Close command from the TabPagecontext menu.public event PageContextMenuHandler PageContextMenu
Fired when the context menu is about to be shown for a TabPage. Use this event to add or
remove entries from the presented menu or to cancel the menu from appearing.public event TabControlCreatedHandler TabControlCreated
Fired whenever a new TabControl instance is created. Use this to modify the default
properties of the created control.public event GlobalSavingHandler GlobalSaving
Fired when the configuration information is being saved and allows custom information to be stored
inside the configuration stream.public event GlobalLoadingHandler GlobalLoading
Fired when a configuration is being reloaded and allows custom information previously saved to be
reloaded again.public event PageSavingHandler PageSaving
Fired for each TabPage instance being saved. You should override this to save the actual data
associated with the page so that it can be recreated when the configuration is reloaded.public event PageLoadingHandler PageLoading
Fired when a configuraton is ebing reloaded for each TabPage being recreated. Allows custom
information to be reloaded and the appropriate setup of the page to be performed.public event ExternalDropHandler ExternalDrop
Fired when an external drag source has been dropped onto a TabGroupLeaf instance.Delegate Signatures
void TabControlCreatedHandler(TabbedGroups tg, Controls.TabControl tc);
void PageCloseRequestHandler(TabbedGroups tg, TGCloseRequestEventArgs e);
void PageContextMenuHandler(TabbedGroups tg, TGContextMenuEventArgs e);
void GlobalSavingHandler(TabbedGroups tg, XmlTextWriter xmlOut);
void GlobalLoadingHandler(TabbedGroups tg, XmlTextReader xmlIn);
void PageSavingHandler(TabbedGroups tg, TGPageSavingEventArgs e);
void PageLoadingHandler(TabbedGroups tg, TGPageLoadingEventArgs e);
void ExternalDropHandler(TabbedGroups tg, TabGroupLeaf tgl,
Controls.TabControl tc, DragProvider dp);
|
|
|
|
|
|
|
|
|
Copyright 2003 Crownwood Consulting Ltd. All Rights Reserved |
|
|
|