I am having trouble setting the value of a textbox inside a nested listview (listview inside a lsitview). What I am trying to do is pull values of two textboxes (which is working fine), multiply them together, and set that value to the third textbox (where I am having the trouble).
here is the listview setup that I have:
<asp:ListView ID="LV_Tickets" runat="server" ClientIDMode="Static" DataSourceID="SQL_Tickets" InsertItemPosition="FirstItem" OnPreRender="LV_Tickets_PreRender" DataKeyNames="TicketNum">
<SelectedItemTemplate>
<asp:ListView ID="LV_TicketProd" runat="server" DataKeyNames="ChargeID" DataSourceID="SQL_TicketProducts" InsertItemPosition="LastItem" OnPreRender="LV_TicketProd_PreRender" OnItemInserted="LV_TicketProd_ItemInserted" OnItemInserting="LV_TicketProd_ItemInserting" OnItemUpdated="LV_TicketProd_ItemUpdated" OnItemUpdating="LV_TicketProd_ItemUpdating">
<InsertItemTemplate>
<td>
<asp:TextBox ID="HoursOrCubesTextBox" runat="server" style="height: 20px; width: 165px;" Text='<%# Bind("HoursOrCubes") %>' OnTextChanged="HoursOrCubes_TextChanged" AutoPostBack="true" />
</td>
<td>
<asp:TextBox ID="RateTextBox" runat="server" style="height: 20px; width: 120px;" Text='<%# Bind("Rate") %>' OnTextChanged="Rate_TextChanged" AutoPostBack="true" />
</td>
<td>
<asp:TextBox ID="LineTotalTextBox" runat="server" style="height: 20px; width: 120px;" Text='<%# Bind("LineTotal") %>' />
</td>
</ InsertItemTemplate>
</ SelectedItemTemplate>
The current way that I am getting the values from HoursOrCubesTextBox and RateTextBox is:
protected void HoursOrCubesTextBox_TextChanged(object sender, EventArgs e)
{
ListView LV_TicketProd = (ListView)Session["TicketProd"];
TextBox HoursOrCubesTextBox = (TextBox)(LV_TicketProd.InsertItem.FindControl("HoursOrCubesTextBox"));
string HoC = HoursOrCubesTextBox.Text //This here is getting the value from the textbox.
}
But when I try to do the opposite to set the value of the textbox nothing happens:
TextBox LineTotalTextBox = (TextBox)(LV_TicketProd.InsertItem.FindControl("LineTotalTextBox"));
LineTotalTextBox.Text = FinalValue; //FinalValue is the two values multiplied together.
I have check that the values coming from the textboxes are correct, and that when I multiply them together I get a value that is an integer. So I am not entirely sure why I cannot set the value of the LineTotalTextBox. Any help will be greatly appreciated.
Don't try reading & writing into the item template. That's the ListView's job.
Read & write the data source which the ListView is bound to.
I'd show examples if what I mean, but I can't figure your code.... Are you filling the ListView from an SQL db or from User input?
I figured out how to fix this problem. What I did was set the two textboxes HoursOrCubes and Rate to autopostback, then did the multiplication and setting of the textbox in the onload function.
Related
I have a button in a ListView that when its click it opens a modal with information relevant to the button that was clicked. I was able to get the index of the current listview item but I need to get the text from a label in both the previous item and next item. Heres what I have:
protected void List_ItemCommand(object sender, ListViewCommandEventArgs e)
{
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
//Gets index of Listview
int DispalyIndex = e.Item.DisplayIndex;
int ItemIndex = e.Item.DataItemIndex;
Button index = (Button)dataItem.FindControl("TitleButton");
Label Name = (Label)dataItem.FindControl("LabelName");
}
I tried decrementing the index but no luck, anyone have an idea or a better solution? Thanks.
UPDATE
Heres my listviews, I use the first Listview to get the title and then the second to pull Jobs under the title. I bind both with a query using data bind
<asp:ListView ID="List" runat="server" OnItemCommand="List_ItemCommand" OnItemDataBound="List_ItemDataBound">
<LayoutTemplate>
<table>
<tr>
<asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<span class="label label-primary"><%# Eval("LabelName")%></span> <br />
<asp:ListView ID="JobList" runat="server" ItemPlaceholderID="JobPlaceHolder" OnItemDataBound="JobList_ItemDataBound">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="JobPlaceHolder" />
</LayoutTemplate>
<ItemTemplate>
<br />
<asp:Button runat="server" ID="TitleButton" Text='<%# Eval("Job Title") %>' Font-Size="XX-Small" Font-Bold="true" CssClass="btn-xs btn-default" ClientIDMode="Static" OnClick="TitleButton_Click" />
</ItemTemplate>
<EmptyDataTemplate>
<br />
<b> <asp:Label runat="server" Text="There is no job for this Family and Level!" /></b>
</EmptyDataTemplate>
Try this
//null check before performing an operation, dataItem might be the first element in the page
//If so, prevItem will be null
var prevItem = List.Items[itemIndex - 1].FindControl("LabelName") as Label;
//null check before performing an operation, dataItem might be the last element in the page
//If so, nextItem will be null
var lastItem = List.Items[itemIndex + 1].FindControl("LabelName") as Label;
I've got this code in the code-behind on my page, which works perfectly fine for a repeater:
protected void AcctAssnRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["PBRConnectionString"].ConnectionString);
con.Open();
{
string str10 = ((HtmlInputText)e.Item.FindControl("txtFlgUpdatedOn")).Value;
}
}
I'm trying to do something similar on another page, but it is telling me that "item" isn't valid:
protected void btnSubmit_OnClick(object sender, EventArgs e)
{
string str10 = ((HtmlInputText)e.Item.FindControl("txtDtSentToCIS")).Value;
}
I'm still a C# n00b, can anyone tell me how to reference the value inside this control? Both pages have a runat="server" on the aspx side, so I would expect that there's a way to do it, I'm sure my syntax just needs adjusting.
Thanks!
EDIT: Here's a piece of the aspx. Maybe I should note that it's all inside a Tab Control.
<div style="width:430px;border:1px solid blue;float:left;">
<asp:Panel ID="Panel3" runat="server" Height="220px" style="float:left; margin-left: 19px"
Width="410px">
<table>
<tr>
<td width="210px">BIL Name:</td>
<td width="200px"><asp:textbox id="txtCISName" runat="server"></asp:textbox></td>
</tr>
<tr>
<td width="210px">Date Sent To BIL:</td>
<td width="200px"><input type="text" id="txtDtSentToCIS" class="datepicker" name="txtDtSentToCIS" runat="server" style="height: 14px; width: 70px" /></td>
</tr>
<tr>
<td width="210px">BIL Sign Off Received:</td>
<td width="200px"><asp:DropDownList ID="cboCISSignOff" runat="server" Height="16px"
AutoPostBack="True" onselectedindexchanged="chkCISSignOff_CheckedChanged">
<asp:ListItem>N</asp:ListItem>
<asp:ListItem>Y</asp:ListItem>
</asp:DropDownList></td>
</tr>
<tr>
<td width="210px"><asp:Label runat="server" Text="BIL Response:" ID="CISResp" /></td>
<td width="200px"><asp:textbox id="txtCISResponse" runat="server"
textmode="MultiLine" rows="9" Width="180px"></asp:textbox></td>
</tr>
</table>
</asp:Panel>
</div>
You should be able to use the ID to reach the control. For ex. a textbox:
<asp:TextBox ID="txtDtSentToCIS" runat="server" />
In your code behind you can do something as
SomeMethod(this.txtDtSentToCIS.Text);
or
string enteredByUser = this.txtDtSentToCIS.Text;
If you want to access repeater containing textbox(es) from outside the repeater, you may code like this:
Iterating the RepeaterItemCollection:
foreach (RepeaterItem item in Repeater1.Items)
{
TextBox txtDtSentToCIS = item.FindControl("txtDtSentToCIS") as TextBox;
}
Or simply accessing through indexer:
TextBox txtDtSentToCIS = Repeater1.Items[1].FindControl("txtDtSentToCIS") as TextBox;
Good luck.
If you are using asp I would suggest that you use an asp Text box.
<asp:TextBox ID="textBoxName" runat="server" />
When the button is clicked and you OnClick method is called you can search for the text box by name and assign the text to your string.
string str10 = textBoxName.text;
You don't really need to use the find control unless that control is buried in another control like a grid view or login view.
What could be happening is that the FindControl method only works for the first control collection in this case the only control contained is "Panel3", try this:
var panel = e.Item.FindControl("Panel3") as Panel;
string str10 = ((HtmlInputText)panel.FindControl("txtFlgUpdatedOn")).Value;
Good luck
I have an accordion that has another accordion inside one of its panes. This inner accordion is created using a datasource so each of its panes are loaded from a list of objects. In this particular case, this datasource is also loaded on demand. Now, where I'm stuck is that I want to be able to load the pane headers only and then load the contents when the pane is clicked; similar to what I have in the outer pane. The reason I'm confused here, is because the lazy load happens when the pane is clicked, but since this happens AFTER the databind, I don't know how to reference the content of the pane that invokes the ItemCommand. Not sure if that makes sense. Here is the inner accordion:
<ajaxToolkit:Accordion runat="server" ID="accReviewers" OnItemDataBound="accOuterAccordion_ItemDataBound" ContentCssClass="ReviewerContent" RequireOpenedPane="False" SelectedIndex="-1" OnItemCommand="accReviewers_ItemCommand">
<HeaderTemplate>
<div>
<asp:LinkButton Text='<%#Eval("Header") %>' CssClass="InReviewHeader" runat="server"
CommandName="LoadReviewers" CommandArgument='<%#Eval("MocRequestId") %>'/>
</div>
</HeaderTemplate>
<ContentTemplate>
<div>
<asp:ListView runat="server" ID="lvReviewers" ItemPlaceholderID="phReviewer" OnItemDataBound="lvReviewers_ItemDataBound">
<LayoutTemplate>
<div>
<asp:HyperLink runat="server" ID="lnkGotoRequest" Text="View this request"/>
</div>
<asp:PlaceHolder runat="server" ID="phReviewer"/>
<div style="margin-top: 5px;">
<asp:Button runat="server" ID="btnResubmit" Text="Resubmit" CssClass="ResubmitInitial"/>
</div>
</LayoutTemplate>
<ItemTemplate>
<div class="ReviewerItem">
<%#Eval("Assignee.Name") %><br />
<img src="" alt="Reviewer" runat="server" ID="imgReviewer" width="75" style="border: 1px solid gray; border-radius: 6px;"/><br />
<asp:Label runat="server" ID="lblStatus" Text='<%#Eval("ReviewStatus") %>' />
<asp:HyperLink runat="server" ID="lnkRejectComment" CssClass="InitialRejectComment">(details)</asp:HyperLink>
</div>
</ItemTemplate>
</asp:ListView>
</div>
</ContentTemplate>
</ajaxToolkit:Accordion>
</Content>
</ajaxToolkit:AccordionPane>
As you can see, the accordion accReviewers is generated via a DataSource. The listview contained in the LayoutTemplate will not have its datasource bound until the LinkButton has been clicked, which will fire the item command. Also worth noting that this entire accordion is wrapped in an UpdatePanel.
This is the code behind I was starting to work with, but it doesn't appear to get the correct instance of the listview and while the list is not empty, it will not display anything:
protected void accReviewers_ItemCommand(object sender, CommandEventArgs e)
{
var mocId = int.Parse(e.CommandArgument.ToString());
var list = (sender as AjaxControlToolkit.Accordion).FindControl("lvReviewers") as ListView; //APPARENTLY WRONG
var reviewers = MocApi.GetReviews(mocId);
list.DataSource = reviewers;
list.DataBind();
}
So to recap, when the LinkButton within the HeaderTemplate is clicked, I need to somehow gain reference to the correct instance of the ListView so that I can bind its datasource. As always, any help or insight is appreciated. This is similar to a previous question of mine but is specific to gaining this reference after databind which seems a bit more complicated. TIA
UPDATE:
I found that I can bind the item datasource if I can somehow capture its index. I'm exploring trying to set that as a command argument during the databinding of the inner accordion.
I managed to solve this with some minor shenannigans:
Here is the markup:
<ItemTemplate>
<div class="ReviewerItem">
<%#Eval("Assignee.Name") %><br />
<div style="display: inline-block; position: relative;">
<img src="" alt="Reviewer" runat="server" ID="imgReviewer" width="75" style="border: 1px solid lightgray; border-radius: 6px; overflow: hidden;"/><br />
<div runat="server" ID="divYes" Visible="False">
<img src="../Images/Yes.png" alt="Approved" class="ApprovalIcon" />
</div>
<div runat="server" ID="divNo" Visible="False">
<img src="../Images/No.png" alt="Rejected" class="ApprovalIcon" id="imgNo" />
</div>
</div>
<asp:Label runat="server" ID="lblStatus" Text='<%#Eval("ReviewStatus") %>' />
<asp:HyperLink runat="server" ID="lnkRejectComment" CssClass="InitialRejectComment">(details)</asp:HyperLink>
<asp:Panel runat="server" ID="pnlDemoApproval" Visible="False" CssClass="DemoButtons">
<asp:Button runat="server" ID="btnApprove" Text="Approve" CommandArgument='<%#Eval("Assignee.Guid") + "|" + Eval("Ticketid") %>' CommandName="ApproveReview"/>
<asp:Button runat="server" ID="btnDeny" Text="Deny" CommandArgument='<%#Eval("Assignee.Guid") + "|" + Eval("Ticketid") %>' CommandName="DenyReview"/>
</asp:Panel>
<ajaxToolkit:BalloonPopupExtender runat="server" ID="balloon" BalloonPopupControlID="pnlPopup"
TargetControlID="lnkRejectComment" Position="TopRight" BalloonStyle="Cloud" BalloonSize="Medium" DisplayOnMouseOver="True"/>
<asp:Panel runat="server" ID="pnlPopup">Rejection Reason</asp:Panel>
</div>
</ItemTemplate>
On databind, I catch the item so that I can grab the index and set it to the CommandName for later use:
AjaxControlToolkit.AccordionItemEventArgs e)
{
if (e.ItemType != AjaxControlToolkit.AccordionItemType.Content) return;
var index = e.ItemIndex;
var button = e.AccordionItem.Parent.FindControl("lnkbHeader") as LinkButton;
if (button != null) button.CommandName = index.ToString();
}
Now that control contains the index, i can use that to target the correct pane and bind its datasource:
protected void accReviewers_ItemCommand(object sender, CommandEventArgs e)
{
//This seems stupid to put here, but for some reason the item command bypasses the listview catch and passes it to the accordion
if (e.CommandName == "ApproveReview")
{
var assigneeGuid = new Guid(e.CommandArgument.ToString().Split('|')[0]);
var ticketId = int.Parse(e.CommandArgument.ToString().Split('|')[1]);
var ticket = new MocApproval(ticketId);
DoDemoApproval(ticketId, assigneeGuid, true);
var approvalIndex = (sender as AjaxControlToolkit.Accordion).SelectedIndex;
var lv =
(sender as AjaxControlToolkit.Accordion).Panes[approvalIndex].FindControl("lvReviewers") as ListView;
lv.DataSource = MocApi.GetReviews(ticket.MocRequest);
lv.DataBind();
return;
}
if (e.CommandName == "DenyReview")
{
var assigneeGuid = new Guid(e.CommandArgument.ToString().Split('|')[0]);
var ticketId = int.Parse(e.CommandArgument.ToString().Split('|')[1]);
var ticket = new MocApproval(ticketId);
DoDemoApproval(ticketId, assigneeGuid, false);
var approvalIndex = (sender as AjaxControlToolkit.Accordion).SelectedIndex;
var lv =
(sender as AjaxControlToolkit.Accordion).Panes[approvalIndex].FindControl("lvReviewers") as ListView;
lv.DataSource = MocApi.GetReviews(ticket.MocRequest);
lv.DataBind();
return;
}
...
I have a form with containing a datalist which is bound to a datasource which contains a list of items and a true/false flag. If true, the myCheck checkbox is checked:
<form id="myForm" runat="server">
<asp:Button ID="save" runat="server" Text="Save" OnClick="save_Click" />
<br />
<asp:DataList runat="server" id="myList" onitemdatabound="myList_ItemDataBound">
<HeaderTemplate>
<th>Item Name</th>
<th id="thCheck" runat="server">Check?</th>
</HeaderTemplate>
<ItemTemplate>
<td id="tdName" runat="server"><%# Eval("Name") %></td>
<td runat="server"><asp:CheckBox id="myCheck" runat="server" Checked="false" /></td>
</ItemTemplate>
</asp:DataList>
On clicking save, I want to see which items have been checked. I am using the following to iterate through the items in the datalist:
protected void save_Click(Object sender, EventArgs e)
{
String Name;
Boolean omit;
foreach (DataListItem item in myList.Items)
{
CheckBox omitCheck = (CheckBox)item.FindControl("myCheck");
if (omitCheck != null)
{
if (omitCheck.Checked == true) // This line is my problem!!
{
// do stuff
}
break;
}
}
FindControl appears to work ok and returns a checkbox, however the value is always false, even if I have checked some of the boxes. If I set the value of the checkboxes to True in the aspx page, omitCheck.Checked is always true. ViewState is not disabled.
I'm new to this so sure there is an obvious answer.
what does the myList_ItemDataBound function look like? I suspect it needs a !IsPostback to not override entered values on the postback
I have a sales simulator written in C#. I did not write this however I am currently modifying it to suit different requirements.
It basically displays a list of products from a database, and has a textbox for each product where you can enter in the quantity sold. The quantity sold is calculated based on it's price in the database.
Now it's all working fine, however there is one SMALL issue. When "Buy" is clicked, it returns me back to the list of products which IS correct, however the quantity I have entered for the previous product remains.
I would like to know how to restore the text boxes to their default value when the after the data is submitted to the database.
I always thought the way to do this would be in the .cs code behind file
txtQuantity.Text = "";
However, for some odd reason, txtQuantity will not show up.
Can anyone think of anything I am doing wrong? Here is a snippet of code from the aspx file.
<form id="form1" runat="server">
Date:
<asp:TextBox ID="txtDate" runat="server" />
Retailer:
<asp:DropDownList ID="dlStore" runat="server"
onselectedindexchanged="dlStore_SelectedIndexChanged" />
<asp:ListView ID="lbProducts" runat="server">
<LayoutTemplate>
<layouttemplate>
<table border="1" cellpadding="1" style="width:800px">
<tr style="background-color:#E5E5FE">
<th>ID</th>
<th>ProductCode</th>
<th>Product Title</th>
<th>RRP $</th>
<th>Quantity</th>
<th>Sale Price $</th>
</tr>
<tr id="itemPlaceholder" runat="server"></tr>
</table>
</layouttemplate>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td style="width: 50px;">
<%#Eval("ProductID") %>
</td>
<td>
<%#Eval("ProductCode") %>
</td>
<td>
<%#Eval("ProductTitle") %>
</td>
<td>
<%#Eval("USListPrice") %>
</td>
<td style="width: 50px;">
<asp:TextBox ID="txtQuantity" runat="server" Text="0" />
</td>
<td style="width: 50px;">
<asp:TextBox ID="txtSalePrice" runat="server" Text="0.00" />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
<asp:Button ID="btnBuy" Text="Buy These Items" runat="server" OnClick="btnBuy_Click" />
<asp:Button ID="btnClear" Text="Clear Existing Sales" runat="server"
onclick="btnClear_Click" />
</form>
There's a lot going on in the code behind file and I wouldn't expect anyone to go through it, but how I collect the data from txtQuantity is done with the following line of code:
Int32 quantity = Int32.Parse(((TextBox)item.FindControl("txtQuantity")).Text);
So what I want to be able to do is set this textbox either to be empty, or back to zero.
Any help is appreciated, thanks.
Because that txtQuantity control is within a ListView, there could be any number of instances of that control generated. So you can't access all of them through a single variable.
You will need to look through all controls within that ListView (and several levels deep) to find all your txtQuantity controls.
The same of course for the txtSalePrice control.
EDIT
You could find those textboxes with code like (untested)
public IEnumerable<TextBox> FindTextBoxes(Control parent)
{
if (parent == null) yield break;
foreach (Control child in parent.Controls)
{
TextBox tb = child as TextBox;
if (tb != null)
yield return tb; // found one!
else
foreach(TextBox tb in FindTextBoxes(child))
yield return tb; // found it deeper
}
}
and call it like:
foreach(TextBox tb in FindTextBoxes(lbProducts)
{
if (tb.Name == "txtQuantity")
{
// found a quantity
}
else if (tb.Name == "txtSalePrice")
{
// found the salesprice
}
}