Friday, October 09, 2009

Set Full Image Path in FCK Editor

        We have used FCK editor as an HTML editor for our recent project. It is one the best and easy to integrate HTML editor available free. When I test the editor on local server and it works fine. However when we add image using FCK editor the image path is relative to tour webpage. So if you have created an email template using FCK editor and you sends email to your customers they will not able see the image.

Set Full Image Path in FCK Editor

Fig - (1) Relative Image path in FCK editor

              We need to use full image path in FCK editor to display the image. You can change SetUrl function at following place to set full image path in FCK editor. You can find SetUrl function in fck_image.js fule at “FckEditor\editor\dialog\fck_image”. Below is the original function,

function SetUrl( url, width, height, alt )


{


    if ( sActualBrowser == 'Link' )


    {


        GetE('txtLnkUrl').value = url ;


        UpdatePreview() ;


    }


    else


    {


        GetE('txtUrl').value = url ;


        GetE('txtWidth').value = width ? width : '' ;


        GetE('txtHeight').value = height ? height : '' ;


 


        if ( alt )


            GetE('txtAlt').value = alt;


 


        UpdatePreview() ;


        UpdateOriginal( true ) ;


    }


 


    dialog.SetSelectedTab( 'Info' ) ;


}




Fig - (2) SetUrl function of FCK Editor



          Change GetE(‘txtUrl’).value = url, first line in else condition to GetE(‘txtUrl’).value = “http://www.xyz.com” + url. See the changed line below,





GetE('txtUrl').value = 'http://www.xyz.com' + url ;




Fig - (3) Changed function.



           Save fck_image.js  file and now check the image path. FCK editor will take full image path instead of relative.



Set Full Image Path in FCK Editor 2



Fig - (4) Full Image Path in FCK Editor



 



Set Full path for Flash File



            Same way you have to change fck_flash.js file at FckEditor\editor\dialog\fck_flash folder to set fill flash path in FCK Editor.







 



Happy Programming !!!

Friday, August 21, 2009

AJAX UpdatePanel and UpdateProgress to show please wait

     While refreshing the AJAX skill today I wrote a simple code to display please wait message while asynchronous postback. I added one Update Panel, one Update Progress panel and a button control and registered button  as Asynchronous Postback Trigger control. I assign my UpdatePanel’s id as AssociatedUpdatePanelID to UpdateProgress panel. I ran the code found that Progress panel is not displayed while async postback, strange !!!! Then I remember few basic points regarding Update Panel and Update Progress which is available on MSDN and found that If we set AssociatedUpdatePanelID to Update Progress panel then we must have to button as inside Update Panel if register button as Async Postback trigger then it will not work. Below is the points (that MSDN Suggests) needs to remember while using UpdateProgress,

The AssociatedUpdatePanelID property has the following effect on UpdateProgress control behavior,

When the AssociatedUpdatePanelID property is not set, the UpdateProgress control is displayed for the following postbacks:

  • Postbacks that originate from inside any UpdatePanel control.
  • Postbacks that originate from controls that are asynchronous triggers for any UpdatePanel control.

When the AssociatedUpdatePanelID property is set to an UpdatePanel control ID, the UpdateProgress control is displayed for postbacks that originate from inside the associated UpdatePanel control.

If the AssociatedUpdatePanelID property is set to a control that does not exist, the UpdateProgress control will never be shown.

You must provide client script to display an UpdateProgress control when a target UpdatePanel control is updated in the following circumstances

  • When a postback from a control is registered as an asynchronous postback trigger for the panel, and there is an UpdateProgress control on the page. However, the AssociatedUpdatePanelID property is not set to the panel's ID.
  • When postbacks from controls are registered as asynchronous postback controls by using the RegisterAsyncPostBackControl method of the ScriptManager control. 

Happy Programming!!!!

Thursday, August 20, 2009

Context.RewritePath and Images

     I was reading articles on URL Rewriting in ASP.NET and I found the most common way suggested is to use Context.RewritePath either in global.asax file or in HttpHandler with Application_BeginRequest method. The most common found code is Context.RewritePath(NewURL). When you the application you find it works like a charm and yes it does so!!!!.

     However sometime Images and CSS are not displayed on page when we use Context.RewritePath. Let me be more specific if you have a hierarchy as shown below,

