Geeks With Blogs
Create Fun Things - Samer's Developer Blog Development Blog for C#, .NET and Obj-C

I had looked up the LoadControl(“”) method earlier today, and came upon a short website entry that quickly discussed how to load a web user control (.ascx) dynamically onto a page. The link is:

http://www.codeproject.com/KB/aspnet/LoadingUSerControl.aspx

It mentioned inside that a CMS (content management system) could be built using this method + a database table to track these controls. It got me intrigued, so I decided to pursue it. It’s pretty simple, and actually adds a lot of cool functionality to some of my pages.

I started off by adding this table to my database:

image

Nothing too fancy here—Just a name, the URL of the control, and then a timestamp column so that one day I can dynamically manage these and use LINQ to SQL to take care of ChangeTracking. Anyway, so the backend is now ready to go.

I have a web.config with all the major web user controls in my project defined, with a name. That way I can just type in something like <MyProgram:MyControl> in my .aspx pages, without having to drag/drop and register them individually. Here’s an example:

<addtagPrefix="KFNet" src="~/UserControls/Blog/ReadBlog.ascx" tagName="ReadBlogEntry"/>


So what if I wanted to load this user control dynamically on a page? Or even one day enable a user to add it to a portal style page? I wrote an entry in my database to match up pretty much exactly what this XML entry looks like. I made its name “ReadBlogEntry” and its url “~/UserControls/Blog/ReadBlog.ascx”

I wrote a custom method in a partial class of my LINQ to SQL object, and it looks like this:

public static string ReturnURLByName(string Name)
        {
            KfNetUserControl webControl = new KfNetUserControl();
            webControl = webControl.SelectCached().FirstOrDefault(m => m.Name == Name);
            if (webControl != null)
            {
                return webControl.URL;
            }
            else
            {
                throw new RecordNotFoundException(
string.Format("Failed to find the URL of the user control based off the name, {0}. Please check the method call.",Name));
            }
        }

You can write this method anyway you’d like, but basically it will select the item from the cached list of user control entries, and return the URL of it. I can then just call this method whenever I want to load a control, and all I need is its name as specified in the web.config / database record. I made it throw an exception if the entry was not found, so that if I mistype a name, I know immediately why a control isn’t loading properly.

Now comes the cool part. I have a webpage that I want to be able to dynamically load web user controls when the user clicks a button. I want the control to appear inside a Modal Pop Up, so that it keeps them in-page. Here is a snippet from the .aspx page code:

<asp:UpdatePanel runat="server" ID="UpdatePanelPage">
                <ContentTemplate>
                    <asp:LinkButton runat="server" ID="EmptyButton" />
                    <ajaxToolkit:ModalPopupExtender runat="server" ID="GeneralModalPopUp" PopupControlID="ModalPopUpPanel"
                        TargetControlID="EmptyButton" OkControlID="OkButton" CancelControlID="CancelButton"
                        EnableViewState="false" BackgroundCssClass="modalBackground" />
                    <asp:Panel runat="server" ID="ModalPopUpPanel" CssClass="LargeModalPopUp" Style="display: none;
                        vertical-align: middle;">
                        <asp:UpdatePanel runat="server" ID="UpdatePanelModalPopUp">
                            <ContentTemplate>
                                    <asp:PlaceHolder runat="server" ID="DynamicPlaceHolder" />
                            </ContentTemplate>
                        </asp:UpdatePanel>
                        <asp:Button runat="server" ID="OkButton" Text="Ok" />
                        <asp:Button runat="server" ID="CancelButton" Text="Close" />
                    </asp:Panel>

 

Nothing too unusual going on in here. I have a page that’s in an UpdatePanel (for my own reasons) and then a ModalPopUpExtender and its required controls (Panel, Ok/cancel button,etc.) The key thing here is to place an UpdatePanel inside the Modal pop-up Panel, because you will be adding the web user control dynamically. I added a placeholder inside because if I eventually want to add more controls to this UpdatePanel, I need to control exactly where my user control will be added. The placeholder acts as….a placeholder, for my control.

