accessing objects in listview after buttonclick in listviewitem - c#

I'm trying to setup a usercontrol.
I've setup a usercontrol with a table incl table header. For each row a second usercontrol is issued displaying 1 row of the table. The line-usercontrol is embedded in a listview.
One cell of the listview contains a textbox, another cell contains a Button. The buttons for each row are using the same buttonclick event using a commandargument for finding the pressed button.
Is there somekind of way to get the value entered in the textbox of that specific line?
code header control:
<asp:Panel runat="server" ID="pnlUcHeader">
<table>
<thead>
<tr>
<th>...</th>
...
<th>Textbox Column</th>
<th>Button Column</th>
</tr>
</thead>
<asp:ListView runat="server" ID="lvUcItemsItem" OnItemDataBound="lvUcItems_ItemDataBound">
<ItemTemplate>
<uc1:Items runat="server" ID="ucItems" CssClass="normal" />
</ItemTemplate>
</asp:ListView>
</table>
code Item User control
<tr runat="server" id="serverRow">
<td>
<asp:Literal runat="server" ID="..."></asp:Literal></td>
<td>
<asp:TextBox runat="server" ID="tbItem"></asp:TextBox>
</td>
<td>
<asp:Button runat="server" ID="btnItem" Text="..." OnCommand="btnItem_Click"/>
</td>
code behind Item User control
protected void btnItem_Click(object sender, CommandEventArgs e)
{
var lineID = e.CommandArgument;
//TextBox tb = FindControl("tbAfhaalDatum)
???????
}
Is this possible in code behind or is there an option to use Javascript/Jquery to postback the value?
Kind regards

You have to access your control's NamingContainer to search for your text box:
protected void btnItem_Click(object sender, CommandEventArgs e)
{
var control = (Control)sender;
var container = control.NamingContainer;
var textBox = container.FindControl("tbItem") as TextBox;
if (textBox != null)
{
var lineID = e.CommandArgument;
var text = textBox.Text;
}
}

Related

Show hide repeater item template field when used with user control in item template

