Introduction
There are plenty of popup controls out there; just do a Google search and thousands will pop up (no pun intended). More often than not, these implementations are either pure JavaScript or simplified web control extensions. While these implementations are good, I was looking for a control that would be capable of writing the JavaScript for me and providing good design-time support. In the end, what I needed was a control that was a little more robust and capable of handling multiple pre-determined and on-the-fly popups from a central location on the page. Also, the need to provide massive amounts of information via a conventional tool tip just wasn't possible. After doing some research on DHTML implementations, I came across the overLIB DHTML library and was impressed with the way that more information could be arranged in the JavaScript DHTML environment. The big limitation for this library was the fact that the developer had to write all of the commands by hand. Although there were sites out there that could write the appropriate code blocks for you, I still needed a control that had everything localized.
The purpose of this article is to discuss the capability of the wrapper control that I developed in order to accomplish the need for showing formatted information whether it be from a database, dataset, or other forms of information repository. The source code provides extensive comments on how these controls operate and what was needed to wrap the overLIB functionality. The two major controls are the OverlibPageControl
which resides on any particular web page and is a central repository for binding popup tool tips to all web controls, e.g., Label
s, CheckBox
es, etc., during design time, and the OverlibPopupAnchor
which is a simplified hyperlink for adding popup capabilities to a word or word groups on any particular web form. I will discuss how to create and modify the popup during design- and run-time. The goal of this article is to show how this control can save time during the design and testing when lots of information, if shown as is, on a web page will make the webpage unreadable or cause major headaches when switching to lower screen resolutions.
Background
One of my previous projects needed to have the ability to show through tool tips extra data concerning a particular keyword or web control. Because of this, my searches led me to Code Project and the popup capabilities of Tomas Petricek and others within the Code Project arena.
Yet what we needed, however, was what none of these items seemed to be able to do. What we really needed was a way to handle a lot of popups from a central location within a page and also define new ones dynamically. Thus the OverLibWrapper
C# namespace
was created. For a more complete definition of the overLIB commands, go to the overLIB documentation site. There are a lot of commands and the definitions are much better explained on the Bosrup and Boughner pages.
Using the code
First of all, you will need to add the OverLibWrapper.dll file to your Toolbox. I will not go into the details of installing it, because many who are using this control should be familiar with adding/removing visual and non-visual controls to their IDE toolboxes. The OverLibWrapper
namespace
contains visual controls: OverlibPageControl
, OverlibPopupAnchor
and ColorComboBox
. Never mind the ColorComboBox
, it is a control that was developed because of some UI requirements for the design-time development of an OverlibCommand
. For a quick run down, download the demo to test out the operations of the controls.
The two controls that are the most important are the OverlibPageControl
and OverlibPopupAnchor
. The OverlibPopupAnchor
wraps itself around the basic <a>
HTML control with some side benefits. For those developers that don't want or don't have a lot tool tips or even just want to play around similar to what is shown on Robert Boughner or Erik Bosrup's pages; you will want to use this item. The concept is just like adding a new hyperlink to your page, but you can also change some of the parameters to make it view whatever you wish. It contains all of the other designers there are for the OverlibPageControl
so if you don't want to put a page control for just one measly anchor, you don't have to.
In the screenshots at the beginning of the article, you can see what the OverlibPageControl
looks like during design-time. The following shows what is seen in the HTML view:
<asp:Label id="Label1" style="Z-INDEX: 101; LEFT: 56px;
POSITION: absolute; TOP: 112px" runat="server">Label</asp:Label>
<asp:CheckBox id="CheckBox1" style="Z-INDEX: 102; LEFT: 32px;
POSITION: absolute; TOP: 160px" runat="server" Text="CheckBoxName">
</asp:CheckBox>
<olwc:OverlibPageControl id="OverlibPageControl1" runat="server"
PageDefaults="STICKY,FGCOLOR,'#D2691E',CAPCOLOR,'#D4D0C8',WRAP">
<OverlibPopup ControlLink="Label1"
Text="This is the Tip Text shows when the control is clicked"
Commands="STICKY,CENTER,CAPTION,'Clicked caption'" EventType="OnClick" />
<OverlibPopup ControlLink="Label1"
Text="This shows when the user passes the mouse over"
Commands="STICKY,CENTER"
EventType="OnMouseOver" />
</olwc:OverlibPageControl>
The OverlibPageControl Designer
The OverlibPageControl
has two properties that enable it to function within a web form. They are PageDefaults
and Tips
.
The PageDefaults
property connects to a custom UITypeEditor
that allows the developer to build the appropriate commands that will be used for every call to the underlying overlib
function call. These are the same commands that would have been normally typed by hand to the overLIB JavaScript library.
The Tips
property opens a CollectionEditor
that allows for the designer to create, delete, and modify popups for particular controls that reside on the current page. One of the good things about this control is that it allows for the developer to link more than one popup to a particular control with different actions. There are only two event types currently, OnMouseOver
and OnClick
. These are the most commonly used events in web development. For this article, they will be the ones that are referenced most often. As illustrated in the image below, there are two popups that govern Label1
. When you mouse over Label1
, a popup will appear; when you click on Label1
, another popup will appear. Technically, the number of popups per control is only limited to the number of events that a particular control can handle.
Inside of the CollectionEditor
, the Commands
property opens up the OverlibCommandEditor
which is used to add commands that will be run on this particular popup. The Text
property opens a text editor, and it also allows for the direct input of what the text for the ToolTip will be.
Code
Not only can popups be built in the designer, but they can also be built during runtime. This allows for greater flexibility when dynamic popups are needed.
OverLibWrapper.OverlibPopup pop = new OverLibWrapper.OverlibPopup();
pop.Text = "This is a color test";
string colorStr =
HexColor.HexColorUtil.ColorToHex(System.Drawing.Color.Beige);
string colorStr2 =
HexColor.HexColorUtil.ColorToHex(System.Drawing.Color.IndianRed);
pop.AddCommand(OverLibWrapper.OverlibCommand.BackgroundColor,colorStr2);
pop.AddCommand(OverLibWrapper.OverlibCommand.ForegroundColor,colorStr);
pop.AddCommand(OverLibWrapper.OverlibCommand.Caption,"This is a color Test");
pop.ControlLink = "Label1";
pop.EventType =
OverLibWrapper.ControlEventType.OnClick;
OverlibPageControl1.Tips.Add(pop);
One of the other classes to use during run-time is the OverlibPopupTextBuilder
. This class provides the same functionality as the Text Editor, but allows for the developer to specify the exact layout of the information during run-time. It is useful if you want to create a table to organize the data to display in the tool tip.
OverLibWrapper.OverlibPopupAnchor anchor =
new OverLibWrapper.OverlibPopupAnchor();
OverLibWrapper.Design.OverlibPopupTextBuilder optb =
new OverLibWrapper.Design.OverlibPopupTextBuilder();
optb.AddTable();
optb.AddTableAttribute("border","1");
int rowIndex = optb.AddTableRow();
optb.AddRowCell(rowIndex,"this is some information in a cell");
optb.AddRowCell(rowIndex,"This is an cell with information");
anchor.Title = "Inner popup";
anchor.PopupText = "This is text inside the popup";
anchor.IsInnerPopupAnchor = true;
anchor.OverlibCommands =
"STICKY,CAPTION,'This is an inner popup caption',WRAP";
rowIndex = optb.AddTableRow();
optb.AddRowCell(rowIndex,"This is another cell");
optb.AddRowCell(rowIndex,anchor.HyperlinkString());
string popupInformation = optb.PopupText();
To understand more of the workings of the OverlibPopupTextBuilder
, download the source code and see what is going on under the hood.
OverlibPopupAnchor
The OverlibPopupAnchor
contains the same items that an OverlibPageControl
does, except that it is more compact in its representation to the developer. This control displays a text hyperlink that is already set up to display popups. One limitation to using the anchor is that it cannot have multiple event types added during design time.
OverlibCommand and OverlibCommandCollection
The OverlibCommand
and OverlibCommandCollection
are two of the classes that build the command structure for a call to the overlib
function. The OverlibCommand
contains the entire list of 100+ overLIB commands that comprise the core and official plug-in for the overLIB library. The OverlibCommandCollection
is a strongly typed collection that allows for the normal methods for a collection (i.e., Add
, Remove
, IndexOf
, etc). One of the more interesting methods of the OverlibCommandCollection
is the ToString()
method. When calling the ToString()
, the return value is a comma delimited string containing all of the commands that were inserted into the collection. This is the exact format that the overLIB JavaScript library expects the commands to be in. The OverlibCommandEditorDialog
contains an OverlibCommandCollection
that will parse the incoming string of commands and convert them into valid OverlibCommand
s for editing. It is best not to directly create an OverlibCommand
, but to use the OverlibPopup
to add particular commands with values to the popup.
OverlibPopup
This class is one of the other important items within the OverLibWrapper
namespace
. The OverlibPopup
class is parsed and generated by the OverlibPageControl
. The OverlibPopupCollection
contains the popups during design and rendering. When adding a new OverlibPopup
during design and runtime, it is imperative that the ControlLink
property is set to a WebControl that is currently on the design view of the web form. By setting the ControlLink
property, you are indicating that the particular popup is going to show for that particular WebControl. If the property is not set then exceptions will be thrown when execution of the web page happens.
Examples of each of the above mentioned command types are:
OverlibCommand.Sticky;
OverlibCommand.Caption;
OverlibCommand.Frame;
OverlibCommand.ForegroundColor;
The following is an example of creating a popup and adding the various commands with their associated values:
OverLIBWrapper.OverlibPopup pop = new OverLIBWrapper.OverlibPopup();
pop.Text ="A new popup";
pop.AddCommand(OverLIBWrapper.OverlibCommand.Draggable);
pop.AddCommand(OverLIBWrapper.OverlibCommand.Center);
pop.AddCommand(OverLIBWrapper.OverlibCommand.Caption,"This is a test");
pop.ControlLink = "Label1";
OverlibPageControl1.Tips.Add(pop);
Points of Interest
A point of interest that you may find interesting is the problem with trying to find the particular controls on the page. Tomas (mentioned earlier) got me half way to point with his UITypeEditor
that finds controls via the current context instance. However, when you create a new instance of a CollectionEditor
and add a new object, there is a problem with finding the current service that gives you the reference that has all of the controls on the page. The following snippet can be used with some minor modifications to find anything on the page that you wish:
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider,object value){
if (context!=null && context.Instance!=null && provider!=null) {
edSvc=(System.Windows.Forms.Design.IWindowsFormsEditorService)
provider.GetService(typeof(
System.Windows.Forms.Design.IWindowsFormsEditorService));
if (edSvc!=null) {
lb=new System.Windows.Forms.ListBox();
lb.BorderStyle=System.Windows.Forms.BorderStyle.None;
lb.SelectedIndexChanged+=
new EventHandler(lb_SelectedIndexChanged);
ArrayList items = new ArrayList();
System.Web.UI.Control parentControl = null;
IReferenceService service =
(IReferenceService)provider.GetService(typeof(IReferenceService));
object[] references =
service.GetReferences(typeof(System.Web.UI.Control));
foreach(Control control in references){
if(control.GetType() == typeof(System.Web.UI.UserControl) ||
control.GetType() == typeof(System.Web.UI.Page)){
parentControl = control;
break;
}
}
if (parentControl == null) {
return "No controls found";
}
foreach(Control ctrl in parentControl.Controls){
GetControls(ctrl, items);
}
items.Sort();
lb.Items.AddRange(items.ToArray());
edSvc.DropDownControl(lb);
if (lb.SelectedIndex==-1) return value;
return lb.SelectedItem;
}
}
return value;
}
Another item to note is that trying to incorporate an already valid piece of code without rewriting it for yourself can be a big problem. Since this was the case in using overLIB JavaScript files, the idea of compiling them as resources and then inserting the resource files into the calling web project was both a good idea and a challenge. Two other classes inside the OverLibWrapper
namespace
helped in the manipulation of the web.config file and inserting the appropriate folders and files into the current web project. These classes are generic enough to insert and manipulate just about any embedded resource that you want inserted into a particular web project. OverLibWrapper.Design.ProjectController
handles the file insertion from an embedded resource. OverLibWrapper.Design.AppConfig
works with and manipulates the configuration files. For those of you who are sticklers for comments, you can even insert a comment into the particular configuration file based on the key that you had just inserted.
During the OnPreRender()
of both the OverlibPageControl
and the OverlibPopupAnchor
, the requisite overLIB JavaScript elements are generated and written to the page. Both controls are smart enough that if there are problems with the overLIB script location, or with the text that is supposed to be displayed, nothing will be injected into the page so that there is no clutter when you are trying to troubleshoot other elements of your web form source.
Tips, Tricks, and Troubleshooting
OverlibPageControl
OverlibPopupAnchor
- Dragging and dropping the control onto the web form will conduct the same actions as the
OverlibPageControl
. Like the OverlibPageControl
, adding this control to your page will insert the <appSettings>
reference and also put the overLIBScripts folder in your web project.
- Note: The action of deleting the overLIBScripts directory or excluding it from the project or deleting the
overLIBLocation
from the <appSettings>
will not be automatically re-added with an OverlibPopupAnchor
. This is due to the fact that the OverlibPopupAnchor
only looks for the appSettings
key and file folder location during the creation of the control.
- The
OverlibPopupAnchor
is really only designed for smaller implementations on a page, where there is predominately a lot of text present. For a more robust implementation where there are controls, an OverlibPageControl
would be more suited for development.
Thanks
My deepest thanks go to the Code Project authors that provided serious timesaving steps and helped me muddle through some of the more distressing parts of this implementation. Other thanks and nods go to Erik Bosrup and his helpers for coming up with a well received and highly used piece of JavaScript and allowing me to wrap their code. Thanks also goes to Rob Battle for hitting me in the head a few times to drive me in the right direction during some of the seemingly hard portions of this code.
Legal
All overLIB JavaScript code is copyright of Erik Bosrup and Robert Boughner.
All other code is copyright to their respective developers.
At no time during the development of this code was intentional infringement conducted.
History
2005-02-16 -- Initial writing of this article.