Introduction
Many of you might have seen Outlookbar as shown above while using Microsoft Outlook application. This UI control has always fancied me. I felt why not use the power of ASP.NET to develop this control? All the OutlookBar menu and submenu items are configured from an XML file. So you can configure the XML file as per your requirement to display main menu and submenu items. Sample XML files used in demo project are for illustration purpose only. This article will walk you through the implementation of this as a user control in ASP.NET.
Background
Recently, I was working on master/detail DataGrid
with collapsible feature. As most of you might be aware, TemplateColumn
feature of DataGrid
enables us to make use of templates such as Itemtemplate
, EditTemplate
, HeaderTemplate
, FooterTemplate
and SeparatorTemplate
. These templates give developer control over what s/he wants to paint in each of these templates. Also, DataGrid
provides OnEditCommand
and OnCancelCommand
events for which we can write handler code so that DataGrid
can paint what is specified in Itemtemplate
or EditItemTemplate
. I have used the same concept for this control.
I have used asp:Button
control in ItemTemplate
section, and used asp:Button
and other user controls using Repeater
to display child items in EditTemplate
section. I have wired the OnEditCommand
event handler to asp:Button
control. The code section below explains step by step implementation details.
Using the code
Outlookbar
user control is implemented in Outlookbar.ascx. It has the following HTML declaration:
<%@ Register TagPrefix="uc1" TagName="ImageHandler" Src="ImageHandler.ascx" %>
<asp:DataGrid ShowHeader="False" runat="server" OnEditCommand="OnEdit">
<Columns>
<asp:TemplateColumn>
<ItemTemplate>
<asp:Button Width="100%" BackColor="#cccc99"
Text='<%# DataBinder.Eval(Container.DataItem,"Caption") %>'
runat="server" CommandName="Edit" ID="Button1"/>
</ItemTemplate>
<EditItemTemplate>
<asp:Button width="100%" BackColor="#cccc99"
Text='<%# DataBinder.Eval(Container.DataItem,"Caption") %>'
runat="server" CommandName="Cancel" ID="Button2"/>
<uc1:ImageHandler id="imgHandle1"
SelectedIndex='<%# DataBinder.Eval(Container.DataItem,"MenuItemIndex") %>'
runat="server">
</uc1:ImageHandler>
</EditItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
If you look at the above HTML, you can see that I have used DataGrid
control. Please note that I have set ShowHeader
attribute to false
as this control has no headers. In Itemtemplate
section, I have declared asp:Button
control and have set its width to 100%. I have also set commandname
property to 'Edit' so it gets wired to OnEditCommand
event handler. EditTemplate
section has asp:Button
and another user control which displays all submenu items. I will explain this user control later in this article. Please note that Text
property of asp:Button
is set to Caption
item of Datasource
bound to Datagrid
. ImageHandler
user control has SelectedIndex
property which is set using menuItemIndex
property of Datasource
.
The code behind of this control has the following details:
namespace OutLookStyleBar
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.IO;
public abstract class OutlookStyleBar : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.DataGrid dgOutLookStyleBar;
private string m_sMenuItemsXML;
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
GetMenuItems();
dgOutLookStyleBar.EditItemIndex=2;
BindData();
}
}
If you look at the above code snippet, the code behind class OutlookStyleBar
has been derived from System.Web.UI.UserControl
, and has the following variables. The first variable is dgOutLookStyleBar
and is of type DataGrid
, and another is a string
variable m_sMenuItemsXML
. This string variable holds the XML of all the main menu items. This XML string is used to set DataSource
property of DataGrid
. This is saved in viewstate to avoid frequent trips to database on every postback.
If you look at Page_Load
handler, it invokes GetMenuItems
method which populates the m_sMenuItemsXML
from OutlookItems.xml.
Since I want to show one row item as expanded, I have set EditItemIndex
as 2. So that when the control loads for the first time, it will show third row as expanded. BindData
method binds the XML string to DataGrid
.
Please download source code from the link shown at the top of this article for detailed implementation of the above methods. Now, let us see the code in OnEdit
event handler.
public void OnEdit(object source,
System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
dgOutLookStyleBar.EditItemIndex= e.Item.ItemIndex;
BindData();
}
If you look at the above code, it is very simple. When user clicks on any of the menu item, the OnEditCommand
is fired and the OnEdit
event handler is invoked. This just sets EditItemIndex
property to the row value selected by the user. This is passed in event argument of type DataGridCommandEventArgs
. The property is e.Item.ItemIndex
. After setting EditItemIndex
, the next step is to invoke BindData
method so that DataGrid
will paint as per EditTemplate
section for the row selected. Rest of the rows are painted as per what is specified in Itemtemplate
section.
Now, let us see how the inner control is implemented.
This control is implemented in ImageHandler.ascx. I have named it so because it has used asp:ImageButton
control to represent sub menu items and also for up and down scrolling. The HTML declaration is shown below:
<table cellSpacing="1" cellPadding="1" width="100%" bgColor="#808080" border="0">
<tr>
<td align="right" height="15"><asp:imagebutton id="btnUp"
Runat="server" ImageUrl="Images/UpArrow.gif" Height="15px"
Width="30px"></asp:imagebutton></td>
</tr>
<tr>
<td align="middle">
<asp:repeater id="drImageList" runat="server"
OnItemCommand="ImageSelect_Handler">
<HeaderTemplate>
<div style="WIDTH: 100%; BACKGROUND-COLOR: #808080">
</HeaderTemplate>
<ItemTemplate>
<br />
<span>
<asp:ImageButton Width="40px" Height="40px" CommandName="Item"
BackColor="#cccc99"
ImageUrl='<%# DataBinder.Eval(Container.DataItem,"ImageURL") %>'
Runat="server" />
</span>
<br />
<span style="COLOR: white">
<%# DataBinder.Eval(Container.DataItem,"Caption") %>
</span></br>
</ItemTemplate>
<FooterTemplate>
<br />
</div>
</FooterTemplate>
</asp:repeater> </td>
</tr>
<tr>
<td align="right" height="15"><asp:imagebutton id="btnDown"
Runat="server" ImageUrl="Images/DownArrow.gif" Height="15px"
Width="30px"></asp:imagebutton></td>
</tr>
</table>
In the above HTML code, I have declared table
tag having three rows. In <td>
tag of first row, I have used asp:ImageButton
control to represent Up Arrow. Middle row <td>
tag contains Repeater
control, and last row <td>
tag contains another asp:ImageButton
control to represent Down Arrow. Up & Down Arrow button controls provide handler to handle scrolling of image items shown in Repeater
control.
Repeater
control as you know is very flexible and gives us control over what to paint. I have used <DIV>
tag in its HeaderTemplate
and asp:ImageButton
control inside <span>
tag. Another <span>
tag is used to contain Caption
of Image_Menu_Item
. Lastly, the Footer Template contains the end </DIV>
tag.
Now, let us go through the code behind of ImageHandler.ascx which is in ImageHandler.ascx.cs file:
namespace OutLookStyleBar
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.IO;
public abstract class ImageHandler : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.Repeater drImageList;
private string m_sImageItemsXML;
protected System.Web.UI.WebControls.ImageButton btnUp;
protected System.Web.UI.WebControls.ImageButton btnDown;
private int m_iSelectedIndex;
private const int MAX_REPEATER_ITEMS =3;
private int m_iCurrentPos =1;
private int m_iTotalItems =8;
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
m_iCurrentPos=1;
ViewState["CurrentPos"]= m_iCurrentPos.ToString();
GetNewItems();
BindData();
}
else
{
if((string)ViewState["CurrentPos"] != null)
{
m_iCurrentPos =
Int32.Parse((string)ViewState["CurrentPos"]);
m_iTotalItems =
Int32.Parse((string)ViewState["TotalItems"]);
}
else
{
m_iCurrentPos=1;
m_iTotalItems=5;
}
}
}
If you look at the above code snippet, I have declared class ImageHandler
which is derived from System.Web.UI.UserControl
and has following declarations:
protected System.Web.UI.WebControls.Repeater drImageList;
private string m_sImageItemsXML;
protected System.Web.UI.WebControls.ImageButton btnUp;
protected System.Web.UI.WebControls.ImageButton btnDown;
private int m_iSelectedIndex;
private const int MAX_REPEATER_ITEMS =3;
private int m_iCurrentPos =1;
private int m_iTotalItems =8;
drImageList
is a variable of type Repeater
and will contain all the submenu items represented as Images.
btnUp
and btnDown
are two variables of type ImageButton
used to provide handlers for up and down scrolling of Repeater
items.
m_iSelectIndex
is variable of type int
and is used to hold position of parent menu item, which in our case is DataGrid
row of OutlookBar.ascx. This variable is important as it is used to retrieve submenu items from ImageItems.xml based on its value.
MAX_REPEATER_ITEMS
is an integer constant used to define maximum items to be shown at any given point in Repeater
.
m_iCurrentPos
is integer variable used to store position of top item shown in Repeater
. m_iTotalItems
is used to store total number of submenu items. These two variable values control when to show or hide up and down arrow buttons.
m_sImageItemsXML
is a variable of type string used to store XML string retrieved from ImageItms.xml.
Inside Page_Load
event handler, we retrieve the submenu items by invoking GetNewItems
method, and then invokes BindData
method to bind the XML retrieved to Repeater
. It also sets the m_icurrentPos
as 1 to display the top list of images equal to MAX_REPEATER_ITEMS
.
Please note that values of these variables are preserved in viewstate so that it can be tracked during post back when user wants to scroll up or down.
SelectedIndex
is defined as public
property which is used by parent control to set its value. Once set, it invokes GetNewItems
and BindData
methodd to refresh ImageList
of Repeater
. The code snippet is as shown below:
public int SelectedIndex
{
set {
m_iSelectedIndex=value;
GetNewItems();
BindData();
}
}
GetNewItems
method is responsible for retrieving submenu items from XML file based on value of SelectedIndex
property and value of m_iCurrentPos
. It uses XPATH
expression to retrieve appropriate items from XML. BindData
method is pretty standard as it binds the XML string to Repeater
. You can download the code from the link shown at top of this article and refer its details.
Conclusion
We saw how the power of ASP.NET, especially DataGrid
and Repeater
, can be used to develop rich user controls such as OutlookBar
. The source code contains the test web form which contains OutlookBar
user control. Please download and see the working demo. If you face any difficulties, please contact me at gokuldasc@yahoo.com. Good Luck !!!
My Other Articles