Required multiple instances of a UserControl loaded at runtime

J

J055

Hi

I need to access multiple instances of the same UserControl dynamically. I
can successful do this with one control but I'm not sure how I can assign
multiple instances to a Repeater at runtime.

This is what I have so far

protected void Page_Init(object sender, EventArgs e)

{

// load the account finder control

_accountFinder =
(AccountFinder)LoadControl("~/Controls/AccountFinder.ascx");


}

//This is called multiple times by a Repeater control

//I need to be able to add a new instance of the control if the PlaceHolder
is visible

protected void phIndividualsFinder_Load(object sender, EventArgs e)

{

PlaceHolder phIndividualsFinder = (PlaceHolder)sender;

// made visible by the click event on a previous postback

if (phIndividualsFinder.Visible == true)

{

phIndividualsFinder.Controls.Add(_accountFinder);

}

}

What is the correct way of achieving this? Many thanks

Andrew
 
S

Steven Cheng[MSFT]

Hello Andrew,

Do you mean you want to programmatically add an ascx usercontrol into each
Item of the repeater control? If so, I think you can use the
Repeater.ItemCreated event. This is because for dynamic control, we need to
create and add it in each page request, and for Repeater control, those
items are generated through Databinding, and the only means to customize
each repeater item's control collection is in the "ItemCreated" event
because this event is fired in each page request. e.g.

=======aspx=======
...............................
<asp:Repeater ID="Repeater1" runat="server"
DataSourceID="SqlDataSource1" OnItemCreated="Repeater1_ItemCreated">
<ItemTemplate>
<br /><hr /><br />
<asp:placeHolder ID="holder1" runat="server"></asp:placeHolder>
</ItemTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>


========code behind=========
protected void Repeater1_ItemCreated(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
PlaceHolder holder = e.Item.FindControl("holder1") as
PlaceHolder;

if (holder != null)
{
Control uc = Page.LoadControl("~/uc/WebUserControl.ascx");
holder.Controls.Add(uc);
}
}
}
====================

Hope this helps.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================



This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

J055

Hi Steven

That helps, thanks. I have another related question.

I have a repeater

protected void repFilterParamsGroups_ItemDataBound(Object Sender,
RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
DataRowView row = (DataRowView)e.Item.DataItem;

// bind data
byte val = (byte)row["OrGroup"]))
}
}

There are a few nested controls under each repeater Item. I need to access
the row["OrGroup"] value from a custom event which fires from a User
Control. I've been trying to access this value but I can't find it

private void accountFinder_AccountIdSelected(object sender, EventArgs e)
{
AccountFinder accountFinder = (AccountFinder)sender;
// This doesn't work
Trace.Warn(accountFinder.Parent.Parent.Parent.Parent.Controls[1].ID);

}

Is there a neater/suggested way to locate the value of the accountFinder's
ancestor?

Thanks
Andrew
 
S

Steven Cheng[MSFT]

Hello Andrew,

Thanks for your reply.

For your further questions, here are my understanding and suggestion:

the "e.Item.DataItem" object refer to the current item from databound
datasource, and this is only available during databinding period. And in
your usercontrol's custom event handler (or any other place durign control
lifecycle), this propety is not available, you need to persist the value in
some certain place so that the usercontrol can access it later.

So far what I've got are the following two means to persist the value:

1. directly use databinding expression in ascx usercontrol to bind the
value to a sub control in usercontrol. e.g.

================
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="WebUserControl.ascx.cs" Inherits="uc_WebUserControl" %>
........................
<asp:Label ID="lblData" runat="server" Text='<%# Eval("CategoryName") %>'
Visible="false"></asp:Label>
================

When you add usercontrol into any databound context(in repeater,
datalist...), it can automatically join the databinding context and get the
value from each DataItem


2. You can also define a custom property on the usercontrol so that you can
persist the data from DataSource Item into this property on usercontrol.
Later, the usercontrol's method or event can access this property to get
the data. e.g.

=========usercontrol code behind=========
public partial class uc_WebUserControl : System.Web.UI.UserControl
{
public string DataText
{
get
{
if (ViewState["_datatext"] != null)
{
return ViewState["_datatext"] as string;
}
return "default data text";
}

set
{
TrackViewState();
ViewState["_datatext"] = value;
}
}

..................

protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = DataText;
}
}
========================

And in repeater's databound code, you can programmatically assign this
value:

===================
protected void Repeater1_ItemCreated(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
PlaceHolder holder = e.Item.FindControl("holder1") as
PlaceHolder;

if (holder != null)
{
Control uc = Page.LoadControl("~/uc/WebUserControl.ascx");

uc_WebUserControl wuc = uc as uc_WebUserControl;
wuc.DataText = DataBinder.Eval(e.Item.DataItem,
"CategoryID", "{0}");

holder.Controls.Add(uc);
}
}
}
===============================

#Note that since ASP.NET page/usercontrol use partial class, to reference
the actual type of the usercontrol in page, you need to explicitly
reference it in Page(through @page directive) .e.g.

================
<%@ Page ...................%>
<%@ Reference VirtualPath="~/uc/WebUserControl.ascx" %>

...............
==================

Hope this helps. If there is anything unclear, please feel free to let me
know.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

J055

Hi Steven

Thanks for the information. I have another question. I am currently loading
the user control when a button onclick event fires and also in a Placeholder
Load event in the right conditions. This works fine for me. How can I access
the DataItem value from the ItemCreated method?

I think I need to store the values in viewstate for each DataItem of each
RepeaterItem so I can access these values in the Load and OnClick events
(also without rebinding).

What would be the appropriate way?
Thanks
Andrew


Steven Cheng said:
Hello Andrew,

Thanks for your reply.

For your further questions, here are my understanding and suggestion:

the "e.Item.DataItem" object refer to the current item from databound
datasource, and this is only available during databinding period. And in
your usercontrol's custom event handler (or any other place durign control
lifecycle), this propety is not available, you need to persist the value
in
some certain place so that the usercontrol can access it later.

So far what I've got are the following two means to persist the value:

1. directly use databinding expression in ascx usercontrol to bind the
value to a sub control in usercontrol. e.g.

================
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="WebUserControl.ascx.cs" Inherits="uc_WebUserControl" %>
.......................
<asp:Label ID="lblData" runat="server" Text='<%# Eval("CategoryName") %>'
Visible="false"></asp:Label>
================

When you add usercontrol into any databound context(in repeater,
datalist...), it can automatically join the databinding context and get
the
value from each DataItem


2. You can also define a custom property on the usercontrol so that you
can
persist the data from DataSource Item into this property on usercontrol.
Later, the usercontrol's method or event can access this property to get
the data. e.g.

=========usercontrol code behind=========
public partial class uc_WebUserControl : System.Web.UI.UserControl
{
public string DataText
{
get
{
if (ViewState["_datatext"] != null)
{
return ViewState["_datatext"] as string;
}
return "default data text";
}

set
{
TrackViewState();
ViewState["_datatext"] = value;
}
}

.................

protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = DataText;
}
}
========================

And in repeater's databound code, you can programmatically assign this
value:

===================
protected void Repeater1_ItemCreated(object sender, RepeaterItemEventArgs
e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
PlaceHolder holder = e.Item.FindControl("holder1") as
PlaceHolder;

if (holder != null)
{
Control uc = Page.LoadControl("~/uc/WebUserControl.ascx");

uc_WebUserControl wuc = uc as uc_WebUserControl;
wuc.DataText = DataBinder.Eval(e.Item.DataItem,
"CategoryID", "{0}");

holder.Controls.Add(uc);
}
}
}
===============================

#Note that since ASP.NET page/usercontrol use partial class, to reference
the actual type of the usercontrol in page, you need to explicitly
reference it in Page(through @page directive) .e.g.

================
<%@ Page ...................%>
<%@ Reference VirtualPath="~/uc/WebUserControl.ascx" %>

..............
==================

Hope this helps. If there is anything unclear, please feel free to let me
know.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no
rights.
 
S

Steven Cheng[MSFT]

Thanks for your reply Andrew,

Yes, you're right. You have to store the value (from DataItem) in some
place since DataItem is only available during databinding context and in
your Button_Click or placeholder's load event, it is not always supposed to
work. There are two common approachs you can consider to store the value:

** during databinding context, store those data you need later in ViewState
(you also need to put additional info to identify which row does each data
belongs to)

** you can add an additional hidden control (<input type="hidden" .../> or
a hidden Label) in each Repeater Row and you can use databinding to store
the data you need in those hidden control.

No matter what means you use, the purpose is prestore the data during
databinding and the storage should be accessible at sequential time when
you need it.

Hope this helps.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 

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,997
Messages
2,570,240
Members
46,828
Latest member
LauraCastr

Latest Threads

Top