Bind a list of users controls to gridview - c#

I desperately seeks in vain. I want to bind a List(T) of Users Controls (.ascx) to a gridview. I initialize my controls in code-behind :
List<myControl> ctrls = new List<myControl>();
myControl ctr = LoadControl("~/Control.ascx") as myControl;
ctr.Name = ...
// ...
ctrls.Add(myControl); // add new control to the collection
And after, i bind this list to Gridview control :
this.GridView1.DataSource = ctrls;
this.gridView1.DataBind();
In the Page_Load event with condition If (!IsPostBack). This does not work: the representation of the object is displayed. Whereas when I put the controls in a Panel, all worked.

Don't use a GridView for this. Use a Repeater. And bind it to the data, not to list of controls. Example:
<asp:Repeater runat="server" id="ControlsRepeater">
<ItemTemplate>
<uc:MyControl runat="server" />
</ItemTemplate>
</asp:Repeater>
Code Behind
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
var myData=GetData(); //should return some type of ICollection representing your data to bind to
ControlsRepeater.DataSource=myData;
ControlsRepeater.DataBind();
}
}
If you want paging, then you should take advantage of lazy loading (the Entity Framework handles this for you if you use that) and the Linq functions .Take() and .Skip().

Related

How to find a HTML tag with runat=server into a repeater?

I'm generating a table using a Repeater and I need to set a <td> as runat=server to set visibility for it.
I'm trying to find it into ItemDataBound event using FindControl method, but it doesn't work.
Hot can I achieve this?
If you want to do that, you should write like this:
Visible=<%= SetVisiblity() %>
where SetVisiblity is a public function
This should do the trick. First, create a method called to catch the repeater's OnDataItemBound event.
protected void MyRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// Use FindControl, but start from the context of the RepeaterItem.
//
HtmlTableCell cell = e.item.FindControl("CellID") as HtmlTableCell;
if ( cell != null )
{
// Do what you gotta do.
}
}
You can explicitly wire the event up on the repeater markup.
<asp:Repeater ID="MyRepeater" runat="server" OnItemDataBound="MyRepeater_ItemDataBound">
</asp:Repeater>

Gridview Row Events not firing in UserControl

