CompositeControls and RecreateChildControls()

J

jeljeljel

I have a CompositeControl (called SimplePager) that creates an
UpdatePanel in its CreateChildControls override. The CompositeControl
uses two LinkButtons to control the forward/backward state. W/out the
use of the UpdatePanel it works just great. However, as a learning
exercise I want to AJAXify the control. I am placing the entire
control in an UpdatePanel. During the link click event handler, I
make a call to RecreateChildControls() which throws an exception.

This is so close to working. Can someone suggest how to accomplish
what I am trying to do with an UpdatePanel?

My class is copied below.

Thanks,
John


public class SimplePager : CompositeControl
{
private int _currentRecord;
private int _totalRecords;

public SimplePager(int totalRecords)
{
_totalRecords = totalRecords;
_currentRecord = 1;
}

protected override void OnInit(EventArgs e)
{
Page.RegisterRequiresControlState(this);

EnsureChildControls();

base.OnInit(e);
}

protected override void LoadControlState(object savedState)
{
int[] state;

state = (int[])savedState;

_currentRecord = state[0];
_totalRecords = state[1];
}

protected override object SaveControlState()
{
int[] state;

state = new int[] { _currentRecord, _totalRecords };

return state;
}

protected override void CreateChildControls()
{
HtmlGenericControl div;
LinkButton linkButton;
UpdatePanel updatePanel;
Label label;

div = new HtmlGenericControl("div");
Controls.Add(div);

updatePanel = new UpdatePanel();
updatePanel.ID = this.ID + "BWPagerUpdatePanel";
updatePanel.ChildrenAsTriggers = true;
updatePanel.UpdateMode =
UpdatePanelUpdateMode.Conditional;
div.Controls.Add(updatePanel);

linkButton = new LinkButton();
linkButton.Text = "<< prev";
linkButton.ID = "prevPage";
linkButton.Click += new EventHandler(linkButton_Click);

updatePanel.ContentTemplateContainer.Controls.Add(linkButton);

linkButton = new LinkButton();
linkButton.Text = "next >>";
linkButton.ID = "nextPage";
linkButton.Click += new EventHandler(linkButton_Click);

updatePanel.ContentTemplateContainer.Controls.Add(linkButton);

label = new Label();
label.ID = "SimplePagerTextBox";
label.Text = String.Format("&nbsp;&nbsp;Page {0} of {1}",
_currentRecord, _totalRecords);
updatePanel.ContentTemplateContainer.Controls.Add(label);

base.CreateChildControls();
}

private void linkButton_Click(object sender, EventArgs e)
{
LinkButton linkButton = sender as LinkButton;

if (PageChange != null)
{
switch (linkButton.ID)
{
case "prevPage":
if (_currentRecord > 1)
_currentRecord--;
break;

case "nextPage":
if (_currentRecord < _totalRecords)
_currentRecord++;
break;
}

PageChange(this, _currentRecord);

RecreateChildControls();
}
}

public int CurrentRecord
{
get
{
return _currentRecord;
}
}

public delegate void PageChangeEvent(object sender, int
newPage);
public event PageChangeEvent PageChange;
}
 
N

Nathan Sokalski

I am not an expert with using UpdatePanels in CompositeControls, but I am
wondering if the Control rendering process is getting confused somehow
because of the fact that the Controls get added to
updatePanel.ContentTemplateContainer.Controls rather than
updatePanel.Controls? You may want to see if including the RenderContents()
method helps (I don't know if it will or not, but it's worth a try).
Something else I would like to point out, just as a suggestion, is that you
are placing all of your controls into a div tag. There is nothing wrong with
this, except that it is inefficient because the CompositeControl places all
the rendered Controls into a div by default anyway. To control what tag
everything is placed into and what attributes are added to that tag, use the
following methods (note that my code is in VB.NET, but I'm sure you can do
the necessary translation):

