ArticleDirectory
- Tabschemeprovider usage
- Tabschemeprovider implementation
This article presents the tabordermanager, which is a class that automatically adjusts the tab order on a Windows form based on different high-level schemes.
Introduction
Good tab orders on your Form S are important. they allow experienced users to more rapidly interact with your application, and they may even be necessary to enable your application for users that cannot manipulate the mouse. you may sometimes find it desirable to set the tab order at runtime. for example, you may allow your users to customize the visibility or position Form Controls, and you 'd like a professional tab order even when you don't know exactly how the final Form Will look. Or you may not want to have to worry about maintaining the tab order for Complex Form S at design-time as the design changes. Tabordermanager
Class will help you easily automate the process of applying a nice tab order at runtime. And Tabschemeprovider
Component makes it simple to set up your tabbing strategies in the windows Form S designer.
Background
This article assumes a basic familiarity with WindowsFormS programming in the. NET Framework Using C # Or Visual Basic. net.
Using the code
the tabordermanager
class is currently available in both C # and Visual Basic. net. it's quite simple: Given a container control (probably a form
, but possibly a groupbox
, tabcontrol
, panel
, etc .), calling the settaborder
method will automatically adjust the tabindex
Properties on child controls to implement a tab order that is either primarily "setting ss the container, then down "or" down the container, then restart SS ". by default, this strategy is inherited by child container controls. however, using the setschemeforcontrol
method, you can override the strategy for specific iners. one situation where this is useful is when you wowould like users to tab through a series of groupbox
es generation SS-first, but Tab through set of enclosed textbox
es down-first.
Here is an example invocation ofTabordermanager
To set an Alibaba SS-first tabbing strategy in C #:
Collapse | Copy code
//In constructor after initializecomponent (or whatever other//Code might set controls 'tabindex properties ).(NewTabordermanager (This). Settaborder (tabordermanager. tabscheme. Sort ssfirst );
And in Visual Basic. Net:
Collapse | Copy code
'// In constructor after initializecomponent (or whatever'// Other code might set controls 'tabindex properties ).DimTomAsTabordermanager =NewTabordermanager (Me) Tom. settaborder (tabordermanager. tabscheme. acrossfirst)
Implementation
to implement a given Tab Scheme strategy, we need to sort the controls and then set their tab order. the key is how the controls are sorted. if the primary scheme is "Your SS the container, then down", our primary sorting priority is by the controls ' top
property values. if and only if the top
properties are the same, then we fall back to sorting on the left
property values. the converse is true for the "down the container, then sans SS" tabbing scheme. we use. net Framework's built-in ability to sort collections based on a custom icomparer
implementation. our icomparer
is called tabschemecomparer
, and its compare
method implements the sorting strategy described above.
If a given control is itself a container (that is, it has child controls), we need to recurse. if the scheme override functionality is being used, we need to check whether or not we need to change the tab scheme at each level of the recursion. tab scheme overrides for individual containers are tracked usingHashtable
That lives inTabordermanager
That the user creates. When we recurse, we create a newTabordermanager
And pass the overrides down. The process of creating AuxiliaryTabordermanager
S is invisible to the client code. To see a tab scheme override in action, you may choose to add a down-first override to the group box inside the tab control of the demo application.
The tabschemeprovider component
You may also want to configure your tab schemes in the windowsFormS designer without having to write any code.Tabschemeprovider
Component is a thin wrapper aroundTabordermanager
Class to allow you to do just that.Tabschemeprovider
ImplementsIextenderprovider
Interface to dynamically AddTabscheme
Property to your container controls. A complete discussionIextenderprovider
Is beyond the scope of this article. Here, I will simply explain how you can take advantage ofTabschemeprovider
Functionality and discuss the interesting implementation details.
Tabschemeprovider usage
In the specified ded solution, Taborder
Class Library project contains both Tabordermanager
Class and Tabschemeprovider
Component. After you build this project, you can then add Tabschemeprovider
Component to your windows Form S toolbox by right-clicking, choosing Add/Remove items, and browsing to Taborder. dll Assembly that you compiled. Once it's on the toolbox, you may drag and drop it onto a Windows Form . There it sits in the component tray. But if you now examine the Properties window for your Form
, Groupbox
Es, Panel
S, orUsercontrol
S, you will see a new Tabscheme
Property which you can set None
(The default ), Acrossfirst
, Or Downfirst
. At runtime, during FormLoad
Event, the selected tab scheme for each container will propagate down through its Child controls as though you had Tabordermanager. settaborder
On the containers in question.
Tabschemeprovider implementation
there are some implementation details for the tabschemeprovider
control that are worth noting. as I stated above, the tabschemeprovider
gets its interesting functionality from the tabordermanager
class. thus, getting it to work is just a matter of creating a tabordermanager
instance for the top-level form , adding overrides for all other container controls with the tabscheme
property set, and calling tabordermanager. settaborder
In the form load
event (which occurs after the form -designer-generated code has positioned all of the controls in the form
's control hierarchy ).
the surprisingly difficult part is getting a reference to the top-level form
whose load
event we need. components like the tabschemeprovider
are not sited on the form
at runtime, and therefore do not automatically have access to the control hierarchy. this is in contrast to Control
S, which have properties like control. parent
or control. toplevelcontrol
. for the purposes of the tabschemeprovider
component, when the form
itself is one of the controls whose tab order needs to be set, this is not a problem. in that case, the designer generates a line of code like the following:
Collapse | Copy code
// //DemoForm// This. Tabschemeprovider1.settabscheme (This, Smcmaster. tabordermanager. tabscheme. datagssfirst );
The Tabschemeprovider
Can detect that Tabscheme
Of Form
Is being set and use the given Form
Instance to wire up Load
Event handler. Case closed. But what happens when Form
Has the default tab scheme Tabordermanager. tabscheme. None
? In that case, no such line of code is generated by the designer, and it is no longer clear from where Tabschemeprovider
Can obtain its Form
Instance. One might think that when Settabscheme
Is called for non-Form
Controls, you coshould just grab Form
Reference out of Control. toplevelcontrol
Property. Unfortunately, this does not work, because in general, Settabscheme
May get called before Control
And/or its parents have been added to Form
, And Control. toplevelcontrol
Is Null
In that situation.
One solution to this problem wowould have been to removeDefaultvalue
Attribute from the extender'sTabscheme
Property, upgrade tively forcing the windowsFormS designer to generateSettabscheme
Call for each and every supported container control including the top-levelForm. This isn' t very satisfying. So, I worked until I came up with an alternative.
The final implementation recognizes that there are two possibilities whenTabschemeprovider
Component is notified via a callSettabscheme
That a container wants its tab order managed:
- the control is already a part of the
form
's control hierarchy (where the case where the control is the form ). then we can directly and immediately obtain a reference to the form
and hook its load
event.
- the control is not already a part of the
form
's control hierarchy. here, we hook the parentchanged
event for the control and for all of its ancestors. eventually, the control or one of its ancestors will be added to the form
, and we can hook the form
's load
event in the resulting parentchanged
handler.
When we finally do discoverFormReference via the handling of either of the two possibilities, we have the inFormAtion we need and can short-circuit further processingParentchanged
Events.
Finally, if you use more than oneTabschemeprovider
On a givenForm, The resulting tab order will depend on the order in which they processFormLoad
Event. In other words, the behavior is undefined, So you shoshould avoid this scenario.
History
- Initial Release: 09/28/2004
- Added
Tabschemeprovider
Component: 10/28/2004