This is a migrated thread and some comments may be shown as answers.

Help With "Object Reference Not Set"

4 Answers 133 Views
Ajax
This is a migrated thread and some comments may be shown as answers.
Joshua
Top achievements
Rank 1
Joshua asked on 15 Mar 2010, 06:54 PM
Okay, if I dynamically created a RadAjaxManager in a page's code-behind everything works fine.  I followed the same technique as: http://www.telerik.com/community/forums/aspnet-ajax/ajax/nullreferenceexception-in-radajaxmanager-ajaxsettings-addajaxsetting.aspx

Then, I wanted to dynamically create the RadAjaxManager in a server control.  So I added:
        #region private properties  
          
        private RadAjaxManager _radAjaxManager = null;
        #endregion  
 
        protected override void OnInit(EventArgs e)  
        {  
            RadScriptManager scriptManager = new RadScriptManager();   
            Controls.Add(scriptManager);  
              
            RadAjaxManager radAjaxManager = new RadAjaxManager();  
            radAjaxManager.ID = "radAjaxManager";  
            _radAjaxManager = radAjaxManager;  
            Controls.Add(radAjaxManager);  
              
            base.OnInit(e);   
 
            scriptManager.Scripts.Add(new ScriptReference("Elevate.UI.Scripts.Search.js""Elevate"));  
        }  
 
        protected override void CreateChildControls()  
        {  
            RadAjaxLoadingPanel radAjaxLoadingPanel = new RadAjaxLoadingPanel();  
            radAjaxLoadingPanel.ID = "ajaxLoadingPanel";  
            radAjaxLoadingPanel.Skin = "Default";  
            Controls.Add(radAjaxLoadingPanel);  
 
            /* Child Controls Creation */ 
 
            _radAjaxManager.AjaxSettings.AddAjaxSetting(button1, simplePanel, radAjaxLoadingPanel);  
            _radAjaxManager.AjaxSettings.AddAjaxSetting(linkButton1, simplePanel, radAjaxLoadingPanel);  
            _radAjaxManager.AjaxSettings.AddAjaxSetting(lbMLS, simplePanel, radAjaxLoadingPanel);  
        } 

As you can imagine, I get the dreaded NullReferenceException. 

Obviously, I don't want to require the end-user to add a RadAjaxManager to the page manually or in the parent page's OnInit.  I want the control to be self-contained (i.e. adding the RadAjaxManager only when needed for the control).

How do I do this?

Thanks,
Joshua

4 Answers, 1 is accepted

Sort by
0
Joshua
Top achievements
Rank 1
answered on 16 Mar 2010, 09:58 PM
Can I please get some help on this?

Thanks,
Joshua
0
Veli
Telerik team
answered on 18 Mar 2010, 01:50 PM
Hi Joshua,

You can add RadAjaxManager and RadScriptManager to your page from user controls you develop. However, there are a couple of rules you need to follow tightly.

These rules are related to RadAjaxManager. It has special requirements as to how it needs to be created and how AJAX settings are to be added. Particularly, RadAjaxManager needs to be created in the OnInit or Page_Init methods of the Page object. As you will be inserting the manager from a user control, you are left with OnInit.

So, supposing you are subclassing, let's say, RadGrid. You have:

public class Grid : RadGrid
{
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
    }
 
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
    }
}

Obviously, I will need the OnInit and OnLoad methods of the control overridden. Now, how do we insert RadAjaxManager to the page at latest before the end of the OnInit method of the Page? We need to subscribe for the OnInit event of the Page object:

public class Grid : RadGrid
{
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        Page.Init += new EventHandler(Page_Init);
    }
 
    void Page_Init(object sender, EventArgs e)
    {
        ScriptManager scriptManager = null;
        RadAjaxManager ajaxManager = null;
 
        foreach (Control control in Page.Form.Controls)
        {
            if (control is ScriptManager) scriptManager = (ScriptManager)control;
            if (control is RadAjaxManager) ajaxManager = (RadAjaxManager)control;
        }
 
        if (scriptManager == null)
        {
            scriptManager = new RadScriptManager { ID = "RadScriptManager1" };
            Page.Form.Controls.AddAt(0, scriptManager);
        }
 
        if (ajaxManager == null)
        {
            ajaxManager = new RadAjaxManager { ID = "RadAjaxManager1" };
            Page.Form.Controls.AddAt(1, ajaxManager);
        }
    }
 
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
    }
}


