3

Ive been playing around with the default ASP.NET web application template and the following code throws an exception:

Object reference not set to an instance of an object.

when clicking the created button.

Can anyone offer a technical explanation?

Note 1: The markup is just a blank page with a placeholder in it - see below.

Note 2: Substituting Button for LinkButton, and the code does not throw an exception and works.

public partial class test : System.Web.UI.Page
{
    protected override void OnInit(EventArgs e)
    {
        foo();
    }
    protected override void OnLoad(EventArgs e)
    {
        foo();
    }
    protected void foo()
    {
        placeholder1.Controls.Clear();
        placeholder1.Controls.Add(new Button() { Text = "test", ID = "btn" });
    }
}

Markup:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="test.aspx.cs" Inherits="WebApplication1.test" %>

<!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">
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder runat="server" ID="placeholder1" />
    </div>
    </form>
</body>
</html>
maxp
  • 24,209
  • 39
  • 123
  • 201

3 Answers3

0

It looks like either placeholder1 or placeholder1.Controls is null. This is the only explanation for a NullReferenceException given your code example.

Bas
  • 26,772
  • 8
  • 53
  • 86
0

My guess would be that the button is null once it comes back from the post-back. You are essentially removing the Button and creating a new button which will likely remove the associated event.

Just to support my thoery I tried this:

protected override void OnInit(EventArgs e)
{
    if (!IsPostBack)
        foo();
}
protected override void OnLoad(EventArgs e)
{
    if (!IsPostBack)
        foo();
}
protected void foo()
{
    placeholder1.Controls.Clear();
    placeholder1.Controls.Add(new Button() { Text = "test", ID = "btn" });
}

and did not receive the error that you received.

Why are you wanting to add the button at run-time like you are?

Anthony Shaw
  • 8,146
  • 4
  • 44
  • 62
  • You didnt receive that error because the button, let alone the event doesnt even exist on postback...remove your 'IsPostBack' conditional and it will occur. – maxp Mar 24 '11 at 15:15
  • right, I tried your code and received the error. By dynamically creating the button on the Init/Load it only exists for that specific request. Once the post-back occurs (i.e. clicking on the button) the button and the event associated is null, which is why you're experiencing the Object Reference Exception you're getting, it still needs to exist in the state that it did prior to postback – Anthony Shaw Mar 24 '11 at 15:20
  • The postback is part of the lifecycle: http://msdn.microsoft.com/en-us/library/ms178472.aspx – maxp Mar 24 '11 at 15:25
  • Also, if you remove the ID property of the button it wont throw an exception anymore. – maxp Mar 24 '11 at 15:27
  • Sorry to spam, but also, changing the type from 'Button' to 'LinkButton' will also not throw an exception. – maxp Mar 24 '11 at 15:32
  • I guess what it really comes down to then, is what are you trying to accomplish by doing this? I would still assume you wouldn't want to recreate the button before you can do anything that would have been associated with an event handler that you would inevitably bind to the button. – Anthony Shaw Mar 24 '11 at 15:32
  • I think for it to work properly in the end, you'll need to bind an event to the click and not remove the item on the Postback. Also, why are you running the same code OnInit and OnLoad? They're both being called on every page load and every postback again – Anthony Shaw Mar 24 '11 at 15:37
0

If you remove the call to foo() from the OnLoad() I think the code will start to work.

The reason for this is due to the order of events in the Page Life cycle. In order for a control to be able to raise events the control needs to have been created before the ProcessPostData(), RaiseChangedEvents() and RaisePostBackEvents() events occur (see http://www.eggheadcafe.com/articles/o_aspNet_Page_LifeCycle.jpg for a graphical representation of the page lifecycle) These events are raises after OnInit() but before OnLoad()

As your code stands at the moment by calling foo() in OnLoad(), you destroy the instance created when foo() was called in OnInit() and so when the Event is raised the control that raised it no longer exists, hence the "Object reference not set to an instance" message.

benophobia
  • 771
  • 6
  • 8