Sunday, 12 December 2010

How to Show Image stored in Database in ToolTip on Mouseover of GridView row


In this post, we are going to see how to show an image as tooltip when we hover the mouse on Grid View row where the image stored on the database field instead of url.

To understand how to store and retrieve image in the database, please look at this Post.

The actual functionality of the example taken in this post is shown below :
  1. Bind the Products data in the grid, with last column in each row contains an image.
  2. When the user hover the mouse on the last column image, show the image stored in the database for that product as tooltip.
  3. When no image stored for a product, show a default text/image for informing to the user “No image found”
  4. For good UI presentation, when the image retrieved from the database show a progress bar to let the user know something going on in background. (If the database connection is slow, user won’t feel bad showing the progress bar)
Now lets us look at the code how to implement the requirement shown above.
The GridView script will looks like this
<asp:GridView ID="grdViewProducts" runat="server"
    AllowPaging="True" AutoGenerateColumns="False" TabIndex="1"
    DataKeyNames="ProductID" Width="100%"
    ShowFooter="True" CellPadding="4" ForeColor="#333333" GridLines="None" >
    <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="Product ID" />
        <asp:BoundField DataField="ProductName" HeaderText="Product Name" />
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" />
        <asp:BoundField DataField="QuantityPerUnit" 
                                HeaderText="Quantity Per Unit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" />
        <asp:TemplateField HeaderText="Photo">
            <ItemStyle Width="10%" HorizontalAlign="Center" />
            <ItemTemplate>
                <img id="imgPhoto" src="Images/zoom_icon.jpg"
                    onmouseover="ShowToolTipImage(event, this.alt)"
                    onmouseout="HideTooTipImage()"
                    onmousemove="MoveToolTipImage(event)"
                    alt="<%# Eval("ProductID") %>,<%# Eval("IsImageAvailable") %> " 
                    width="20px" height="20px" 
                    title="<%# Eval("ProductName") %>" 
                    style="cursor:hand" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
    <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
    <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
    <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
    <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
    <EditRowStyle BackColor="#999999" />
    <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
</asp:GridView>
To bind the data to the grid, BindGrid() method is used in code behind. The code would be
protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        BindGrid();
    }
}
private void BindGrid()
{
    using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
    {

        SqlCommand command = new SqlCommand(
                "SELECT ProductID, ProductName, CompanyName, CategoryName, " +
                "QuantityPerUnit, UnitPrice, ProductImage FROM Products " +
                "JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID " +
                "JOIN Categories ON Products.CategoryID = Categories.CategoryID " +
                "Order by ProductID", connection);

        connection.Open();
        SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

        IList<ProductView> productViewList = new List<ProductView>();
        while (dr.Read())
        {
            ProductView productView = new ProductView();
            productView.ProductID = dr["ProductID"].ToString();
            productView.ProductName = dr["ProductName"].ToString();
            productView.CompanyName = dr["CompanyName"].ToString();
            productView.CategoryName = dr["CategoryName"].ToString();
            productView.QuantityPerUnit = dr["QuantityPerUnit"].ToString();
            productView.UnitPrice = Convert.ToDouble(dr["UnitPrice"].ToString());
            productView.IsImageAvailable = ((dr["ProductImage"].ToString().Length > 0) ? true : false);
            productViewList.Add(productView);
        }
        grdViewProducts.DataSource = productViewList;
        grdViewProducts.DataBind();
    }
}
The ProductView entity class
public class ProductView
{
    public string ProductID { get; set; }
    public string ProductName { get; set; }
    public string CompanyName { get; set; }
    public string CategoryName { get; set; }
    public string QuantityPerUnit { get; set; }
    public double UnitPrice { get; set; }
    public bool IsImageAvailable { get; set; }
}
To get the image from the database there are two ways are available
  1. Generic Handler (extension .ashx)
  2. Web Page (extension .aspx)
But in both the ways, we must open the database connection and return the image as response. To get the proper image, we should pass the required parameter to the file as url querystring. In this example, I am taking Generic Handler to get the image.

The ProcessRequest() event on GenericHandler looks like:
System.Threading.Thread.Sleep(1000);
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
{
    SqlCommand command = new SqlCommand(
        "select ProductImage from Products where ProductID = '" +
        context.Request.QueryString["ProductID"] + "'", connection);

    connection.Open();
    SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);
    while (dr.Read())
    {
        if (dr["ProductImage"].ToString().Length > 0)
        {
            context.Response.BinaryWrite((byte[])dr["ProductImage"]);
        }
    }
}
We are getting the product image from the query and converting as Byte[] stream and writing to the response.

