Add controls dynamically to a listview - c#

I have an asp.net listview. The data that populates it is sorted into groups, and i'm using some code in the listview item template, that essentially checks if the grouping field has changed in the data, and if so it prints a new row, with the heading, so it looks a bit like this:
<ItemTemplate>
<%# AddGroupingRowIfWPHasChanged() %>
<tr id="row" class="GridViewRow" runat="server" >
<td valign="top" align="left" ><%# Eval("item1") %></td>
.......
</itemTemplate>
This works great. However now I need to add a button the the group heading field, and I can't seem to get this to work. Obvioulsy this button only needs adding if the heading has changed, but the AddGroupingRowIfWPHasChanged() method does not seem to have access to the current ListviewItem, so I can't add a control.
Any suggestions on how I can add a control to a list view dynamically, depandant on whether its a group heading or not?

It may be easier to override the ItemInserting event in the codebehind and do it from there

Use a placeholder?
.aspx
<asp:Placeholder id="plhControlHolder" runat="server" />
code-behind
' ** use FindControl if instead a databound event, otherwise you could skip.
Dim plcControlHolder as PlaceHolder = e.Row.FindControl("plcControlHolder")
Dim btnDynamic As New Button
btnDynamic.Id = "MyButton"
plcControlHolder.Controls.Add(btnDynamic)

Try using the GroupTemplate and GroupSeparatorTemplate instead of trying to fit it all in the ItemTemplate.

Create a UserControl to include in place of the AddGroupingRowIfWPHasChanged() method call. Override Render(). Use the logic that's currently in AddGroupingRowIfWPHasChanged() to render the control if the group has changed; otherwise, render an empty string.

Related

.NET webform Hide a HTML td column in backend server (Update Panel, Content Template)

I have an instance, it shows a listView.
the listview is in the update panel, it needs to response to each data source binding and show/hide a column in the listView table by checking a Session.
I cannot simply add
<% if((int)Session["v1"] ==1) { %> <td>Hi</td> <%}%>
as the exception throw saying that the update panel cannot update when <% %> exists.
(but it works for the control outside of the update panel)
I think I can do it by javascript but I just want to make sure if there is a smarter way to do in the backend.
class='<%# HiddenClass %>'
and changing this parameter during onload (change HiddenClass to empty string if the column should show.
It works for the item's column (in the ItemTemplate) but it doesn't work for the item's header column LayoutTemplate (i think it is because data source binding only re-rendered the fields in the ItemTemplate and not included LayoutTemplate.
currently, I was able to hide it to set the runat="server" Visible to false if for each data source binding of the listview. But it looks very complicated when I need to hide more columns (need to create more ID and asp.net cannot set visible of fields by class).
Wrap the <td></td> with a PlaceHolder and set it's Visibility property from code behind.
<asp:PlaceHolder ID="PlaceHolder1" runat="server" Visible="false">
<td>Hi</td>
</asp:PlaceHolder>
And then in code behind
if ((int)Session["v1"] == 1)
{
PlaceHolder1.Visible = true;
}

ASP.Net Checkboxlist Background color

I have a checkboxlist on aspx
<asp:CheckBoxList ID="cblCalendarFilter" runat="server" />
I add the listItems from code behind.
newCkItm = new ListItem();
newCkItm.Text = childrenFoldersData[i].Description.Trim();
newCkItm.Value = childrenFoldersData[i].Id.ToString().Trim();
newCkItm.Selected = true;
I can add the background of the ListItem by
newCkItm.Attributes.Add("style", "background-color:Red;");
The colors will be different from one item to another and the name of the item will also be different. So, the problem is the background color is only covering the text length. The background color is not aligned for all Items. I checked with the inspector and found out that..
The background color style is applying to <span> surrounding the text
All spans are inside the <td>.
I am wondering if there is a way to apply that style to <td> without much effort. I'd rather not use jquery and javascript by searching the name.
Is there any way to do that??
I have tried and found this solution & it worked for me.
Just try to give padding-right
for example:
newCkItm.Attributes.Add("style", "background-color:Red;padding-right:30px");
Instead of adding a style attribute to each item, and because you mentioned each item needs a different background colour, I'd add an id attribute:
newCkItm.Attributes.Add("id", "alpha");
That way you can keep all your styles separate from your code and not have to recompile, etc. every time you need to tweak the CSS.
With the <asp:CheckBoxList /> the CSS itself would look something like this:
#cblCalendarFilter {
border:none;
border-collapse:collapse;
}
#cblCalendarFilter td {
padding:0;
}
#cblCalendarFilter span {
display:block;
padding:2px;
}
#cblCalendarFilter #alpha {
background:red;
}
#cblCalendarFilter #beta {
background:yellow;
}
Hopefully making the span block-level will fix the issue you had with the background colour only covering the text length.
How about if you use a Repeater which has tr/td with CheckBox inside it and do the logic on the ItemDataBound event where you can retrieve the td:
<table>
<asp:Repeater ID="rpt" runat="server" OnItemDataBound="rpt_ItemDataBound">
<ItemTemplate>
<tr>
<td id="myTd" runat="server">
<asp:CheckBox runat="server" ID="myCheckBox" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
I think there is no other way, you have to individually access the element and assign the css to items. I tend to use foreach loop, access the item and add attributes. TBH, I would stay with checkboxlist compared to repeater, unless I need some extra functionality

