Click event does not fire - IPostBackEventHandler ?

A

Ahmet Gunes

Hi all,

I am developing a container control like a standard Div with a template
property called Content.
Unfortunately, although the button implements the IPostBackEventHandler
interface (since it is the standard Button control) it's click event does
not fire.

I am almost running crazy. I don't understand the problem. Could you please
help?


Here is my code for my custom container:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.ComponentModel;

namespace MyCustomControlLibrary {

[ParseChildren(true)]
[PersistChildren(false)]
public class MyDiv: WebControl {

private Control container = null;

protected override HtmlTextWriterTag TagKey {
get {
return HtmlTextWriterTag.Div;
}
}

[DefaultValue(null)]
[Browsable(false)]
[TemplateInstance(TemplateInstance.Single)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[NotifyParentProperty(true)]
public ITemplate Content {
get;
set;
}

protected override void OnInit(EventArgs e) {
if (Content != null) {
container = new HtmlGenericControl("div");
container.ID = ClientID + "_Content";
Content.InstantiateIn(container);
}
}

protected override void CreateChildControls() {
base.CreateChildControls();

if (container != null) {
Controls.Add(container);
}
}
}
}


Here is a sample ASPX page that uses MyDiv:

<%@ Page Debug="true" Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="MyTestWebApplication._Default" %>
<%@ Register Assembly="MyCustomControlLibrary"
Namespace="MyCustomControlLibrary" TagPrefix="mcc" %>

<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<mcc:MyDiv ID="MyDiv1" runat="server">
<Content>
<asp:Button ID="Button1" runat="server" Text="Button"
OnClick="Button1_Click" />
</Content>
</mcc:MyDiv>
</form>
</body>
</html>
 
P

Peter Bucher [MVP]

Hi Ahmet

I guess your Control have to implement "INamingContainer" to garant
unique IDs and the Access from the ASP.NET-Engine.

Try this :)

To implement IPostBackEventHandler doesnt make any Sense for
that control and your case, because _that_ Control isnt`t a
PostBackEventHandler.
 
A

Ahmet Gunes

Thanks Peter,

Actually I have already tried implementing INamingContainer and it worked.
:)
I also found another way that also worked:

Replace the following lines

container = new HtmlGenericControl("div");
container.ID = ClientID + "_Content";
Content.InstantiateIn(container);
with

Content.InstantiateIn(this);

and remove the override of CreateChildControls.

But I didn't like these solutions since I need to call those content with
the same ids in the client code.
When INamingContainer is implemented the ids of the content controls are
changed.
My control is actually much more complicated and needs some inner container.

Actually, I saw a sample code at http://www.coolite.com which achieves this
without implementing INamingContainer.
If you wish, you may download the community edition as a Zip file and check
the ContentPanel control.
It does not implement INamingContainer in any way.

Thanks,

Ahmet
 
P

Peter Bucher [MVP]

Hi Ahmed
I also found another way that also worked:

Replace the following lines

container = new HtmlGenericControl("div");
container.ID = ClientID + "_Content";
Content.InstantiateIn(container);
with

Content.InstantiateIn(this);
Here you do manually what ASP.NET does if INamingContainer is implemented.
And like you guess, thats not a good solution.

Whats the Problem with implementing INamingContainer?
Actually, I saw a sample code at http://www.coolite.com which achieves
this without implementing INamingContainer.
If you wish, you may download the community edition as a Zip file and
check the ContentPanel control.
It does not implement INamingContainer in any way.
I looked short at that Code, but doesent see the Reason - its way to
complicated, IMO.
 
A

Ahmet Gunes

Hi Peter,

First of all, my container is actually a custom web control which does not
output begin/end tags.
To simplify things, I just put a sample div control.
Therefore, I think my solution is not the same as implementing
INamingContainer.

Now let me give you an example:
Assume the containing panel is named "pnl01", and my button control is
"btn01".
When I implement INamingContainer, the name and id of the button becomes
"pnl01$btn01" and "pnl01_btn01", respectively.
But for simplicity purposes I need to call the button as "btn01" in the
client-side script.

Next, since those containers can be nested as many times as the page
developer wishes, when you put pnl01 inside pnl02 then the name of the
button becomes "pnl02$pnl01$btn01" which makes client-side scripting a
tedious task. In addition, those new names adds to the total bytes sent to
the client since there will be many textbox, dropdownlist or button controls
in the form.

Another question: Is there any way to override the default behaviour of
implementing INamingContainer?


Thanks,
 
A

Ahmet Gunes

Solved at last.

The point that I was missing is the execution order of the events.
In order for a control to raise an event that control should be added to the
Control tree first.

Hence the following code in the custom container control solved my problem:

protected override void OnInit(EventArgs e) {
base.OnInit(e);
if (Content != null) {
this.EnsureID();
container = new MyContainer();
container.ID = this.ID + "_Content";
Controls.Add(container);
Content.InstantiateIn(container);
}
}

Thanks,

Ahmet
 
I

Ion Lamasanu

You must implement RegisterRequiresRaiseEvent ( control)
where control implements IPostBackEventHandler. This must be done in the
control's load event.
Also I must note that 'Only one server control can be registered per page
request.' (MSDN cited) so only one control from those which implements
IPostBackEventHandler will run its implemented RaisePostBackEvent(). That
control will be the last one which registers its instance with
RegisterRequiresRaiseEvent() from Page class.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top