ImagesNotDisplayedContext.RewritePath 

Fig - (1) Website structure

       Now if you have used images on Default2.aspx and also have css for controls. We have redirected user to Default2.aspx page using Context.RewritePath path when there is no specific file available physically. So here if we write the URL http://localhost:3030/Example1/Test.aspx then we are redirected to Default.aspx page and images will be displayed properly. However id you type URL http://localhost:3030/Example1/Products/Test.aspx then we are redirected to Default.aspx page however images will not be displayed.

       Even if you have assign ImageURL using “~/Images/Image1.jpg” you find that images will not be displayed. The image path will always taken as relative path with the URL mentioned in address bar. So in first case the virtual path of image becomes Example1/Images/Image1.jpg while in second case the virtual path of image becomes Example1/Products/Images/Image1.jpg. So in second case images and css will not displayed with Context.RewritePath.

      To solve this use second argument with Context.RewritePath so the function will be Context.RewritePath(NewURL,false) and everything will work fine. if second argument is true reset the virtual path else the virtual path will not be changed. As we want virtual path to be unchanged we have to pass false in second argument.

Pleas read this article for more detail.

Happy Programming !!!!

Thursday, August 13, 2009

How to detect page is loaded

      Sometime we need to find when the page is loaded or page is completely loaded before specific java script function is called.  As we all know if try to access DOM element using document.getElementBtId() before page is loaded or page is completely loaded we get error. So to prevent the error we can user following java script to detect page is loaded?

   1: var body = document.getElementsByTagName('BODY')[0];



   2:  



   3: if (body && body.readyState == 'loaded') {



   4:     AfterLoad();



   5: } else {        



   6:     if (window.addEventListener) {



   7:         window.addEventListener('load', AfterLoad, false);



   8:     } else {



   9:     window.attachEvent('onload', AfterLoad);



  10:     }



  11: }



  12: function AfterLoad() {



  13:     alert("page loaded !!!");



  14: }






Fig (1) – Detect Page is loaded !!



Happy Programming !!!

Tuesday, August 11, 2009

How to set multiple default button in ASP.NET

        In my previous post I mentioned the one way to set default button in ASP.NET. There are few other methods also.  One of them is to use asp panel and set its DefaultButton property. When we need to set multiple default buttons on single page we can do it by using asp panels. Lets consider that you have login control and search control on same page.  User must be redirect to proper page while he press enter on search and login control. Lets look at following code,

<asp:Panel ID="pnlSearch" DefaultButton="btnSearch" runat="server">
    <table width="50%" cellpadding="0" cellspacing="0">
        <tr>
            <td>
                Search :
            </td>
            <td>
                <asp:TextBox ID="txtSerach" runat="server"></asp:TextBox>
            </td>
            <td colspan="2">
                <asp:Button  ID="btnSearch" runat="server" Text="Search" OnClick="btnSearch_Click" />
            </td>
        </tr>
    </table>
</asp:Panel>

Fig - (1) Default Button with asp panel in ASP.NET


        You can add multiple asp panel and set default button for each panel. I found this as the easiest way to set multiple default button in asp.net.


         Lets look at how default button works. First step is to observe the rendered HTML,



<div id="pnlSearch" onkeypress="javascript:return WebForm_FireDefaultButton(event, 'btnSearch')">
    
    <table width="50%" cellpadding="0" cellspacing="0">
        <tr>
            <td>
                Search :
            </td>
            <td>
                <input name="txtSerach" type="text" id="txtSerach" />
            </td>
            <td colspan="2">
                <input type="submit" name="btnSearch" value="Search" id="btnSearch" />
            </td>
        </tr>
    </table>                        
</div>
 

Fig - (2) HTML code for Default Button with asp panel in ASP.NET


           ASP panel is rendered as DIV.  You may have observer that onkeypress event is added to DIV, onkeypress events calles WebForm_FireDefaultButton(event, 'btnSearch') function. ASP.NET automatically includes WebForm_FireDefaultButton function when default button property is set.   WebForm_FireDefaultButton takes button's ClientID as one of the argument and second argument is event. As Click is the default event of button, button click event will be fired on post back.


          Now take a look at WebForm_FireDefaultButton function,



