Convert ASPX pagename to Page Control

Posted on 2011-03-12
Last Modified: 2012-05-11
With previous assistance from Experts Exchange members I've written a recursive routine to loop through all the controls on an ASP.NET 1.1 page to assign images and tooltips from a database.
    ' Recursively set the ImageUrl and ToolTip for Images and Image Buttons
    ' together with the ToolTip for Mandatory fields. This is a modified version 
    ' that gets the tooltip from the ToolTips table and the ImageURL from the
    ' ControlNames table
    Public Sub SetIconImages(ByVal Page As Control, ByVal WebPageName As String)

        For Each ctrl As Control In Page.Controls

            If TypeOf ctrl Is ImageButton Then
                CType(ctrl, ImageButton).ImageUrl = GetSpecificImageURL(ctrl.ID.ToString)
                CType(ctrl, ImageButton).ToolTip = GetSpecificToolTip(WebPageName, ctrl.ID.ToString)
            ElseIf TypeOf ctrl Is Image Then
                If Left(ctrl.ID.ToString, 4) = "tti_" Then
                    CType(ctrl, Image).ImageUrl = GetSpecificImageURL(ctrl.ID.ToString)
                    CType(ctrl, Image).ToolTip = GetSpecificToolTip(WebPageName, ctrl.ID.ToString)
                End If
                If System.Configuration.ConfigurationSettings.AppSettings(ctrl.ID.ToString) Is Nothing Then
                    CType(ctrl, Image).AlternateText = "Assign an Image in the Web.config file to this key: " + ctrl.ID.ToString
                    CType(ctrl, Image).ImageUrl = System.Configuration.ConfigurationSettings.AppSettings(ctrl.ID.ToString)
                End If
            ElseIf TypeOf ctrl Is Label Then
                If CType(ctrl, Label).Text = "M" Then
                    CType(ctrl, Label).ForeColor = Drawing.Color.Silver
                    CType(ctrl, Label).ToolTip = "Mandatory Field: This will turn red if invalid or incomplete data is detected"
                ElseIf CType(ctrl, Label).Text = "9" Or CType(ctrl, Label).Text = "D" Or CType(ctrl, Label).TemplateSourceDirectory = "V" Then
                    CType(ctrl, Label).ForeColor = Drawing.Color.Silver
                    CType(ctrl, Label).ToolTip = "Optional Field: This will turn red if invalid or incomplete data is detected"
                End If
                If ctrl.Controls.Count > 0 Then
                    SetIconImages(ctrl, WebPageName)
                End If
            End If
    End Sub

Open in new window

. This is called from each page when it is first loaded and works fine.  
With clsGenericFunctions.GetInstance
                .SetIconImages(Me, .GetCurrentPageName)
            End With

Open in new window

I want to be able to do the same thing from a generic page, i.e. to let an administrative user see all the controls on a selected page and add image urls and/or tooltips. The problem I can't resolve is how to convert the page name I have in a listbox, e.g. MCR.aspx, back into a Page Control to pass to this routine instead of passing the varialble 'Me'. I know how to get the ID and ClientID to get the actual page name (MCR.aspx) but not how to do this in reverse.

I display a list of all the Page names, then when I select one I want call a routine that looks something like this:
Public Sub GetControlNames(ByVal Page As Control, ByVal WebPageName As String, ByVal ArrayCtrl As ArrayList)

        For Each ctrl As Control In Page.Controls

Open in new window

. The Page variable needs to be the equivalent of {asp.MCR_aspx} as a Control but I can't get this conversion to work.

I'm sure it's not too difficult for someone with more experience but any assistance will be greatly appreciated.  
Question by:pstanford
  • 3
  • 3

Assisted Solution

_kiwi_ earned 300 total points
ID: 35121388

