RadioButtonList with Repeater - c#

I read a very good article here: (Displaying Data with the DataList and Repeater Controls (C#))
https://www.asp.net/web-forms/overview/data-access/displaying-data-with-the-datalist-and-repeater/displaying-data-with-the-datalist-and-repeater-controls-cs
I was trying to respond to the article author but am unable to add my account through Facebook, Twitter, etc at work to ask my question through the site, so I though I would ask here.
The example is very thorough and easy to follow, but I would like to see a RadioButtonList (say with Gender) x Male Female, showing the DB field value.
This would be a big help to compliment the article content
thx

First you need to add the RadioButtonList to the DataList or Repeater (they both work the same so I will provide only one example) and add the OnItemDataBound event.
<asp:DataList ID="DataList1" runat="server" OnItemDataBound="DataList1_ItemDataBound">
<ItemTemplate>
<asp:RadioButtonList ID="RadioButtonList1" runat="server"></asp:RadioButtonList>
</ItemTemplate>
</asp:DataList>
Code behind
protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
{
//find the control with findcontrol and cast back to a radiobuttonlist
RadioButtonList radioButtonList = e.Item.FindControl("RadioButtonList1") as RadioButtonList;
//add some listitems, usually filled from list or database
for (int i = 0; i < 5; i++)
{
radioButtonList.Items.Insert(i, new ListItem("ListItem " + i, i.ToString(), true));
}
//cast the dataitem to the datarowview
DataRowView row = e.Item.DataItem as DataRowView;
//set the correct radiobuttonvalue
radioButtonList.SelectedValue = row["dbValue"].ToString();
}

Related

ASP table row count not getting incremented

I have an ASP table, with a dropdownlist and text box in its 1st row. I have a button on click of which a similar row should be added. I have the following function in its button click event.
public void addRow()
{
int flag = Table1.Rows.Count;
DropDownList ddl = new DropDownList();
ddl.ID = "ddl" + (flag + 1).ToString();
TextBox tBox = new TextBox();
tBox.ID = "txt" + (flag + 1).ToString();
TableCell tCell1 = new TableCell();
TableCell tCell2 = new TableCell();
tCell1.Controls.Add(ddl);
tCell2.Controls.Add(tBox);
TableRow tRow = new TableRow();
tRow.Cells.Add(tCell1);
tRow.Cells.Add(tCell2);
Table1.Rows.Add(tRow);
}
This code works fine when adding 2nd row. When I click the button again, the value of flag which should have the value of number of rows of the table is not getting incremented. So a new row doesn't get created. Can you please tell me why the value of flag doesn't get incremented ? Or is their an easier way to do this ? Direct answer or link would be helpful.
Mark up code for Table:
<asp:Table ID="Table1" runat="server" Width="410px">
<asp:TableRow>
<asp:TableCell>
<asp:DropDownList runat="server" ID="ddl1"></asp:DropDownList>
</asp:TableCell>
<asp:TableCell>
<asp:TextBox runat="server" ID="txt1"></asp:TextBox>
</asp:TableCell>
</asp:TableRow>
</asp:Table>
Warning - Big ugly block of text
I'm going to try and explain why what you're trying to do is not as simple as it sounds (or as simple as I'd like it to be) and hopfully give you an alterantive approach, which while it
may not be straight forward, it should be "better".
It looks a high level overview of what you are trying to do is the following:
Give the user the oppotunity to add one or more records to a collection (database) before finalising the save.
It is possible to do this using postback to generate the additional rows/items beofore clicking the final save button. Hover this may not be the easiest, or best, way to do this.
From a technical viewpoint adding dynamic controls has to be handeld in a very specific manner at a specific point in the ASP.net page lifecylce. Dynamic controls also have to be recreated on every post back, so every time a user clicks the "add" button, you will have to re-reate the rows you already have in addition to the new row. This is why you only get the one row in this example. Thats just the adding of the dynaimc controls. Wait till you get to getting data from your dynamic text boxes and drop downs!
From an end users perspective, this approach is also not ideal as every time the user clicks the "add" button the page cycles through the request/response process, which at the minumun cuases a bit of an ugly flash.
Update
But how? I hear you ask. Well here it is (I've simplified it to one column for this example):
ASPX
<asp:Table ID="Table1" runat="server">
<asp:TableRow>
<asp:TableCell><asp:TextBox ID="txt1" runat="server"> </asp:TextBox></asp:TableCell>
</asp:TableRow>
</asp:Table>
<asp:Button ID="btnAdd" runat="server" Text="Add" onclick="Button1_Click" />
<asp:HiddenField ID="hdnRowCount" runat="server" />
<asp:Button ID="btnSave" runat="server" onclick="btnSave_Click" Text="Save" />
<div>
<asp:Label ID="lblResult" runat="server" Visible="false"></asp:Label>
</div>
C#
private int rowCount = 1;
private bool rowNeeded = false;
protected override void OnPreInit(EventArgs e)
{
//Pre-emptively create additional row on post back.
//We'll remove it if we don't need it later
//Controls Have to be added at pre-init to maintain their view state
//Adding a row in the button click event will result in any data
//entered in that row dissapearing from viewstate on next post back
if (IsPostBack)
{
//Get number of additional rows from hidden field
//We're using a hidden form field and Request.Form
//instead of ViewsState and hdnRowCount.value
//because ViewState has not been loaded at this stage
//of the page life cycle
if (!string.IsNullOrEmpty(Request.Form["hdnRowCount"]))
{
rowCount = int.Parse(Request.Form["hdnRowCount"]);
}
for (int i = 0; i < rowCount; i++)
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TextBox tb = new TextBox();
// +2 as there are existing controls with "1", eg txt1
tb.ID = string.Format("txt{0}",i+2);
tc.Controls.Add(tb);
tr.Cells.Add(tc);
Table1.Rows.Add(tr);
}
}
base.OnPreInit(e);
}
//Add Row Click
protected void Button1_Click(object sender, EventArgs e)
{
//Hold number of additional rows in hidne field
hdnRowCount.Value = (++rowCount).ToString();
//Let the page know we need to keep the row
rowNeeded = true;
}
//An Exmple of how to get your data out
protected void btnSave_Click(object sender, EventArgs e)
{
string s = "";
//Iterate through the table rows finding the controls
//Using count -1 as we still have the pre-emptive row
for(int i = 0; i < Table1.Rows.Count-1; i++)
{
TextBox tb = (TextBox)Table1.Rows[i].FindControl(string.Format("txt{0}",i+1));
s += "," + tb.Text;
}
lblResult.Text = s;
lblResult.Visible = true;
}
protected override void OnLoadComplete(EventArgs e)
{
//Get rid of pre-emptive row if we don't need it
if (IsPostBack)
{
if (!rowNeeded)
{
Table1.Rows.RemoveAt(Table1.Rows.Count - 1);
}
}
base.OnLoadComplete(e);
}
End Update
So, how would I do it? Client side, is the answer to that question. I would use jQuery to create a clone of the first row. You then would need to adjust the id and name attributes of your form fields before appending your new row to the table. You would also need a hidden form field to keep track of the number of hidden rows. When your user finaly hits the "save" button, on the C# side, get the number of additional rows from you hidden field the go old school and use Request.Form[] to get the value of each of your added fields.
This, in my opionion, will be a smoother experience for the end user.
Another, somewhat hacky option,if you have a defined maximum number of additional rows. For this have the mamimum rows, with form controls in the table. You can then either use visible="false" in the aspx and use post back to change that to visible="true" when the user clicks "add". The other option there is to give the row a CSS class that hides the row and then use javascript/jquery to remove the class to make the row visible.
The issue here is that you are not understanding the ASP.Net Page Lifecycle and more importantly how it interacts with dynamic controls (your added controls.)
Unfortunately, we can not answer this question without understanding whether the values in these "dynamically" created controls are used server-side or client-side.
I can guess that:
1) If they are for client side consumption/usage, you are doing wrong. If you need more info ask another (more specific) question.
2) If they are for server side consumption/usage, you must only allow one new record per postback, and should include a "Save" button that will save the current "new" row and cause a page refresh that the user can add a new entry to.
3) See rule #0 (Every rule has exceptions. {This rule applies in so far that you understand the problem at hand.})
Monk

