Solved

Problem with Image controls in ASP.NET

Posted on 2011-09-11
11
213 Views
Last Modified: 2012-05-12
I have a web page that contains images in a Panel control.  The images are loaded with a CssStyle of "borders_off".

I am using Javascript to change the style sheet applied to an image when the image is clicked to mimic selecting the image:

function SetClass(obj){
    if (obj.className == 'borders_on')
    {
        obj.className='borders_off';
    }
    else
    {
        obj.className='borders_on';
    }

I have a button on the Page that when clicked I want to look for all images whose ClassName is 'borders_on'.  Right now I am just printing the value and the problem is all  the images show borders_off even though the images have been clicked.  Here is the code:

        Dim img As Image
        If CurrentPanel.HasControls Then

            For Each ctrl As Control In CurrentPanel.Controls
                If ctrl.GetType.ToString = "System.Web.UI.WebControls.Image" Then
                    Label1.Text = Label1.Text & ctrl.ID & ", " & TryCast(ctrl, Image).CssClass & "<br />"
                End If
            Next
        End If

What do I need to do so that the current state of the image control is returned when the image is clicked?  Any help is greatly appreciated.
0
Comment
Question by:dyarosh
  • 6
  • 5
11 Comments
 
LVL 38

Expert Comment

by:Tom Beck
Comment Utility
Assuming that I understand clearly what you are trying to accomplish, I think this can be best achieved on the client side with javascript.

Here's a sample page that has four images (substitute your own). When an image is clicked, it gets a border. When the button is clicked, all borders turn off.
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm2.aspx.vb" Inherits="testApp.WebForm2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
<style type="text/css">    
    .borders_off {border:none}
    .borders_on {border: solid 2px blue} 
    </style>
</head>
<body>

<form id="form1" runat="server">
    
          <asp:Panel ID="imagesPnl" runat="server">
                <img id="Img0" class="borders_off" src="images/red75.jpg" alt="" onclick="turnOnBorder(this)" /> 
                <img id="Img1" class="borders_off" src="images/red75.jpg" alt="" onclick="turnOnBorder(this)" />
                <img id="Img2" class="borders_off" src="images/red75.jpg" alt="" onclick="turnOnBorder(this)" />
                <img id="Img3" class="borders_off" src="images/red75.jpg" alt="" onclick="turnOnBorder(this)" />
          </asp:Panel> 
          <input type="button" id="borderOff" value="Turn Off Borders" onclick="turnOffBorders()" />    
</form>
<script type="text/javascript">
function turnOnBorder(img) {
    img.className = "borders_on";
}
function turnOffBorders() {
    var allImages = document.getElementsByTagName("img");
    for (i=0; i<allImages.length; i++) {
        if (allImages[i].className == 'borders_on') {
            allImages[i].className = 'borders_off';
        }
    }
}
</script>
</body>
</html>

Open in new window

0
 
LVL 38

Expert Comment

by:Tom Beck
Comment Utility
Are you using <asp:Image controls or html <img controls?
0
 

Author Comment

by:dyarosh
Comment Utility
I already have the code for turning the borders on and off.  What I need is to determine which images have been clicked when a submit button is clicked.  This is going to be done from the server side.  When I look at the images on the server side, all of the styles are borders_off even though I've checked some pictures and the borders have been turned on.

I am setting up the images dynamically using <asp:image>.  Here is the code I am using:
        Dim cnt As Integer = 1
        For Each img In nodeList
            Dim imgTemp As New Image
            imgTemp.ID = "CurImage" & cnt.ToString
            imgTemp.CssClass = "borders_off"
            imgTemp.ImageUrl = img.InnerText
            imgTemp.Attributes("onclick") = "SetClass(this);"
            CurrentPanel.Controls.Add(imgTemp)
            Dim HRlitCTRL As New LiteralControl
            HRlitCTRL.Text = "<hr/>"
            CurrentPanel.Controls.Add(HRlitCTRL)
            cnt = cnt + 1
        Next
0
 

Author Comment

by:dyarosh
Comment Utility
I am including the code that I have in my On_Load function.  I put all of the code inside the IF statement and when I hit my Remove button, I didn't get anything printed.  Does the load function get called before the RemoveBtn_Click function?
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        ' If form has not been submitted then check for valid access
        If Not Page.IsPostBack Then
            ' Check if user is logged in and if not redirect to login page
            If Not DB.LoggedIn() Then
                Response.Buffer = True
                Response.Redirect("login.aspx")
            End If

            ' Check if user has access to requested page and if not display error message
            accessGranted = DB.PageAccess(DB.LoginID, DB.FileUploadPage)
            If Not accessGranted Then
                Response.Buffer = True
                Response.Redirect("noaccess.aspx")
            End If

        End If

        ' Load images.xml
        Dim xmlDoc As New XmlDocument
        xmlDoc.Load(Server.MapPath("images.xml"))

        Dim nodeList As XmlNodeList
        Dim root As XmlNode = xmlDoc.DocumentElement
        Dim img As XmlNode
        nodeList = root.SelectNodes("descendant::image")

        ' Add curent pictures to Current Panel
        Dim cnt As Integer = 1
        For Each img In nodeList
            Dim imgTemp As New Image
            imgTemp.ID = "CurImage" & cnt.ToString
            imgTemp.CssClass = "borders_off"
            imgTemp.ImageUrl = img.InnerText
            imgTemp.Attributes("onclick") = "SetClass(this);"
            CurrentPanel.Controls.Add(imgTemp)
            Dim HRlitCTRL As New LiteralControl
            HRlitCTRL.Text = "<hr/>"
            CurrentPanel.Controls.Add(HRlitCTRL)
            cnt = cnt + 1
        Next

        ' Add pictures from images/HomePics folder
        ' make a reference to a directory
        Dim di As New IO.DirectoryInfo(Server.MapPath("images/HomePagePics"))
        Dim diar1 As IO.FileInfo() = di.GetFiles()
        Dim dra As IO.FileInfo
        Dim ext As String

        'list the names of all files in the specified directory
        For Each dra In diar1
            ' Only allow .jpg, .jpeg, .png and .gif files 
            ' Get File Extension
            If dra.Name.LastIndexOf(".") <> -1 Then
                ext = dra.Name.Substring(dra.Name.LastIndexOf(".") + 1)
                If ext.ToUpper = "JPG" Or ext.ToUpper = "JPEG" Or ext.ToUpper = "PNG" Or ext.ToUpper = "GIF" Then
                    Dim imgTemp As New Image
                    imgTemp.ID = "AvailImage" & cnt.ToString
                    imgTemp.CssClass = "borders_off"
                    imgTemp.ImageUrl = "images/HomePagePics/" & dra.Name
                    imgTemp.Attributes("onclick") = "SetClass(this);"
                    AvailablePanel.Controls.Add(imgTemp)
                    Dim HRlitCTRL As New LiteralControl
                    HRlitCTRL.Text = "<hr/>"
                    AvailablePanel.Controls.Add(HRlitCTRL)
                    cnt = cnt + 1
                End If
            End If
        Next
    End Sub

Open in new window

0
 
LVL 38

Expert Comment

by:Tom Beck
Comment Utility
Yes, the Page_Load function runs first with each postback so your image's class is being reset to "borders_off" before the RemoveBtn_Click function.

There is another problem you will need to overcome. There's a bug associated with asp:Image controls. All asp:Image controls are rendered to the page with the following inline css:  style="border-width:0px;". Changing the class from borders_on to borders_off will have no affect because the inline style will take precedence over a class definition. Consider using standard html <img elements with a runat="server" attribute.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 38

Expert Comment

by:Tom Beck
Comment Utility
Here's my suggestion. Load your images into standard <img tags on Page_Load like this.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim imgString As String = String.Empty
        Dim fakeSrc As String = "images/red75.jpg" 'In the loop, substitute your image sources from XML instead
        For i As Integer = 0 To 10
            imgString &= "<img src=""" & fakeSrc & """ alt="""" id=CurImage" & i & " class=""borders_off"" onclick=""SetClass(this)"" runat=""server"" /><hr />"
        Next
        Me.CurrentPanel.Controls.Add(New LiteralControl(imgString))
    End Sub

Then on the client side, use javascript to record the current state of the selected images (borders_on) using an asp:HiddenField that you can then access in codebehind.


<asp:Panel ID="CurrentPanel" runat="server"></asp:Panel>  
<asp:HiddenField ID="selectedImages" runat="server" />

<script type="text/javascript">
var hiddenField = document.getElementById('<%= selectedImages.ClientID %>').value;
function SetClass(obj){
    if (obj.className == 'borders_on')
    {
        obj.className='borders_off';
    }
    else
    {
        obj.className='borders_on';
    }
    //Record the current state of selected images
    hiddenField = '';
    var imagePanel = document.getElementById('<%= CurrentPanel.ClientID %>');
    var allImages = imagePanel.getElementsByTagName('img');
    for (i=0; i<allImages.length; i++) {
        hiddenField += allImages[i].id + '_' + allImages[i].className + ',\n\r';
    }
    alert(hiddenField); //This is just for testing purposes
}
</script>

Open in new window

0
 

Author Comment

by:dyarosh
Comment Utility
I must be doing something wrong with the way I've setup my page.  I used your code and when I click on the images, the alert displays the proper value for the classname.  However once the remove button is clicked, the hidden field no longer has the values.  It's like the state isn't being preserved.

If I put the coding of the loading of the images inside an If Not Page.IsPostBack the images no longer appear in the panel when the Remove Button is clicked.

What could be causing this?
0
 
LVL 38

Expert Comment

by:Tom Beck
Comment Utility
Sounds like your Remove button is causing a postback.

Since the images are loaded dynamically on Page_Load, they need to be loaded each time the page is posted back. Putting the image loading code inside an "If Not Page.IsPostBack" would load images only on the initial load. Also, any round trip postback would clear the hidden field, but you can capture the hidden field's value on the server side during a postback.

If I understand correctly, the Remove button is there simply as a convenience to users to allow them to deselect all the images and start over. Is this correct? If so, then there's no need for the Remove button to do a postback. Borders can be turned off on the client side using javascript. For the button, use a standard HTML input for this, not an asp:Button which causes a postback. When the button is clicked, turn borders off on all images AND clear the hidden field using javascript to reset everything back to start.
0
 

Author Comment

by:dyarosh
Comment Utility
The Remove Button is used to remove the images from the current list.  I do all of the selecting and deselcting on the client side.

 Here is an outline of what I want to do:

Initial Page Load:
Load Current Panel with current images retrieved from an XML document (this I can do)

Allow User To:
Select images (shows a border around the image to mimic a selection - this is done)
Deselect images (remove the border around the image to mimic a selection - this is done)
Remove images  - Post back to server where the images that have the border turned on will be deleted from the XML file and removed from the Current Panel.

I am having the problem with the Remove.  When I click Remove, the images no longer have the border and the value of the hidden field is reset.

Is it possible my Remove button is not a submit button?  Is there a way to check for that?
0
 
LVL 38

Accepted Solution

by:
Tom Beck earned 500 total points
Comment Utility
Sorry for the delay in responding, I am out of town and extra busy.

Looks like I guessed wrong as to the purpose of the remove button. If it is for removing the selected items from the XML file then you are correct that it should cause a postback. The value of the hidden field can be retrieved during the postback on the server side, however it's value was not being set properly in the javascript I provided. If you are using that bit of code, here is the corrected version.
<script type="text/javascript">
var hiddenField = document.getElementById('<%= selectedImages.ClientID %>');
function SetClass(obj){
    if (obj.className == 'borders_on')
    {
        obj.className='borders_off';
    }
    else
    {
        obj.className='borders_on';
    }
    //Record the current state of selected images
    hiddenField.value = '';
    var imagePanel = document.getElementById('<%= CurrentPanel.ClientID %>');
    var allImages = imagePanel.getElementsByTagName('img');
    for (i=0; i<allImages.length; i++) {
        hiddenField.value += allImages[i].id + '_' + allImages[i].className + ',\n\r';
    }
    
    alert(hiddenField.value); //This is just for testing purposes
}
function turnOnBorder(img) {
    img.className = "borders_on";
}
function turnOffBorders() {
    var allImages = document.getElementsByTagName("img");
    for (i=0; i<allImages.length; i++) {
        if (allImages[i].className == 'borders_on') {
            allImages[i].className = 'borders_off';
        }
    }
}
</script>

Open in new window

0
 

Author Closing Comment

by:dyarosh
Comment Utility
Thanks for your help.
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Lots of people ask this question on how to extend the “MembershipProvider” to make use of custom authentication like using existing database or make use of some other way of authentication. Many blogs show you how to extend the membership provider c…
ASP.Net to Oracle Connectivity Recently I had to develop an ASP.NET application connecting to an Oracle database.As I am doing it first time ,I had to solve several problems. This article will help to such developers  to develop an ASP.NET client…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now