The method you are using is not a method I would recommend. Getting a recursive loop go through all your controls to have their properties modified is to me the wrong way, I would prefer modifying my layout in order to have my controls load their properties from the database (i.e. by subclassing the controls I use to have them load their content, or by using "<%# GetResourceByName(...) %>", a databinding handler that will get the data out of the database.

I see a few mistakes in your loop, you take control ID to go through the database:
- what if two controls have the same ID in the page ? (i.e. you load two UserControls that both have a "Title" label, but they mean different things)
- what would you do if the control has no ID attribute ?

If you want to have the ID of that specific control, use UniqueID property, and since they are already strings, please don't use ".ToString", because if not set you will raise an error (null reference exception) for calling ToString on a null string. But then again, what would you do if the order of the controls in the page changed ? UniqueId would change, and your database would not be consistent, and tooltips would be wrong. Same with databound controls, UniqueId changes for each item and each line, this would not work.

For your question, if you still want to go down that path, it is pretty complicated to load a page as a control from another page, what I would recommend is to call the initial url (MCR.aspx) and add it a paramater that would change the behavior of your SetIconImages to have the names saved in the database instead of read from the database.

But then again, imagine you have databound controls depending on the data, if you use templating (ITemplate), nothing would guarantee you that your recursive loop would find every control in the page, since these controls are instanciated with the data.

My recommendation is for you to add to your BasePage and default UserControl, or to make available through a static property, a function GetResource() that will take the current page URL (something like HttpRequest.Current.FilePath.Substring(HttpRequest.Current.ApplicationPath)), a data type (url, title, tooltip), a name, and the parameters you will use in that name (the values {0} {1} you will use in your string.format). Another option could be a ressourcemanager ( which is the default .Net 1.1 way to do this.

e.g. (coded in the browser, so not tested):

Public Sub GetResource(ByVal Type As String, ByVal ResourceID As String, ParamArray args As Object())
  Dim PageUrl As String = HttpRequest.Current.FilePath.Substring(HttpRequest.Current.ApplicationPath))
  ' Load data from database (select ResourceValue = value from resources where page = PageUrl and type = Type and resourceID = ResourceID), into string ResourceValue, using SqlConnection and SqlParameter
  GetResource = string.Format(CultureInfo.CurrentUICulture, ResourceValue, args)
End Sub

In your page, you would then have
<asp:imagebutton runat="server" imageUrl='<%# GetResource("Url", "MyImageButton") %>' tooltip='<%# GetResource("Tooltip", "MyImageButton") %>'/>

Some points of attention:
- ResourceIDs must be unique in a page
- warning about " (double quotes) and ' (single quote) in tag attributes with <%#, you should use ' outside and " inside otherwise you will have an invalid tag error thrown
- make sure you have at least one page level databind event (at onload if no postback sent) to enable <%# to work properly

Hope this helps,

Author Comment

ID: 35123655
Thanks for the very detailed response but this is way more complex than I need it to be. I'm simply trying to automate the management of images and tooltips. I have two existing tables and a link table. The first table (ControlNames) contains names of controls but by controls I mean standard controls like buttons, image buttons and images, no user controls.
 ControlNames Table DesignThe second table (WebPageNames) contains names of the .aspx pages within the application.
 WebPageNames Table DesignThe third table (ToolTips) contains references to the WebPageNames and ControlNames tables, i.e. the same control can be used on multiple pages with the same image (for Image Buttons and Images) but a different ToolTip, depending on the context.
 ToolTips Table DesignI can, using a routine similar to the one contained in the first post, iterate through the controls on any given page and get the names of those controls, look up both the image and the tooltip and apply them dynamically at runtime. If I build that functionality into each of the pages I can also push any control names back into the database and also into the link table.

I was just hoping to be able to do this in one generic function rather than having to repeat the code, so while I'm sure your solution is architecturally way more elegant than mine, this is an internal application with a known number of users and I just want the administrator to control the tooltips that are applied rather than hardcode them into the application.

I've manually created the entries in the ControlNames and WebPageNames tables but it seems like there must be a simpler way to do this through a generic routine that I call from each page rather than coding on each page. The following images show samples of the data in the ControlNames and ToolTips tables.
 ControlNames Sample Data ToolTips Sample Data
This application will ultimately be replaced by a new Silverlight application so I don't want to waste too much time on it and only an Administrator would load a page and request a list of Controls from a different page so there wouldn't be a performance issue. I'd just like to now how to do this using a generic routine.

I do appreciate your response but don't think it addresses the issue as simply as I'd like it to do.

Assisted Solution

_kiwi_ earned 300 total points
ID: 35125756

I recommend then having your "SetIconImages" function changed to check for a "process" argument in the URL, and of this parameter is present, instead of calling GetSpecific... You shall call a SaveSpecific... which would simply call the insert statement in your db if this control does not already exist.

You can then use your dropdown to populate an hidden iframe with the target page, with the "process" parameter set.

Finally, to have your administrator modify the contents, simply develop a page that will display an editable datatable from the names found in the db, and you'll be set.

Make sure your method is called late (prerender or render), and check that your controls ids are not null.

Hope this helps,

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.


Accepted Solution

pstanford earned 0 total points
ID: 35159987
Each of the answers above has been useful from a learning perspective but I've not implemented any of this as part of the solution. While not elegant, I've simply implemented a procedure which I call, rather than the user, to generate the list of controls I want and populate those into the database. I then generate a script that can be run against the user's database to populate the appropriate tables. These controls do not change unless I make specific changes to a page in which case I'll regenerate and resynchronise the controls in the database.

The reason for the recursive loop is to address the fact that controls are contained in different sections of a page, for example, in tables that contain tables with named rows so I can collapse/expand them. Again this may not be the most elegant way to do this but it works and there isn't much money in the project, certainly not enough to make wholesale changes to the architecture at this point.

Having said all that, I'm happy to split the points as the quality of feedback and responsiveness was excellent.

Expert Comment

ID: 35163154
Thanks about that.

In the end, whatever the choice you are making, it is yours and it has to answer your specific contraints, after all you are the one coding.

Hava a Nice day.

Author Closing Comment

ID: 35187445
The techniques were useful but none of them were implemented in order to address the problem

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Sometimes in DotNetNuke module development you want to swap controls within the same module definition.  In doing this DNN (somewhat annoyingly) swaps the Skin and Container definitions to the default admin selections.  To get around this you need t…
In .NET 2.0, Microsoft introduced the Web Site.  This was the default way to create a web Project in Visual Studio 2005.  In Visual Studio 2008, the Web Application has been restored as the default web Project in Visual Studio/.NET 3.x The Web Si…
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

856 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