Accessing Object data in repeater

I have a repeater on my asp.net web forms page.
The repeater data source is a list of "OrderLine" objects.
Each repeater item has a TextBox control that displays the quantity of the order line.
When the quantity in the textbox control is changed, there is an auto postback to recalculate the total and discount value properties of the OrderLine object.
My question is, is there a better way to access the object data directly instead of getting the index of the repeater item and using that to get the object list index like below?
I'd like to access the object directly if possible rather than create temporary variables.
protected void txtLineQuantity_TextChanged(object sender, EventArgs e)
{
RepeaterItem rItem = (RepeaterItem)((Control)sender).NamingContainer;
int i = rItem.ItemIndex;
decimal netPrice = OrderLines[i].NetPrice;
decimal netTotal = OrderLines[i].NetTotal;
int qty = OrderLines[i].Quantity;
decimal weight = OrderLines[i].Weight;
TextBox txtLineQuantity = (TextBox)rItem.FindControl("txtLineQuantity");
//... do calculations and bind data to repeater control
}
If i've missed any info that's needed please let me know...
Thanks
You can add a HiddenField control to RepeaterItem. Bind data to HiddenField.
ASP
<asp:Repeater runat="server" ID="repeater">
<ItemTemplate>
<asp:HiddenField ID="hiddenNetPrice" runat="server" Value='<%# Eval("NetPrice") %>' />
<!--Other Controls
</ItemTemplate>
</asp:Repeater>
C#
RepeaterItem rItem = (RepeaterItem)((Control)sender).NamingContainer;
var hiddenNetPrice= rItem.FindControl("hiddenNetPrice") as HiddenField;
var netPrice = hiddenNetPrice.Value;

