DataGrid childcontrols problem

R

Richard Watt

Hi,

I am developing a custom control that inherits from the
datagrid. I want the normal functionality of the
Datagrid, then several buttons created underneath the
grid (not in the footer or pager).

In my basic example below I am creating a single button
in the overridden CreateChildControls. This compiles ok,
and when I use the control in a page, the grid renders
ok, but I do not see the button. I have played around
with overriding the render method, but everything I read
seems to indicate if you use CreateChildControls you
don't need to render.

What am I missing?

'-----------------------
Public Class MyGrid3
Inherits DataGrid

Dim btn As Button

Protected Overrides Sub CreateChildControls()

Controls.Clear()

btn = New Button
btn.Text = "button"
btn.ID = "btn1"
Controls.Add(btn)

MyBase.CreateChildControls()
End Sub

Public Overrides ReadOnly Property Controls() As
System.Web.UI.ControlCollection
Get
MyBase.EnsureChildControls()
Return MyBase.Controls
End Get
End Property
End Class


Cheers
Richard
 
S

Scott Mitchell [MVP]

Richard said:
I am developing a custom control that inherits from the
datagrid. I want the normal functionality of the
Datagrid, then several buttons created underneath the
grid (not in the footer or pager).

In my basic example below I am creating a single button
in the overridden CreateChildControls. This compiles ok,
and when I use the control in a page, the grid renders
ok, but I do not see the button. I have played around
with overriding the render method, but everything I read
seems to indicate if you use CreateChildControls you
don't need to render.

What am I missing?

Well, your code looks like:
Protected Overrides Sub CreateChildControls()

Controls.Clear()

btn = New Button
btn.Text = "button"
btn.ID = "btn1"
Controls.Add(btn)

MyBase.CreateChildControls()
End Sub

And notice that you add your control and *then* call
CreateChildControls(). But... if you look at the CreateChildControls()
method for the DataGrid (using Reflector, for example), you'll see that
it's first line of code is:

base.Controls.Clear();


So the control(s) you add are cleared right off the bat! What you need
to do is call MyBase.CreateChildControls() and *then* add your
additional controls.

hth


--

Scott Mitchell
(e-mail address removed)
http://www.4GuysFromRolla.com
http://www.ASPFAQs.com
http://www.ASPMessageboard.com

* When you think ASP, think 4GuysFromRolla.com!
 
R

Richard Watt

Thanks Scott

I have tried your sugestion and have changed
CreateChildControls() as shown below, but the result is
still the same - the grid shows but nothing else.

MyBase.CreateChildControls()

btn = New Button
btn.Text = "button"
btn.ID = "btn1"
Controls.Add(btn)


Cheers
Richard
 
R

Richard Watt

Scott

Your example works thanks. I broke down the rendering to
beginTag, contents and endTag and can get the button to
appear where I want it rather than on top of the grid.

However the problem I still have is that with a rendered
button I don't believe there is a way to capture server
side events within my control which I need to do.

Cheers
Richard
-----Original Message-----

The DataGrid is kind of tricky; internally it creates a
table and often it "forwards" method calls to that table;
try something like this (in this example I could just
output the string, but you can change the added control
to whatever control you want):
public class MyDataGrid : DataGrid
{
private LiteralControl Lit;
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
Lit.RenderControl(writer);
}

protected override void CreateChildControls()
{
base.CreateChildControls();
Controls.Add((Lit = new LiteralControl("Hello")));
}
}

Scott
"Richard Watt" <rich_watt@NO-SPAM_hotmail.com> wrote
in message news:[email protected]...
 
R

Richard Watt

Scott

The original problem I posted with the child control not
appearing seems to be related to DataBind(). The control
would actually appear (without the need for render) upon
a postback where the grid was not rebound to the data.
Looking at the code in the debugger, the button is in the
control collection, but then disappears after the
DataBind. I tried overriding DataBind so it called
EnsureChildControls after the base DataBind was called,
hoping this would fix it, but it did not work.

I have a solution where I override DataBind, call the
base class DataBind then create the button control. This
works but for reasons I cannot explain looses the
viewstate so the grid needs to DataBind for every
postback. From another thread I recall that creating
your controls anywhere except in CreateChildControl is
not considered good practice, so this is not an ideal
solution, but may have to do for now.

Thanks for your help.

Cheers
Richard
-----Original Message-----

As long as you get the button into the control
heirarchy you should be able to capture the events for
the button; in the example I had, a button created in the
CreateChildControls should be able to be an event target
(try adding an event handler in CreateChildControls and
see what happens).
Scott
"Richard Watt" <rich_watt@NO-SPAM_hotmail.com> wrote
in message news:[email protected]...
 
G

Guest

Scott - you're a genius!! Thanks for sticking with me.
I now have it working with the ViewState.

I have posted my demo class code for the benefit of
others. I did quite of bit of searching in newsgroups
and articles and never found anything demonstrating quite
what I was trying to do.


public class NewDataGrid : DataGrid
{
Button btn;

protected override void Render(HtmlTextWriter
writer) {
//if don't override this method, the child
controls are rendered
//outside of the <table> tags, and will
therefore just appear at top
//of the page.
//RenderBeginTag & RenderEndTag wrap
everything inside a <DIV> tag so
//children controls rendered underneath the
<table>

base.RenderBeginTag(writer);
base.RenderContents(writer);
base.RenderEndTag(writer);
}

void CreateControlButtons() {
btn = new Button();
btn.Text = "button";
btn.ID = "btn1";
btn.Click += new System.EventHandler
(this.btn_Click);
this.Controls.Add(btn);
}

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

private void btn_Click(object sender,
System.EventArgs e) {
base.BackColor= Color.AntiqueWhite;
}

//not sure if actually need to override this or
not.
//Works ok without it so far but some samples
recomend its use.
public override ControlCollection Controls {
get {
base.EnsureChildControls();
return base.Controls;
}
}

public override void DataBind() {
base.DataBind();
CreateControlButtons();
}
}

Cheers
Richard
-----Original Message-----

Ah, yes you are on to something, this is coming back to
me now; for data bound controls the DataBind method will
typically do a Controls.Clear() and then create the
underlying controls (and the DataBind will set
ChildControlsCreated = true, which means that calls to
EnsureChildControls will skip the call to
CreateChildControls()).
For a DataGrid, one usually binds the grid which in
turns creates the control hiearchy. Now, on postback, one
might skip the DataBind on the grid, so the DataGrid
CreateChildControls must be able to recreate the control
heirarchy using the ViewState (thus the
CreateChildControls is called as an alternate to the
DataBind -- kind-a-sorta).
So, you need to create a common-method/code-block that
both DataBind and CreateChildControls can call to get you
control built -- something like:
public override void DataBind() {
base.DataBind(); // this will call Controls.Clear() so do it first
MyCreateButton();
}

protected override void CreateChildControls() {
base.CreateChildControls(); // again, this will call
Controls.Clear() so do it first.
MyCreateButton();
}

Yes, using CreateChildControls is the pattern method
to follow when creating your own composite controls; but
in your case you are really enhancing the DataGrid and
so, doing what you've done -- or, like in the above two
methods -- is the right approach.
 

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,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top