Hi I have a user control inside repater item template .I want to hide the user controls column based on certain values coming in the string.Below are my code
<asp:Repeater runat="server" ID="MyRepeater" OnItemDataBound="MyRepeater_ItemDataBound">
<ItemTemplate>
<uc2:UCToolEventSummary runat="server" ID="UCSummary"
TaskId='<%#Eval("TaskId")%>'
SystemName='<%#Eval("SystemName")%>'
ResourceName='<%#Eval("ToolName")%>'
Requestor='<%#Eval("Requestor")%>'
CategoryName='<%#Eval("CategoryName")%>'
</ItemTemplate>
</asp:Repeater>
I want to hide the columns based on a string list
list<string> columnsHidden = "SystemName,CategoryName"
So systemname and categoryName should be hidden in the user control
I tried below approach in item databound event but could not able to do that
protected void MyRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
List<String> columnsList = new List<String>();
columnsList = "SystemName,CategoryName";
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
var control = e.Item.FindControl("UCSummary");
foreach (String columnName in columnsList)
{
}
}
}
My Usercontrol code is below
<table class="table table-bordered">
<tr class="row">
<td class="col25">
Task Id: <%=TaskId %>
</td>
<td class="col25">
System Name: <%=SystemName %>
</td>
<td class="col25">
Task Status: <%=TaskStatus %>
</td >
<td class="col25">
Requestor: <%=Requestor %>
</td>
<td class="col25">
Request Type: <%=CategoryName %>
</td>
</tr>
</table>
Can anybody help me on this?
Thank you
You have in your markup added some custom attributes with the columns you need. Thus, on item data bound you should be able to grab/get that control, and then hide/show other columns (controls) in that repeater.
And I don't see the need for a for each loop. The item data bound fires ONE time for each row on data bind.
Thus:
var UCToolEventSummary UC = e.Item.FindControl("UCSummary");
if UC.Attributes.item("CategoryName") = "zoo" {
get other controls - hide or show them - use style in place of visible

Update SQL from Checkbox in ListView

Goal: Update row(s) in SQL table when Checkbox inside ListView is clicked.
I would like to update the following columns from sql:
IsApproved
ApprovalType
I am able to find the checkbox in the row that is clicked from the Listview on the page. However, that is as far as I got. Current code below, as well as what I've tried and the subsequent errors.
Code:
aspx:
<asp:ListView ID="lstUsers" runat="server" ItemType="Program.Data.Table" DataKeyNames="ID" SelectMethod="lstUsers_GetData"
OnItemCommand="lstUsers_ItemCommand" DeleteMethod="lstUsers_DeleteItem" OnSorting="lstUsers_Sorting"
OnItemDataBound="lstUsers_ItemDataBound"
ItemPlaceholderID="litPlaceHolder" >
<LayoutTemplate>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>UserName</th>
<th>Approve User</th>
<td><%# Item.LastName %></td>
<td><%# Item.FirstName %></td>
<td><%# Item.UserName %></td>
<td> <asp:CheckBox ID="cbApproved" runat="server" AutoPostBack="true" OnCheckedChanged="Approve_Click" /> </td>
c#:
protected void Approve_Click(object sender, EventArgs e)
{
foreach (ListViewItem item in lstUsers.Items)
{
if ((item.FindControl("cbApproved") as CheckBox).Checked == true)
{
System.Diagnostics.Debug.WriteLine("it was checked!");
I've tried:
item.ColumnName -- but get error ListView does not contain a
definition for ''
item.DataItem -- the output displays what looks
like an object as a whole
(System.Web.UI.WebControls.ListViewDataItem)
item.DataItem.ColumnName
-- but get error Object does not contain a definition for ''
Do the column values im looking to update in SQL have to be displayed on the ASPX page?
I looked through:
https://msdn.microsoft.com/en-us/library/bb398790.aspx#ModifyingDataUsingTheListViewControl
Asp.Net CheckBoxList to update a SqlDataSource
Why not simply cast the sender to a CheckBox?
protected void Approve_Click(object sender, EventArgs e)
{
if ((sender as CheckBox).Checked == true)
{
System.Diagnostics.Debug.WriteLine("it was checked!");
}
}
You must bind data to the ListView inside an IsPostBack check for it to work.
UPDATE
What you want can be done easily with DataKeyNames. Add it to the ListView as a property.
<asp:ListView ID="ListView1" runat="server" DataKeyNames="IDColumn">
Then when the checkbox is changed read the correct key
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
ListView1.DataSource = Common.fillBooks();
ListView1.DataBind();
}
}
protected void Approve_Click(object sender, EventArgs e)
{
//cast the sender back to the checkbox
CheckBox cb = sender as CheckBox;
if (cb.Checked)
{
//get the parent of the parent (itemtemplate > listiew)
ListView lv = cb.Parent.Parent as ListView;
//get the dataitem from the namingcontainer
ListViewDataItem item = cb.NamingContainer as ListViewDataItem;
//get the correct datakey with the index of the dataitem
int ID = Convert.ToInt32(lv.DataKeys[item.DataItemIndex].Values[0]);
//update database here with the ID
}
}
ListView
<asp:ListView ID="ListView1" runat="server" DataKeyNames="id" ItemType="Namespace.Class">
<ItemTemplate>
<div class="table-responsive">
<table class="table">
<tr>
<td>
<asp:CheckBox ID="cbApproved" runat="server" AutoPostBack="true" OnCheckedChanged="Approve_Click" />
</td>
</tr>
</table>
</div>
</ItemTemplate>
</asp:ListView>
This is what is currently working for me. Too long to add in comment or clutter original post:
ASPX:
<ItemTemplate>
<tr>
<td><asp:Label ID="UserNameLabel" runat="server" Text='<%#Eval("UserName") %>' /></td>
<td> <asp:CheckBox ID="Approved" runat="server" AutoPostBack="true" OnCheckedChanged="Approve_Click" /> </td>
</tr>
</ItemTemplate>
Changed the ItemTemplate to use asp Label controls so I could reference them in the code behind:
protected void Approve_Click(object sender, EventArgs e)
{
foreach (ListViewItem item in listUsers.Items)
{
if ((item.FindControl("Approved") as CheckBox).Checked == true)
{
Label myLabel = (Label)item.FindControl("UserNameLabel");
try
{
IQueryable<SUR> user = null;
user = db.SURs.Where(m => !m.IsApproved && m.UserName == myLabel.Text);
if(user != null)
{
db.sp_SUA(user.FirstOrDefault().ID, SessionMgr.CurrentUserID.ToString(), "Manual");
db.SaveChanges();
}
Response.Redirect(Request.RawUrl);
}
catch(Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
}
}
}
Once getting the control that had the username, I check if the DB has a row with the same value
If so, use a stored procedure to update the DB
EDIT:
After refactoring, I was wondering if it would be more efficient to get rid of the foreach loop, and instead use the OnItemCommand property of ListView and set the OnCheckedChanged for the Checkbox to point to the ItemCommand method? My thinking is since I am not looping through each item, would having the array index be better in terms of Big O?
Code would be:
protected void listSTUFF_ItemCommand(object sender, ListViewCommandEventArgs e)
if (int.TryParse(list.DataKeys[e.Item.DisplayIndex].Value.ToString(), out id)) {
var myQuery = db.Table.Where(a=>a.ID == id).FirstOrDefault();
db.StoredProcedure(myQuery.ID)
db.SaveChanges();

Once clicking the select button of a row, a gridview appears between that row and the rest of the gridview. Possible?

I'd like to have the user click the select button of, lets say, the 250th row of a 400 row gridview. When they click that, then another gridview that's 3x12 appears below that row, then the 150 other rows appear below that. Is this at all possible? I guess I could create a whole other div that'll have three gridviews that output depending on being <= and > the index of the selected row.
It starts as:
Gridview rows 1-400
Then after row 350 is selected is it:
Gridview rows 1-350
Gridview of row 350 info
Gridview rows 351-400.
It's definitely possible, but I would use a ListView or DataList as your parent container instead, because with a GridView, you'll have to put the child list in a column, which will look ugly. This should put you on the right path:
<asp:ListView ID="lstOuterList" runat="server" DataKeyNames="ID, OtherColumn">
<LayoutTemplate>
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><asp:LinkButton ID="LinkButton1" runat="server" Text="Expand" OnCommand="LinkButton1_Command" CommandArgument='<%#Container.DisplayItemIndex%>'></asp:LinkButton></td>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
<asp:PlaceHolder ID="plcInnerList" runat="server">
<asp:ListView ID="lstInnerList" runat="server" Width="100%">
<LayoutTemplate>
<tr>
<td colspan="4">
<div style="padding:20px;background-color:#fffeee;">
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</div>
</td>
</tr>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
</ItemTemplate>
</asp:ListView>
</asp:PlaceHolder>
</ItemTemplate>
</asp:ListView>
And when the user clicks the LinkButton/Button in DataList1, do something like this:
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
//pass index of item in command argument
var itemIndex = Convert.ToInt32(e.CommandArgument);
//find the pnlChildView control
var innerPlaceHolder = lstOuterList.Items[itemIndex].FindControl("plcInnerList") as PlaceHolder;
if (innerPlaceHolder != null)
{
innerPlaceHolder.Visible = !innerPlaceHolder.Visible;
if (innerPlaceholder.Visible)
{
var innerList = innerPlaceHolder.FindControl("lstInnerList") as ListView;
if (innerList != null)
{
//the id to retrieve data for the inner list
int keyValue = (int)lstOuterList.DataKeys[itemIndex]["ID"];
//bind the list using DataList1 data key value
innerList.DataSource = new DataTable("DataSource"); //your datasource
innerList.DataBind();
}
}
}
}
one way is:
on the rowcommand of the main grid:
create c# code for the grid will be inside GridView grd = new GridView();
bind this instance like any other grid
add on the controls from the main grid current line, should be something like
e.Cells[0].Controls.Add(grd);
I don't have VS here right now but I guess you could get the idea, I use this approach all the time

UpdatePanel or RadAjaxPanel in RadGrid EditForm template not working

I have a RadGrid in which I'm using an EditForm FormTemplate.
Inside of this there's a list (RadComboBox) with some companies. When a user selects one of these companies, it should fill another RadComboBox with a list of all locations.
At first I tried this using an UpdatePanel, then a RadAjaxPanel. Neither work.
This is a stripped down version:
<FormTemplate>
<table>
<telerik:RadAjaxPanel runat="server">
<tr>
<td>
Company
</td>
<td>
<telerik:RadComboBox ID="rcbCompany" runat="server" Width="250px" ValidationGroup="NewResource"
DataTextField="C_Name" DataValueField="Bedrijf_ID" AppendDataBoundItems="true"
OnSelectedIndexChanged="rcbCompany_OnSelectedIndexChanged">
</telerik:RadComboBox>
</td>
</tr>
<tr>
<td>
Locatie
</td>
<td>
<telerik:RadComboBox ID="rcbLocation" runat="server" Width="250px" ValidationGroup="NewResource"
DataTextField="location" DataValueField="Location_ID" AppendDataBoundItems="true" />
</td>
</tr>
</telerik:RadAjaxPanel>
</table>
</FormTemplate>
How can you make this work? If it's impossible, please give alternative approaches that don't require much work.
You can do it using ItemDataBound event on grid, i have shown the example to bind country drpdown:
protected void gridLocation_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item.IsInEditMode)
{
GridEditableItem item = (GridEditableItem)e.Item;
if (!(e.Item is IGridEditableColumn))
{
RadComboBox combo = (RadComboBox)item.FindControl("dropdwnCountry");
LoadCountries(combo);
}
}
}
protected void LoadCountries(RadComboBox combo)
{
//your defn goes here
}
And to cascade drop down you can take the onchange event event of country like:
protected void country_selected(object sender, RadComboBoxSelectedIndexChangedEventArgs e)
{
RadComboBox combo = (RadComboBox)sender;
GridEditableItem edit = (sender as RadComboBox).NamingContainer as GridEditableItem;
RadComboBox combos = (RadComboBox)edit.FindControl("dropdwnState");
LoadStates(combos, combo.SelectedValue);
}
protected void LoadStates(RadComboBox combo,string countryId)
{
//your defn goes here
}
Hope this helps.

How do I switch visibility of a control in a repeater?

I have a shopping cart that I am developing as a web user control. ucCart.ascx will appear on three different pages and I want the functionality of the cart to alter depending on which page it appears on. When the customer is confirming their order for example, I do not want to the delete cart item buttons or the recalculate cart button to be visible.
Can this be done programmatically in code behind? I'd rather not use JavaScript. I naively tried to use cartDelete.Visible = false; but that's not liked at all!
You need to get a reference to those controls and call set Visible property to false; something like this pseudo code;
ShoppingCartControlVariable.FinControl("idOfTheControlYouWantToHide").Visible=false;
See this documentation
Adding sample code to demonstrate how this is done:
Assuming you have a repeater like this (notice the OnItemCreated handler):
<asp:Repeater ID="myrepeater" runat="server" OnItemCreated="myrepeater_ItemCreated">
<HeaderTemplate>
<table>
<thead>
<th>
Link
</th>
<th>
Button
</th>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:HyperLink ID="link" runat="server" Text='<%#Eval("Text")%>' NavigateUrl='<%#Eval("Url")%>'></asp:HyperLink>
</td>
<td>
<asp:Button ID="btnDelete" runat="server" Text="Delete" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody> </table>
</FooterTemplate>
</asp:Repeater>
You can hide/show elements in the repeater rows as follows:
protected void myrepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item && (boolean_condition_that_on_which_you_will_decide_what_to_show_and_what_to_hide))
{
e.Item.FindControl("link").Visible = false;
}
}
For example, if I want to hide all link elements on every row and just leave the delete buttons, I can do this:
protected void myrepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType==ListItemType.AlternatingItem)
{
e.Item.FindControl("btnDelete").Visible = false;
}
}
And it will produce this:
For reference, the code that I used to populate my repeater was this:
List<CartItem> items = new List<CartItem>();
for (int i = 0; i < 10; i++)
{
CartItem t = new CartItem();
t.Text="Item " +i;
t.Url="http://www."+i+".com";
items.Add(t);
}
myrepeater.DataSource = items;
myrepeater.DataBind();
I think you can make a public function inside this user control named "hide controls" and call this function in the page you want and this function hide the controls or you can make a boolean property in the user control and the page can set it to false and then you can use this flag to hide the controls inside your usercontrol.

Categories