Passing in a value to a usercontrol through a foreach loop

in my asp.net mark up I have a foreach loop that iterates through a simple list. In this foreach loop I am adding a new user control and attempting to pass in the value from the loop. However, this value just wont budge and get inside that damn control! Anyone have any suggestions?
<%foreach (userInfo i in this.items)
{ %>
<uc1:ItemControl ID="ItemControl" runat="server" UserID='<%#Eval("userID") %>'/>
<%} %>
userID is a public property in the control, when it goes to set, the value is just literally : <%#Eval("userID") %>. I've tried #Bind and =Value but nothing seems to work.
Any help would be appreciated!
Looks like the perfect use case for a repeater:
<asp:Repeater runat="server" id="myRepeater">
<uc1:ItemControl ID="ItemControl" runat="server" />
</asp:Repeater>
You can databind your list (this.items) to the repeater and in the code behind, in the DataBind event set the UserID property of the ItemControl control.
The reason your approach will not work is that IDs have to be unique in a page.
Try use a Repeater control for your purpose

How Do I Get a Dynamic Control's Value after Postback?

I have a listview that adds controls in the ItemDataBound Event. When the postback occurs, I cannot find the new controls. After a bit of research, I found that ASP .NET needs these controls created every time, even after postback. From there I moved the function to bind the ListView outside of the if (!Page.IsPostBack) conditional. Now I get the dynamic controls values but the static controls I have are set to their defaults. Here is a sample of what I am trying to accomplish:
For brevity, I left some obvious things out of this example.
<asp:ListView runat="server" ID="MyList" OnItemDataBound="MyList_ItemDataBound">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</LayoutTemplate>
<ItemTemplate>
<asp:PlaceHolder runat="server" ID="ProductPlaceHolder">
<asp:TextBox runat="server" ID="StaticField" Text="DefaultText" />
<asp:PlaceHolder ID="DynamicItems" runat="server" />
</asp:PlaceHolder>
</ItemTemplate>
</asp:ListView>
and here is the codebehind:
protected void MyList_ItemDataBound(object sender, System.Web.UI.WebControls.ListViewItemEventArgs e) {
PlaceHolder DynamicItems = (PlaceHolder)e.Item.FindControl("DynamicItems");
DynamicItems.Controls.Add(textbox);
}
So, like I said, if I only databind when Page != PostBack then I cant find my dynamic controls on postback. If I bind every time the page loads then my static fields get set to their default text.
Try moving the data binding of the ListView into the OnInit() event.
Very similar question (instead of populating a ListView the guy is generating a set of buttons). Briefly, you'll find that you have to store the items in the list in your Viestate - than fish it out on Postback and re-populate the list.
Note that this solutions implies dropping data-binding (which you might not wanna do for others reasons).
Hope it helps.

How to set DropDownList's selected value inside a Repeater?

I need to create a group of DropDownLists to show and allow change of a property group for an item.
I have the following code on my ASP page.
<asp:Repeater runat="server" ID="repeaterProperties">
<ItemTemplate>
<p><asp:DropDownList runat="server" ID="ddProperty" OnInit="ddProperty_OnInit" /><p>
</ItemTemplate>
</asp:Repeater>
The ddProperty_OnInit populates the DropDownList with all the possible values with a database query.
How can I set the selected value of each created DropDownList according to the Repeater's source data?
Let's say, for example, that we have the possible property values of A, B and C.
If the database output for the Repeater contains two of those values, A and B, the Repeater outputs two DropDownLists, both with all 3 values availabla and the first one with A as selected value and the second one with B as selected value.
Edit:
It seems that adding OnItemDataBound="repeater_ItemDataBound" to the Repeater and selecting the appropriate value in there is not the way to go in my case. This is because I also need to save the possibly changed values to a database.
The ItemDataBound event of the Repeater is fired before the OnClick event on a Button and changes the selected values to their old values before the new selections can be saved.
Any suggestion on how to work around this?
Current code:
<asp:Repeater runat="server" ID="repeaterJako" OnItemDataBound="repeater_ItemDataBound">
<ItemTemplate>
<asp:DropDownList id="ddJako" runat="server" OnInit="ddJako_OnInit">
</asp:DropDownList><br />
</ItemTemplate>
</asp:Repeater>
<asp:Button runat="server" id="updateButton" Text="Save" OnClick="update_OnClick" />
In the code-behind, ddJako_OnInit populates the drop down list with all the possible choises, while the repeater_ItemDataBound uses the method suggested by Bryan Parker to select the proper value.
Maybe I'm misunderstanding something about your question... but it seems like this is exactly what OnItemDataBound is for. :)
Use FindControl to get a reference to your DropDownList in the event handler. Also check to make sure the item is not the header/footer. The example from MSDN does both these things:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater.onitemdatabound.aspx
In regard the problem I specified in my edit, the time of the DataBind plays an important role. I used to do the databinding in the Page_Init event, which caused the repeater_ItemDataBound event to be fired before the button_OnClick event.
The solution was to move the databinding to the Page_PreRender event.
The population of the DropDownList with all the choises is still done in its OnInit event.

Categories