The Javascript is follows :
// Declare General Variables 
var sTooTipId = 'divTooTip';
var sToolTipPlacement = "Left"; // Right, Left

// For Hiding tool tip
function HideTooTipImage() {
    // Get the Div element which was created dynamically on ShowToolTipImage function
    var divTip = document.getElementById(sTooTipId);
    if (divTip) {
        while (divTip.childNodes.length > 0)
        // Remove all child content which are added inside on the Div content
            divTip.removeChild(divTip.childNodes[0]);
    }
    // Invisible th Div (which removed all child content)
    divTip.style.visibility = "hidden";

}

function MoveToolTipImage(event) {

    // Verify if the Div content already present?
    if (document.getElementById(sTooTipId)) {

        // Get the Div content 
        var newDiv = document.getElementById(sTooTipId);

        if ('pageX' in event) { // all browsers except IE before version 9
            var pageX = event.pageX;
            var pageY = event.pageY;
        }
        else { // IE before version 9
            var pageX = event.clientX + document.documentElement.scrollLeft;
            var pageY = event.clientY + document.documentElement.scrollTop;
        }

        if (sToolTipPlacement == "Right")
            newDiv.style.left = (pageX + 17) + "px";
        else // Left
            newDiv.style.left = (pageX - (parseInt(newDiv.style.width) + 17)) + "px";

        // Portion of div when hide by browser top
        if ((pageY - (parseInt(newDiv.style.height) + 3)) < 0)
        // Showing below the cursor
            newDiv.style.top = pageY + "px";
        else
        // Showing above the cursor
            newDiv.style.top = (pageY - (parseInt(newDiv.style.height) + 3)) + "px";

        // Finally visibling the div which has the image
        newDiv.style.visibility = "visible";
    }
}
// For showing tool tip
function ShowToolTipImage(event, pId) {

    var newDiv = null;

    // Verify if the Div content already present?
    if (!document.getElementById(sTooTipId)) {

        // If not create a new Div element
        newDiv = document.createElement("div");
        // Set the id for the Div element to refer further
        newDiv.setAttribute("id", sTooTipId);

        // Add it to the page
        document.body.appendChild(newDiv);

    }
    else {
        // Get the Div content which was invisible on HideTooTipImage function
        newDiv = document.getElementById(sTooTipId);
    }

    var url = '';

    // Here the pId is the id of the image + a flag
    // (0 - when no image stored on the database or
    // 1 - when image stored on the in database)
    // which indicate whether the image required to show or not
    if (pId.split(",")[1] == 'False ')
        url = "Images/ImageNotAvailable.jpg";
    else
        url = "GetImageHandler.ashx?ProductID=" + pId.split(",")[0];
       
    var strImageContent =
    '<div class="border_preview"> ' +
    '   <div id="loader_container"> ' +
    '       <div id="loader"> ' +
    '           <div align="center">Loading image preview...</div> ' +
    '           <div id="loader_bg"> ' +
    '               <div id="progress"> </div>' +
    '           </div> ' +
    '       </div> ' +
    '   </div> ' +
    '   <div class="preview_temp_load"> ' +
    '       <img id="previewImage" onload="javascript:remove_loading();" src="' + url + '" border="0" width="100%" height="100%"> ' +
    '   </div> ' +
    '</div>';
    newDiv.innerHTML = strImageContent;

    newDiv.style.zIndex = 2;
    newDiv.style.width = "340px";
    newDiv.style.height = "80px";

    newDiv.style.position = "absolute";

    if ('pageX' in event) { // all browsers except IE before version 9
        var pageX = event.pageX;
        var pageY = event.pageY;
    }
    else { // IE before version 9
        var pageX = event.clientX + document.documentElement.scrollLeft;
        var pageY = event.clientY + document.documentElement.scrollTop;
    }

        
    if (sToolTipPlacement == "Right")
        newDiv.style.left = (pageX + 17) + "px";
    else // Left
        newDiv.style.left = (pageX - (parseInt(newDiv.style.width) + 17)) + "px";

    // Portion of div when hide by browser top
    if ((pageY - (parseInt(newDiv.style.height) + 3)) < 0)
    // Showing below the cursor
        newDiv.style.top = pageY + "px";
    else
    // Showing above the cursor
        newDiv.style.top = (pageY - (parseInt(newDiv.style.height) + 3)) + "px";
            
    // Finally visibling the div which has the image
    newDiv.style.visibility = "visible";
}