function WebForm_FireDefaultButton(event, target) {
    if (event.keyCode == 13) {
        var src = event.srcElement || event.target;
        if (!src || (src.tagName.toLowerCase() != "textarea")) {
            var defaultButton;
            if (__nonMSDOMBrowser) {
               defaultButton = document.getElementById(target);
            }
            else {
                defaultButton = document.all[target];
            }
            if (defaultButton && typeof(defaultButton.click) != "undefined") {
                defaultButton.click();
                event.cancelBubble = true;
                if (event.stopPropagation) event.stopPropagation();
                return false;
            }
        }
    }
    return true;
}

Fig (3) - WebForm_FireDefaultButton function included with default button


        When user press the enter key while the focus is set to any control within DIV it calls WebForm_FireDefaultButton function.


Few interesting articles you may like to read,


http://scottonwriting.net/sowblog/posts/13698.aspx


http://weblogs.asp.net/rternier/archive/2007/10/17/updatepanel-firefox-and-the-defaultbutton.aspx


http://forums.asp.net/t/1409941.aspx 


Happy Programming !!!

Wednesday, May 20, 2009

Maintain Viewstate for Dynamic controls across the postback

       Most of us have faced the case when we have to load the controls dynamically. We can load user control by calling LoadControl method. To load inbuilt server controls we can use Page.Form.Controls.Add() method or we can user any container like panel or place holder and call Controls.Add() method. Upto this it looks very easy and works fine. However at first postback you either find the control is not loaded or the viewstate is not preserved for that control.

        Lets take an example, we have a user control with only one textbox inside it and a web for which have two buttons LoadControl and Submit. When user clicks on LoadControl button we will load the user control and on Submit button we just submit the form so that postback occurs.

   1: <%@ Control Language="C#" AutoEventWireup="true" CodeFile="ucTestControl.ascx.cs"
   2:      Inherits="ucTestControl" %>
   3: <asp:TextBox ID="txtName" runat="server"></asp:TextBox>

Fig - (1) User control with only a textbox.



   1: <%@ Page Language="C#" AutoEventWireup="true" 
   2: CodeFile="LoadUserConrtolDynamically.aspx.cs"
   3:     Inherits="LoadUserConrtolDynamically" %>
   4:  
   5: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
   6: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   7: <html xmlns="http://www.w3.org/1999/xhtml">
   8: <head runat="server">
   9:     <title>Dynamically Load User Control</title>
  10: </head>
  11: <body>
  12:     <form id="form1" runat="server">
  13:     <div>       
  14:         <table>            
  15:             <tr>
  16:                 <td colspan="2">
  17:                     Click on "Load Control" button to load user control dynamically.
  18:                 </td>
  19:             </tr>
  20:             <tr>
  21:                 <td>
  22:                     <asp:Button ID="btnLoad" runat="server" Text="Load Control" OnClick="btnLoad_Click" />
  23:                 </td>
  24:                 <td>
  25:                     <asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
  26:                 </td>
  27:             </tr>
  28:             <tr>
  29:                 <td colspan="2">
  30:                     Enter Name:
  31:                 </td>                
  32:             </tr>
  33:         </table>
  34:     </div>
  35:     </form>
  36: </body>
  37: </html>

Fig - (2) Webform with two buttons. 



   1: protected void btnSubmit_Click(object sender, EventArgs e)
   2: {
   3:     
   4: }
   5:  
   6: protected void btnLoad_Click(object sender, EventArgs e)
   7: {
   8:     AddUserControl();
   9: }
  10:  
  11: private void AddUserControl()
  12: {
  13:     UserControl ucTest = (UserControl)LoadControl("~/ucTestControl.ascx");
  14:     Page.Form.Controls.Add(ucTest);
  15:     IsControlAdded = true;
  16: }

Fig - (3) Code behind for Webform


          As you can see we are calling LoadControl() method to load our user control. Now when you click on submit button and you find that the control disappears.  WHY? The reason is as we have loaded the control the page's control tree does not have its detail so we need to load the control again with each postback. So first rule for lading dynamic control is,


