Introduction
I am currently in the early stages of developing an application that allows the user to create a diagram using a library of pre-defined graphical elements. Each of these graphical elements has functionality that becomes available when the context is on an instance of that element. I decided that this Context Sensitive functionality should be provided by additional controls associated to the graphical element, not via a right click menu. This article describes how I designed and developed a solution to this problem by creating a library that provides a way of attaching one or many sets of Visual Cues to a parent control and then manages the visibility of these by handling certain mouse events of the parent control.
At the moment, the library provides the ability to create a Cues
object, register this with the parent Control
, and then add any number of sets of Visual Cues to that Control
. Each set of Visual Cues is based on a specified model Control
, and each individual Visual Cue can be located either at some pre-defined point around the parent Control
or at an absolute position. The visibility of the Visual Cues is handled by the MouseEnter
and MouseLeave
events, where Show and Hide timers are started and stopped accordingly. It also ensures that any Visual Cues attached to a parent Control
that may change its position at run-time will follow that Control
by handling the LocationChanged
event.
Sample Application
As well as the Visual Cues library, the source code contains a small application, called CueTest, that demonstrates some Visual Cues.
- The CueTest form contains a number of controls, each of which have some Visual Cues attached.
- The Drag 'n Drop Panel contains two draggable controls, each with a set of Corner Cues, demonstrating the repositioning. There is also a Help (?) button.
- The
Button
has a set of Visual Cues attached with the Click
event handled so that a Messagebox
can be displayed.
- The
TextBox
has three sets of Visual Cues attached, one containing a Clear button, one containing a choice list, each which interact with their parent control. The final set contains a Help (?) button.
- The
PictureBox
has three sets of Visual Cues attached, the first set containing cues located at the corners, these have no functionality. The second set has a Help (?) button, and the third has two image navigation buttons.
Some of the Visual Cues are based on native .NET controls, some are extended versions that I have created. The visibility of each set of Visual Cues is controlled by the mouse events of its parent and their Show and Hide timers.
Class Descriptions
Cues
(extends ArrayList
). The Cues
class is the top-level class of the Visual Cues hierarchy, that maintains a collection of CueList
objects. Its constructor receives a reference to the parent Control
that is used to register the Cues
object. The Cues
class contains the code that handles the MouseEnter
, MouseLeave
, and LocationChanged
events of the parent Control
. It contains a number of overloaded methods that return a CueList
object, allowing for the creation of Visual Cues in a variety of pre-defined or absolute positions.
CueList
(extends ArrayList
). The CueList
class maintains a collection of CueAdaptor
objects. It provides a means to reference a set of Visual Cues attached to a parent Control
. It contains the public methods StartShow()
, StopShow()
, StartHide()
, and StopHide()
that control the Visual Cue visibility timers.
CueAdaptor
. The CueAdaptor
class forms part of the implementation of the Adaptor Pattern, allowing a Windows.Forms.Control
to participate as a Visual Cue without being extended or implementing any specific interfaces. Its constructor receives references to both the parent Control
and the Visual Cue control. The CueAdaptor
class handles the event passage between the parent Control
and the Visual Cue and vice versa.
CuePosition
. The CuePosition
class maintains attributes that describe the location of a Visual Cue, relative to its parent Control
. This class also handles the coordinate calculation and Visual Cue repositioning if its parent location changes at runtime.
Visual Cues Class Diagram
Creating a set of Visual Cues
To add a set of Visual Cues to a Windows.Forms.Control
takes up to five steps:
Step 1. Create an instance of Cues
and register the parent Control
. Cues
extends System.Collections.ArrayList
and is used to store any number of sets of Visual Cues attached to the parent control con
.
RestlessCues.Cues cues = new RestlessCues.Cues(con);
Step 2. Create an instance of the Windows.Forms.Control
derivative that will be used as a model for the Visual Cues attached to the parent control.
System.Windows.Forms.Button cue = new Button();
Step 3. If you need to get a handle on the list of Visual Cues when they are created then you need a CueList
. You will need this if you need to handle any events raised by the Visual Cue control.
CueList buttonList;
Step 4. Create a set of Visual Cues and attach them to the parent control. This example will create a single Visual Cue based on the type "cue
", at an absolute position based on the parent control (con
) coordinates. The other attributes set the width (45) and height (20) of the Visual Cue, the gap (1) between the parent control and the Visual Cue, and finally two timer values for show delay (10) and hide delay (1000).
buttonList = cues.AddCue(cue, new Point(con.Width - 50,
con.Height - 25), 45, 20, 1, 10, 1000);
Each Visual Cue is created based on the Type
of the model specified.
Type type;
type = cueModel.GetType();
System.Windows.Forms.Control cue;
cue = (System.Windows.Forms.Control)Activator.CreateInstance(type);
The library contains a number of Add Cue routines for creating pre-located sets of Visual Cues, in the corners, North, South, East and West as a single set, or N, S, E, W individually.
cues.AddCornerCues(cue, 7, 4, 0, 10, 1000);
cues.AddCue(cue, CueDirection.N, 100, 20, 1, 10, 1000);
cues.AddSideCues(cue, 10, 10, 1, 10, 1000);
Step 5. Using the CueList
, iterate the CueAdaptors
collection to register event handlers or alter attributes of the Visual Cue control.
foreach (CueAdaptor ca in buttonList)
{
ca.ClickEvent += new CueClickEventHandler(TextBoxClearButton_Click);
ca.CueControl.Text = "Help";
}
Sequence Diagrams
The following Sequence Diagram illustrates the logic flow resulting from handling the MouseEnter
and MouseLeave
events.
The diagram highlights the importance of the Show and Hide timers. These timers, associated with a CueList
, are started and stopped by the MouseEnter
and MouseLeave
events of the parent control. They are necessary for two reasons, firstly they provide the developer with a way of setting the delays between the context sensitive functionality becoming available and lost, they also overcome the fact that the MouseLeave
event fires as soon as the parent control loses mouse focus that would result in the Visual Cues being hidden before they could gain focus.
Points of interest
The Visual Cues are added to the container that contains the parent control, therefore it is important that the parent has been added to a container before initializing the Visual Cues.
The file handling of the images is a bit primitive, the application requires them to be in the same folder the app is run from, and they have to be named Image0.jpg and Image1.jpg.
One thing I am uncertain of is whether a C# (or any .NET) application will suffer from too many controls on a form, I know Visual Basic had a limit. My library obviously encourages you to add more controls.