I've got a pretty strange problem with my usercontrols that I'm working with. I'm coding some user controls to be used in a DotNetNuke module.
Basically I have a UserControl on my page that holds some controls and then there is a Placeholder where I am loading in a UserControl that has a GridView placed in it.
Basically here is my page structure
<asp:Panel runat="server" ID="pnlServiceType" Visible="false">
<uc:ServiceType runat="server" ID="ServiceType" />
</asp:Panel>
Within that user control are some form elements and then the following:
<asp:PlaceHolder runat="server" ID="phServices" />
That placeholder then has a user control added to it like so:
<p class="header"><asp:Label runat="server" ID="lblServiceHeader" Font-Bold="true" /></p>
<asp:GridView runat="server" ID="gvServices" AlternatingRowStyle-BackColor="#eaeaea" BorderStyle="None" GridLines="None"
AutoGenerateColumns="false" CellPadding="6" Width="100%" EnableViewState="false" OnRowEditing="gvServices_RowEditing">
When the user picks something in the DropDownList, I'm clearing the controls out of the Placeholder, and re-adding just a single UserControl for the set of records for whatever type they've picked like so
_serviceID = e.Value;
//Clear the controls out of the placeholder
phServices.Controls.Clear();
//Reset the count of grids for the OnInit() method
Session["GridCount"] = 0;
if (e.Value != "NULL")
{
PopulateServicesGrid(_service.GetServicesByFormType(Convert.ToInt32(e.Value)));
}
else
{
PopulateServicesGrid(_service.GetServicesByClient(Convert.ToInt32(_client)));
}
And the PopulateServicesGrid method:
private void PopulateServicesGrid(List<NOAService> services)
{
//Creates a LINQ grouping based on the Billing Codes
//Allows a super easy creation of grids based on the grouped billing codes
var query = services.Select(service => service.BillingCode).Distinct();
foreach (string code in query)
{
var servicesByCode = services.Where(service => service.BillingCode == code).ToList();
ServicesGrid servicesGrid = LoadControl("~/DesktopModules/LEL Modules/NOA/ServicesGrid.ascx") as ServicesGrid;
Label lblServiceHeader = servicesGrid.FindControl("lblServiceHeader") as Label;
GridView gvServices = servicesGrid.FindControl("gvServices") as GridView;
phServices.Controls.Add(servicesGrid);
servicesGrid.ID = code;
lblServiceHeader.Text = servicesByCode[0].FormTypeName;
gvServices.DataSource = servicesByCode;
gvServices.DataBind();
Session["GridCount"] = phServices.Controls.Count;
}
}
And on my ServiceType UserControl, on the PageInit, I'm readding the ServiceGrid usercontrol so that my grids show up across postbacks and aren't lost from the Placeholder
void NOAServiceType_Init(object sender, EventArgs e)
{
for (int i = 0; i < Convert.ToInt32(Session["GridCount"]); i++)
{
ServicesGrid servicesGrid = LoadControl("~/DesktopModules/LEL Modules/NOA/ServicesGrid.ascx") as ServicesGrid;
phServices.Controls.Add(servicesGrid);
}
}
The grids populate successfully and everything seems to work just fine. But for some reason, on my GridView, I have a CommandField of
<asp:CommandField ShowEditButton="true" ItemStyle-HorizontalAlign="Right" EditText="Edit" UpdateText="Update"
EditImageUrl="~/images/LELModules/appbar.edit.rest.png" CancelImageUrl="~/images/LELModules/appbar.close.rest.png" UpdateImageUrl="~/images/LELModules/appbar.check.rest.png"
ButtonType="Image" CausesValidation="false" />
When I click my Edit command on the Grid row, nothing happens. My grid doesn't lose its rows, the control is still there, everything seems like it should be ok. The RowEditing event doesn't fire until I click it a second time.
Any idea why this might be occuring?
UPDATE: I've managed to figure out that my SelectedIndexChanged handlers are effectively resetting the DataSource on the Grid contained by the UserControl when they are readded to the PlaceHolder. When the CommandField (Edit) is clicked though, the Init fires for the UserControl that holds the placeholder
ServiceType UserControl < `Init` fires here
-Form elements
-Placeholder which holds
--UserControl with GridView
The Init method loads up new instances of the UserControl and adds them to the PlaceHolder, but the DataSource is null. With EnableViewState=true it looks like the data is still bound, but if I handle PreRender, I can see that the DataSource on my gvServices | null
Is it even possible to edit rows like this on a GridView that is being added dynamically to a PlaceHolder over and over?
FIXED I found out what the issue was after referring to this article
http://www.west-wind.com/weblog/posts/2006/Feb/24/Overriding-ClientID-and-UniqueID-on-ASPNET-controls
It got me thinking, what if the IDs were getting changed? The controls are way nested. So I went and put a watch on the GridView's ID, ClientID, and UniqueID just to see. When the Control is loaded on my Init handler, it's assigned a super generic ID when it's added.
private void PopulateServicesGrid(List<NOAService> services)
{
//Creates a LINQ grouping based on the Billing Codes
//Allows a super easy creation of grids based on the grouped billing codes
var query = services.Select(service => service.BillingCode).Distinct();
foreach (string code in query)
{
var servicesByCode = services.Where(service => service.BillingCode == code).ToList();
ServicesGrid servicesGrid = LoadControl("~/DesktopModules/LEL Modules/NOA/ServicesGrid.ascx") as ServicesGrid;
Label lblServiceHeader = servicesGrid.FindControl("lblServiceHeader") as Label;
GridView gvServices = servicesGrid.FindControl("gvServices") as GridView;
phServices.Controls.Add(servicesGrid);
**servicesGrid.ID = code;**
lblServiceHeader.Text = servicesByCode[0].FormTypeName;
gvServices.DataSource = servicesByCode;
gvServices.DataBind();
Session["GridCount"] = phServices.Controls.Count;
}
}
I was setting the ID as something else. So when I was hitting the Edit RowCommand on my grid, it was reloading the controls again on Init and the IDs were being changed back from my custom set code (T2020, pulled from my database) to the generic ID again, it didn't know how to fire the event.
I hope this helps someone as I've lost at least 12 hours fixing this problem.