RULE 1 : Load the Dynamic control in each postback


        So in our example we also need to add the control with each postback. However we need to check that whether the control is loaded before postback or not. To check this I have created one property as shown in code below,



   1: public bool IsControlAdded
   2: {
   3:     get
   4:     {
   5:         if (ViewState["IsControlAdded"] == null)
   6:             ViewState["IsControlAdded"] = false;
   7:  
   8:         return (bool)ViewState["IsControlAdded"];
   9:  
  10:     }
  11:     set
  12:     {
  13:         ViewState["IsControlAdded"] = value;
  14:     }
  15: }
  16:  
  17: protected void Page_Load(object sender, EventArgs e)
  18: {
  19:     if(IsControlAdded)
  20:         AddUserControl();
  21: }
  22:  
  23: protected void btnSubmit_Click(object sender, EventArgs e)
  24: {        
  25: }
  26:  
  27: protected void btnLoad_Click(object sender, EventArgs e)
  28: {
  29:     if(!IsControlAdded)
  30:         AddUserControl();
  31: }
  32:  
  33: private void AddUserControl()
  34: {
  35:     UserControl ucTest = (UserControl)LoadControl("~/ucTestControl.ascx");
  36:     Page.Form.Controls.Add(ucTest);
  37:     IsControlAdded = true;
  38: }

Fig - (4) loading dynamic control with each postback.


         You may have notice the code the code for lading user control,



   1: UserControl ucTest = (UserControl)LoadControl("~/ucTestControl.ascx");
   2: Page.Form.Controls.Add(ucTest);

Fig - (5) Code for loading User control Dynamically


        You may also write this two line code in single line as shown below,



   1: Page.Form.Controls.Add(LoadControl("~/ucTestControl.ascx"));

Fig - (6) Code for loading Dynamic Control


        If you use this code to load user control dynamically than sometime you find an interesting issue. The viewstate is not maintained for dynamically loaded control !!!!!! The viewstate requires the controls ID to store the viewstate properly. So always use code shown in Fig - (4) to load user control dynamically.


RULE 2 : Always load the Dynamic control by assigning it to one temporary variable so that it has unique id.


       One more common mistake is we write Page.Controls.Add() to add the control. This will leads to "Control 'ControlName' of type 'ControlType' must be placed inside a form tag with runat=server" error.


       Now we have to find how the viewstate is maintained for dynamically loaded user control. I will suggest you to read this article first. When we add any control dynamically it play "catch-up" with the page life cycle once they are added. Once the control is added to the "Controls" collection, it plays "catch-up" with the page life cycle, and all the events that it missed are fired. This leads to a very important conclusion: you can add dynamic controls at any time during the page life cycle until the "PreRender" event. Even when you add the dynamic control in the "PreRender" event, once the control is added to the "Controls" collection, the "Init", "LoadViewState", "LoadPostbackdata", "Load", and "SaveViewstate" are fired for this control.


     We have seen how to load user controls dynamically now we will see how to load inbuilt server controls.  The process is same however we don't have to use LoadControl method, we can directly use Controls.Add() method as shown below,



   1: TextBox tempText = new TextBox();
   2: tempText.ID = LstTextBoxId.Count.ToString();
   3: // pnlTextBox is asp:Panel
   4: pnlTextBox.Controls.Add(tempText);

Fig - (7) Load server controls at runtime and maintaining viewstate


        Here we have added server controls and user controls dynamically using regular way. You can load user controls / server control dynamically using AJAX also. Below is the code where I have displayed loading controls using AJAX and normal way.



<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="LoadUserConrtolDynamically.aspx.cs"
    Inherits="LoadUserConrtolDynamically" %>
 
