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
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
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.
Button has a set of Visual Cues attached with the
Click event handled so that a
Messagebox can be displayed.
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.
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.
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
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 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
StopHide() that control the Visual Cue visibility timers.
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 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
System.Collections.ArrayList and is used to store any number of sets of Visual Cues attached to the parent control
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.
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 = cueModel.GetType();
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";
The following Sequence Diagram illustrates the logic flow resulting from handling the
The diagram highlights the importance of the Show and Hide timers. These timers, associated with a
CueList, are started and stopped by the
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.