how to find control in ItemTemplate of the ListView from code behind of the usercontrol page?

actually, i'm developing a web template using ASP.NET and C#.
i have a listview in a usercontrol page and inside the ItemTemplate i have a PlaceHolder as below:
<asp:PlaceHolder ID="ph_Lv_EditModule" runat="server"> </asp:PlaceHolder>
i want to access to this PlaceHolder from code behind and i have use different method as below but i couldn't access it.
PlaceHolder ph_Lv_EditModule = (PlaceHolder)lv_Uc_Module.FindControl("ph_Lv_EditModule");
or
PlaceHolder ph_Lv_EditModule = (PlaceHolder)this.lv_Uc_Module.FindControl("ph_Lv_EditModule");
could you please help me how to find this control at the code behind of my usercontrol page.
appreciate your consideration.
A ListView typically contains more than one item, therefore the NamingContainer(searched by FindControl) of your Placeholder is neither the UserControl, nor the ListView itself. It's the ListViewItem object. So one place to find the reference is the ListView's ItemDataBound event.
protected void ListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
var ph_Lv_EditModule = (PlaceHolder)e.Item.FindControl("ph_Lv_EditModule");
}
}
If you need the reference somewhere else, you must iterate the Items of the ListView and then use FindControl on the ListViewItem.
By the way, this is the same behaviour as in other DataBound Controls like GridView or Repeater.
As Tim Schmelter mentioned, you can also access your control by iterating through your ListView as follows
private void HideMyEditModule()
{
foreach (var item in lv_Uc_Module.Items)
{
PlaceHolder holder = item.FindControl("ph_Lv_EditModule") as PlaceHolder;
if (holder!= null)
holder.Visible = false;
}
}

aspx dropdown adding items how to get dropdownlist instance

I want to add items to my drop down in function addItems. How to do that at runtime?
<asp:DropDownList ID="DropDownNum" runat="server" Width="50px" SelectedValue='<%#Bind("num")%>' OnLoad='addItems'>
</asp:DropDownList>
protected void addItems() {
...
foreach (NumOption option in ConfigManager.Config.NumOptions.Options)
{
numDropDown.Items.Add(option.Value);
}
}
edit: I need to get the instance of the DropDownList to call it via numDropDown, the adding itself is not the problem
You can add items like...
numDropDown.Items.Add(new ListItem("Text", "Value"));
Edit: In reference your comments, you are unable to get the Control reference in your code class. You have to find the control in the particular container e.g.
DropDownList numDropDown = (DropDownList)Container.Item.FindControl("DropDownNum");
Note: where Container is the control in your dropdownlist
numDropDown.Items.Add(new ListItem("text", option.Value));

accessing gridview hiddenfield

' />
I want to access the value in the hidden field in my code behind. I know i need to do this when the item is bound but i cant seem to work out how to do it.
protected void addLabelsWhereNeeded(object sender, EventArgs e)
{
// Get Value from hiddenfield
}
Try adding
OnRowDataBound="addLabelsWhereNeeded"
to your GridView. Then cast the control in the corresponding cell to a HiddenField to grab the value:
protected void addLabelsWhereNeeded(object sender, GridViewRowEventArgs e)
{
HiddenField hf = e.Row.Cells[0].Controls[1] as HiddenField;
String theValue = hf.Value;
}
assuming you've defined your GridView as:
<asp:GridView runat="server" ID="gv" OnRowDataBound="addLabelsWhereNeeded">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<%--your hidden field--%>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Just make sure you are indexing the correct cell and correct control within that cell.
yes you are right. You must do it on ItemDateBound. Check It must work
I do quite see what you want to achieve with this private field while databinding? In the RowDataBound Event you can access the whole data item, so there is no need for the use of a hidden value.
Pseudocode:
protected void Grid1_RowDataBound(object sender, GridViewRowEventArgs)
{
if(e.RowType == RowType.DataRow)
{
}
}
Set a Breakpoint into if clause and use quickwatch to see how you need to cast the DataItem that is currently bound to gain full access to all properties, even if they aren't bound to any control.

Categories

Resources