You might also notice I have a LinkButton with an ID of “EmptyButton” and no text value set. I do this because if I set the target control ID to the actual button that the user clicks, it will not post-back properly (since it just executes client-side javascript.) There might be some more elegant way of doing this, but this works for me..

This Modal Pop-Up will act as a general modal pop-up, because I can add any control I want to inside of it. So lets say on the page I have several buttons that the user can click. Depending on the button, the custom control will change. The easiest way I found to do this is using CommandName and CommandArgument. Here’s a button snippet:

<asp:LinkButton ID="ReadBlogPopUpButton" runat="server" Text="[Click To Open]" ToolTip="Show a Quick View of this Item"
                            CommandName="PopUpModal" CommandArgument="ReadBlogEntry" OnCommand="PopUpControl_Command" style="color: #FF6633;" />

You will notice it references OnCommand=”PopUpControl_Command” which is a custom method I wrote. Here is the code for it, in my .aspx.cs file:

protected void PopUpControl_Command(object sender, CommandEventArgs e)
    {
        if (e.CommandName == "PopUpModal")
        {
            Control myDynamicControl = LoadControl(KfNetUserControl.ReturnURLByName(e.CommandArgument.ToString()));
            DynamicPlaceHolder.Controls.Add(myDynamicControl);
            GeneralModalPopUp.Show();
        }

    }

So this catch-all command operation will first check to make sure the CommandName is set properly to “PopUpModal” and then it will call my ReturnURLByName method using the CommandArgument.ToString(). I call the .Show() method of the Pop-Up at the end, because if I didn’t ,it wouldn’t show up. This is because of our EmptyButton being the targetID of the extender, and not any other button.

I can now drop in any number of buttons, and all I have to do to make them dynamically generate controls is set their CommandName and CommandArgument, and wire them up to my OnCommand method. No if/else if statements, etc. Very simple!

Cheers,

Samer Paul

Posted on Tuesday, September 8, 2009 12:39 PM | Back to top


Comments on this post: Dynamically Loading Web User Controls Using Database

# re: Dynamically Loading Web User Controls Using Database
Requesting Gravatar...
Hi Samer, thanks for a very helpful post. I've been struggling to achieve the exact same thing for at least two days now... Testing exclusively in Google Chrome I got the modal popup working but without being able to interact with the user control. The entire page is disabled, even the modal window. Its working fine in IE. That I only figured out today after implementing your solution to no avail and out of desperation testing on IE.
Inspecting Google Chrome's JavaScript error, reveals: "Uncaught TypeError: Cannot read property '_notified' of null". Do you perhaps have any thoughts on this and how does this example of yours hold up in Chrome?
Left by Burger Vivier on Nov 10, 2009 8:41 AM

# re: Dynamically Loading Web User Controls Using Database
Requesting Gravatar...
Hi Samer, I found the solution and thought to share...
It turns out there is a JavaScript issue with the AjaxControlToolkit and Webkit related browsers.

To fix the problem, create a .js file containing:

Sys.Browser.WebKit = {}; //Google Chrome; Safari 3 is considered WebKit
if( navigator.userAgent.indexOf( 'WebKit/' ) > -1 )
{
Sys.Browser.agent = Sys.Browser.WebKit;
Sys.Browser.version = parseFloat( navigator.userAgent.match(/WebKit\/(\d+(\.\d+)?)/)[1]);
Sys.Browser.name = 'WebKit';
}

Then reference the .js like this:

<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Scripts/fixWebkit.js" />
</Scripts>
</asp:ScriptManager>

Follow http://forums.asp.net/p/1252014/2392110.aspx for the full discussion.
Left by Burger Vivier on Nov 22, 2009 1:45 AM

Your comment:
 (will show your gravatar)


Copyright © samerpaul | Powered by: GeeksWithBlogs.net