data pager in listview Issue

I have a listview where in I placed datapager as follows.
I am using SQl datasource and binding the records to ListView.
asp:ListView runat="server" ID="ListView1" DataKeyNames="ProductId,GameName" DataSourceID="GameTable" OnItemCommand="On_Select_Item"
and datapager in the LayoutTemplate
And in the item template I am placing a button, when clicked it calls a method where i am trying to fetch DatakeyName values. It is working fine in first page when pager is given, However when moved to other page in the pager, it is throwing me an exception.
Here is the button click code,
protected void On_Select_Item(object sender, ListViewCommandEventArgs e)
{
if (String.Equals(e.CommandName, "AddtoCart"))
{
//checks if the user is logged in
if (User.Identity.IsAuthenticated)
{
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
DropDownList dl = e.Item.FindControl("DropDownList") as DropDownList;
String val="";
if (dl != null)
{
val = dl.SelectedValue; //Get the selected value from DropDownList
}
String price = Convert.ToString(e.CommandArgument).Trim(); //Get the price for the selected game.
-------------Exception is thrown at below line ---------
string ProductId =
ListView1.DataKeys[dataItem.DataItemIndex]["ProductId"].ToString(); //Product Id for the selected game.
string GameName = ListView1.DataKeys[dataItem.DataItemIndex]["GameName"].ToString(); //gamename
...............................
.............................
}
Define a grid first (you can change the control name to listView but the implementation is the same )
<asp:GridView runat="server" ID="grdResult"
CellPadding="2"
OnPageIndexChanging="grdResult_PageIndexChanging"
GridLines="None"
Width="100%"
AllowSorting="True"
AllowPaging="True"
Then in the bottom define a data source
<asp:SqlDataSource ID="sqlGridData" runat="server"></asp:SqlDataSource>
now in the code behind load your sqlGridData control with data (it accepts many parameters like datatable, odbcrecordset you can use .provider property mentioned here http://tinyurl.com/bllyjsz ) if you have static data them you even mention at the design time (as done here http://tinyurl.com/c8b6mbh)
private void BindDataGrid()
{
sqlGridData.Provider = dataReader;
grdResult.DataSourceID = "xmlGridData";
//grdResult.PageIndex = 0;
}
Try this and do let me know if you have any query.

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.

TreeView Control

I am developing an application using C#. I am using RadioButtonlist control inside a TreeView. I am getting collection of items from database. Based on the collection items I need to select the Radiobuttonlist items.
For example from the database i got the Collection in this way: Read(R) Write(W)
based on this colletion i need to set up the user permissions.
If I get your question right you want to bind that radiobutton list based on the items in the database based on the current row item on the grid. If thats the case here is your solution.
Lets say you have a Grid called myGrid, a RadioButtonList called myRadio and a HiddenField called myHidden (this is where you bind the value you have on "R" and "W")
All you have to do is when a RowDataBound Event Occurs then you have to assign the value to myRadio
for Example, you have a RadioButtonList like such
<asp:RadioButtonList ID="myRadio" runat="server">
<asp:ListItem Value="R">Read</asp:ListItem>
<asp:ListItem Value="W">Write</asp:ListItem>
</asp:RadioButtonList>
So your code behind should look like this
protected void myGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
RadioButtonList rdoAnswer = (RadioButtonList)e.Row.FindControl("myRadio");
HiddenField hdnValue = (HiddenField)e.Row.FindControl("myHidden");
rdoAnswer.SelectedValue = hdnValue.Value;
}
}

Categories

Resources