<!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>Dynamically Load User Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <table>
            <tr>
                <td colspan="2">
                    Click on "Add Textbox" button to add texbox dynamically.
                </td>
            </tr>
            <tr>
                <td>
                    <asp:Button ID="btnAddTextBox" runat="server" Text="Add Textbox" OnClick="btnAddTextBox_Click" />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <asp:Panel ID="pnlTextBox" runat="server">
                    </asp:Panel>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <asp:Label ID="lblTest" runat="server"></asp:Label>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <br />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    Click on "Add Textbox using Ajax" button to add texbox dynamically with Ajax.
                </td>
            </tr>
            <tr>
                <td>
                    <asp:UpdatePanel ID="upnlLOadControl" runat="server">
                        <ContentTemplate>
                            <asp:Button ID="btnAddTextBoxAjax" runat="server" Text="Add Textbox using Ajax" OnClick="btnAddTextBoxAjax_Click" />
                            <asp:Panel ID="pnlAjaxTextbox" runat="server">
                            </asp:Panel>
                        </ContentTemplate>
                    </asp:UpdatePanel>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <br />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    Click on "Load Control" button to load user control dynamically.
                </td>
            </tr>
            <tr>
                <td>
                    <asp:Button ID="btnLoad" runat="server" Text="Load Control" OnClick="btnLoad_Click" />
                </td>
                <td>
                    <asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    Enter Name:
                </td>                
            </tr>
        </table>
    </div>
    </form>
</body>
</html>

Fig - (8) code for aspx page.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
public partial class LoadUserConrtolDynamically : System.Web.UI.Page
{
    public bool IsControlAdded
    {
        get
        {
            if (ViewState["IsControlAdded"] == null)
                ViewState["IsControlAdded"] = false;
 
            return (bool)ViewState["IsControlAdded"];
 
        }
        set
        {
            ViewState["IsControlAdded"] = value;
        }
    }
 
    public List<String> LstTextBoxId
    {
        get
        {
            if (ViewState["LstTextBoxId"] == null)
                ViewState["LstTextBoxId"] = new List<String>();
 
            return (List<String>)ViewState["LstTextBoxId"];
 
        }
        set
        {
            ViewState["LstTextBoxId"] = value;
        }
    }
 
    public List<String> LstAjaxTextBoxId
    {
        get
        {
            if (ViewState["LstAjaxTextBoxId"] == null)
                ViewState["LstAjaxTextBoxId"] = new List<String>();
 
            return (List<String>)ViewState["LstAjaxTextBoxId"];
 
        }
        set
        {
            ViewState["LstAjaxTextBoxId"] = value;
        }
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        if(IsControlAdded)
            AddUserControl();
 
        if (LstTextBoxId.Count > 0)
            AddTextBoxes(pnlTextBox, LstTextBoxId);
 
        if (LstAjaxTextBoxId.Count > 0)
            AddTextBoxes(pnlAjaxTextbox, LstAjaxTextBoxId);
    }
 
    protected void btnSubmit_Click(object sender, EventArgs e)
    {        
    }
 
    protected void btnLoad_Click(object sender, EventArgs e)
    {
        if(!IsControlAdded)
            AddUserControl();
    }
 
    private void AddUserControl()
    {
        UserControl ucTest = (UserControl)LoadControl("~/ucTestControl.ascx");
        Page.Form.Controls.Add(ucTest);
        IsControlAdded = true;
    }
 
    private void AddTextBoxes(Panel pnlTemp,List<String> lstTemp)
    {
        TextBox tempText;
        for (int i = 0; i < lstTemp.Count; i++)
        {
            tempText = new TextBox();
            tempText.ID = lstTemp[i];
            pnlTemp.Controls.Add(tempText);
        }
    }
 
    protected void btnAddTextBox_Click(object sender, EventArgs e)
    { 
        TextBox tempText = new TextBox();
        tempText.ID = LstTextBoxId.Count.ToString();
        pnlTextBox.Controls.Add(tempText);
        LstTextBoxId.Add(LstTextBoxId.Count.ToString());
    }
 
    protected void btnAddTextBoxAjax_Click(object sender, EventArgs e)
    {
        TextBox tempText = new TextBox();
        tempText.ID = Guid.NewGuid().ToString();
        pnlAjaxTextbox.Controls.Add(tempText);
        LstAjaxTextBoxId.Add(tempText.ID);
    }
}

Fig - (9) Code for aspx.cs page



<%@ Control Language="C#" AutoEventWireup="true" 
CodeFile="ucTestControl.ascx.cs" Inherits="ucTestControl" %>
<asp:TextBox ID="txtName" runat="server"></asp:TextBox>

Fig - (10) Code for user control


 


Happy Programming !!!