var t_id = setInterval(animate, 20);
var pos = 0;
var dir = 2;
var len = 0;

function animate() {
    var elem = document.getElementById('progress');
    if (elem != null) {
        if (pos == 0) len += dir;
        if (len > 32 || pos > 79) pos += dir;
        if (pos > 79) len -= dir;
        if (pos > 79 && len == 0) pos = 0;
        elem.style.left = pos + "px";
        elem.style.width = len + "px";
    }
}
function remove_loading() {
    var targelem = document.getElementById('loader_container');
    targelem.style.display = 'none';
    targelem.style.visibility = 'hidden';
}
The required Style Sheet follows :
/*Styles*/
.border_preview{
        z-index:100;
        position:absolute;
        background: #fff;
        border: 1px solid #444;
        padding:3px;
        width:100%;
}
#loader_container {text-align:left;position:absolute;}
#loader {
    font-family:Tahoma, Helvetica, sans;
    font-size:10px;
    color:#000000;
    background-color:#FFFFFF;
    padding:10px 0 16px 0;
    margin:0 auto;
    display:block;
    width:135px;
    border:1px solid #6A6A6A;
    text-align:left;
    z-index:255;
}
#progress {
    height:5px;
    font-size:1px;
    width:1px;
    position:relative;
    top:1px;
    left:10px;
    background-color:#9D9D94
}
#loader_bg {
    background-color:#EBEBE4;
    position:relative;
    top:8px;left:8px;height:7px;
    width:113px;font-size:1px
}
.title_h2 {
    color:#000;
    text-align: left;
    padding:12px 0 0 18px;
    margin:0;
    font-size:14px;
}
.preview_temp_load {
    vertical-align:middle;
    text-align:center;
    padding: 0px;
}
.preview_temp_load img{
    vertical-align:middle;
    text-align:center;
}
The output of the code follows:





download the working copy of the source code in C# here and in VB here.

9 Responses to “How to Show Image stored in Database in ToolTip on Mouseover of GridView row”

  • Bella says:
    31 May 2011 at 10:48

    Can you send me the source code Please?
    My email: b020910196@student.utem.edu.my
    thx...

  • Sahil Verma says:
    29 July 2012 at 20:42

    Your job is Awesome.... May i hv d Full Package of Source Code please...
    my ID is sahil_gnr@hotmail.com
    This will help me better...
    THANXXX.....

  • Anonymous says:
    7 May 2013 at 16:19

    data type 's("ProductImage") in database is varchar, it's a path,it's not image, example "Images/image1.jpg". How can I show this field?

  • Thirumalai M says:
    7 May 2013 at 19:12

    Hi, Can you try the following url -

    http://www.dotnettwitter.com/2010/11/sometime-back-i-got-assignment-to-show.html

  • Tran De says:
    7 May 2013 at 20:40

    Thirumalai M says:
    7 May 2013 19:12

    Hi, Can you try the following url -

    http://www.dotnettwitter.com/2010/11/sometime-back-i-got-assignment-to-show.html
    ___________________________________
    Can you send me a demo file? I'm trying very much but it's not work. So bad

  • sn0wman says:
    7 May 2013 at 20:53

    My database in field "ProductImage" is a path.Data type is varchar.
    "unable to cast object of type system.string to type system.byte[]".

  • Thirumalai M says:
    7 May 2013 at 22:10

    Hi, I just tried the same example. It works fine.

    For information, I am using Northwind database in this example. The Product table is used o fetch the values. I also added a new column in the table "ProductImage". So to test this example, you required to add that column. Run the below command to add the column.

    alter table Products add ProductImage image

    You required to store the image file in this column. You can use another post, which store images in the table.

    http://www.dotnettwitter.com/2010/12/storing-images-into-database-and.html

  • sn0wman says:
    8 May 2013 at 00:18

    Thank you very much

  • Anil Choudhary says:
    3 January 2014 at 15:40

    thanx for your help...it works fine

Post a Comment