Protected Overrides ReadOnly Property TagKey() As
System.Web.UI.HtmlTextWriterTag
'This method returns the tag that all rendered controls will be placed
into
Get
Return HtmlTextWriterTag.Div
End Get
End Property

Protected Overrides Sub AddAttributesToRender(ByVal writer As
System.Web.UI.HtmlTextWriter)
'Use this method to add attributes to the tag returned from the TagKey
property
writer.AddAttribute(HtmlTextWriterAttribute.Align, "left")
MyBase.AddAttributesToRender(writer)
End Sub

If you view the output of your current code, you will see a div nested
inside a div, if you use TagKey and AddAttributesToRender you will only see
one. As for the UpdatePanel, I don't know if my suggestion will help, but it
is good programming practice to implement it anyway. Good Luck!
--
Nathan Sokalski
(e-mail address removed)
http://www.nathansokalski.com/

jeljeljel said:
I have a CompositeControl (called SimplePager) that creates an
UpdatePanel in its CreateChildControls override. The CompositeControl
uses two LinkButtons to control the forward/backward state. W/out the
use of the UpdatePanel it works just great. However, as a learning
exercise I want to AJAXify the control. I am placing the entire
control in an UpdatePanel. During the link click event handler, I
make a call to RecreateChildControls() which throws an exception.

This is so close to working. Can someone suggest how to accomplish
what I am trying to do with an UpdatePanel?

My class is copied below.

Thanks,
John


public class SimplePager : CompositeControl
{
private int _currentRecord;
private int _totalRecords;

public SimplePager(int totalRecords)
{
_totalRecords = totalRecords;
_currentRecord = 1;
}

protected override void OnInit(EventArgs e)
{
Page.RegisterRequiresControlState(this);

EnsureChildControls();

base.OnInit(e);
}

protected override void LoadControlState(object savedState)
{
int[] state;

state = (int[])savedState;

_currentRecord = state[0];
_totalRecords = state[1];
}

protected override object SaveControlState()
{
int[] state;

state = new int[] { _currentRecord, _totalRecords };

return state;
}

protected override void CreateChildControls()
{
HtmlGenericControl div;
LinkButton linkButton;
UpdatePanel updatePanel;
Label label;

div = new HtmlGenericControl("div");
Controls.Add(div);

updatePanel = new UpdatePanel();
updatePanel.ID = this.ID + "BWPagerUpdatePanel";
updatePanel.ChildrenAsTriggers = true;
updatePanel.UpdateMode =
UpdatePanelUpdateMode.Conditional;
div.Controls.Add(updatePanel);

linkButton = new LinkButton();
linkButton.Text = "<< prev";
linkButton.ID = "prevPage";
linkButton.Click += new EventHandler(linkButton_Click);

updatePanel.ContentTemplateContainer.Controls.Add(linkButton);

linkButton = new LinkButton();
linkButton.Text = "next >>";
linkButton.ID = "nextPage";
linkButton.Click += new EventHandler(linkButton_Click);

updatePanel.ContentTemplateContainer.Controls.Add(linkButton);

label = new Label();
label.ID = "SimplePagerTextBox";
label.Text = String.Format("&nbsp;&nbsp;Page {0} of {1}",
_currentRecord, _totalRecords);
updatePanel.ContentTemplateContainer.Controls.Add(label);

base.CreateChildControls();
}

private void linkButton_Click(object sender, EventArgs e)
{
LinkButton linkButton = sender as LinkButton;

if (PageChange != null)
{
switch (linkButton.ID)
{
case "prevPage":
if (_currentRecord > 1)
_currentRecord--;
break;

case "nextPage":
if (_currentRecord < _totalRecords)
_currentRecord++;
break;
}

PageChange(this, _currentRecord);

RecreateChildControls();
}
}

public int CurrentRecord
{
get
{
return _currentRecord;
}
}

public delegate void PageChangeEvent(object sender, int
newPage);
public event PageChangeEvent PageChange;
}
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top