As you can see, in the attached Page.Init event handler, I check if I do not previously have RadScriptManager and RadAjaxManager created, and, if not, do create them.

Now we need to add the AJAX settings for AJAX-enabling our server control. The RadAjaxManager's AjaxSettings should be added on Load event of either the page or the control. I use the control's OnLoad method:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
 
    RadAjaxManager ajaxManager = RadAjaxManager.GetCurrent(Page);
    ajaxManager.AjaxSettings.AddAjaxSetting(this, this);
}

At this point, our server control is AJAX-enabled. When we add it on any page, no matter if the page contains a ScriptManager and an AjaxManager, the server control will work asynchronously.

There is one last requirement though. Our most attentive readers will note that, as we are subscribing for the Page.Init event, my control needs to be added to the Page's controls collection pretty earlier in the page lifecycle. Otherwise, if Page.Init has passed by the time the server control is initialized, we do not get the managers added.

Now this requirement may seem pretty strict for some. It implies that I can add my custom server control to the Page's Controls collection in no more than 2 ways:

1. Declaratively through the markup:

<my:Grid ID="Grid1" runat="server" AllowPaging="true" AllowSorting="true" PageSize="5">
</my:Grid>

That option may be sufficient for most control consumers, so this might be a sufficient reason to go for inserting script and AJAX managers through server controls.

2. Programmatically, in the overriden OnInit method of the page and before  calling base.OnInit(e):

protected override void OnInit(EventArgs e)
{
    Grid g = new Grid();
    g.ID = "Grid1";
    g.AllowPaging = true;
    g.PageSize = 5;
    Form.Controls.Add(g);
 
    base.OnInit(e);
}

The second approach is trickier. It says that you can add the control dynamically, but you need to do it only in OnInit(), and only before calling base.OnInit(). The reason? We subscribe to the Page.Init event from the control, remember? We need to make sure Page.Init fires after the control is loaded. Hence, we need to load the control before base.OnInit(e) which will cause the Page object to fire the Init event.

I hope this makes sense. Sample page with custom server control is attached for those who want to try it out.

Sincerely yours,
Veli
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
JD
Top achievements
Rank 1
answered on 10 Feb 2014, 08:27 PM
Veli,

Thanks for your comprehensive answer to this.  My problem is, the entire userControl stack is being created dynamically.  The aspx page places the user control (.cs ONLY, no .ascx) in the Controls collection during its Page_Init.  This means that I can't subscribe to Page_Init from my userControl because the event has passed by the time its own OnInit happens.  I don't have control of the aspx page, only the userControl and I need ajaxy elements in it, requiring a RadAjaxManager.

Is this possible?

Thanks,
JD
0
Maria Ilieva
Telerik team
answered on 13 Feb 2014, 12:27 PM
Hi Justyn,

Ajaxifying  controls that are positioned within a user controls works somewhat differently from the scenario when they are loaded directly on a web form. In your case, you need to move the RadAjaxManager control to the mentioned UC  class, create it there and add it to the Controls collection  as follows:
private RadAjaxManager _ajaxManager;
  
protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
  
    SetUpAjaxManagerOnPage();
  
    EnsureChildControls();
}
  
  
protected void SetUpAjaxManagerOnPage()
{
    RadAjaxManager currentAjaxManager = RadAjaxManager.GetCurrent(Page);
  
    if (currentAjaxManager == null)
    {
        Page.Form.Controls.AddAt(0, AjaxManager);
        Page.Items.Add(typeof(RadAjaxManager), AjaxManager);
    }
}
  
protected virtual RadAjaxManager AjaxManager
{
    get
    {
        if (_ajaxManager == null)
        {
            _ajaxManager = RadAjaxManager.GetCurrent(Page);
  
            if (_ajaxManager == null)
            {
                _ajaxManager = new RadAjaxManager() { ID = "RadAjaxManager1" };
            }
        }
  
        return _ajaxManager;
    }
}

Then in the OnLoad event get the RadAjaxManager and add programmatic settings:
RadAjaxManager _manager = RadAjaxManager.GetCurrent(Page);

I hope this helps.

Regards,
Maria Ilieva
Telerik
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the UI for ASP.NET AJAX, subscribe to the blog feed now.
Tags
Ajax
Asked by
Joshua
Top achievements
Rank 1
Answers by
Joshua
Top achievements
Rank 1
Veli
Telerik team
JD
Top achievements
Rank 1
Maria Ilieva
Telerik team
Share this question
or