Update SQL from Checkbox in ListView - c#

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();

Related

Get repeater row data through checkbox

I have a repeater control and a check box on each row. On the checkbox click event I wanted to obtain the data items for this row. I have tried the following but the data items within Repeater Item is always empty.
protected void CheckChanged(object sender, EventArgs e)
{
string county = string.Empty;
string country = string.Empty;
string postcode = string.Empty;
string posttown = string.Empty;
var item = ((CheckBox) sender).Parent as RepeaterItem;
if (item != null)
{
if (item.ItemType == ListItemType.Item)
{
System.Data.DataRowView drv = (System.Data.DataRowView)(item.DataItem);
county = drv.Row["county"].ToString();
country = drv.Row["country"].ToString();
postcode = drv.Row["postcode"].ToString();
posttown = drv.Row["posttown"].ToString();
}
}
}
<asp:Repeater ID="Repeater1" runat="server">
<HeaderTemplate>
<table border="1" width="100%" >
<tr>
<th>Select</th>
<th>Country</th>
<th>County</th>
<th>CSS Database Code</th>
<th>Postcode</th>
<th>Town</th>
</tr>
</HeaderTemplate>
<Itemtemplate>
<tr>
<td><asp:CheckBox ID="selectAddress" runat="server" OnCheckedChanged="CheckChanged" AutoPostBack="true"/></td>
<td><%# Eval("county")%>
<td><%# Eval("country")%></td>
<td><%# Eval("cssDatabaseCode")%></td>
<td><%# Eval("postcode")%><br /></td>
<td><%# Eval("postTown")%><br /></td>
</tr>
</Itemtemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
try this:
If CheckBox is Inside Repeater Then
var chk = (CheckBox)sender;
var item = (RepeaterItem)chk.NamingContainer;
if (item.ItemType == ListItemType.Item)
{
//find your items here
}
Here You can get the RepeaterItem by casting the CheckBox's NamingContainer. Then you can use FindControl to get the reference to your other Controls Inside Repeater

accessing objects in listview after buttonclick in listviewitem

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;
}
}

How to get Value from DropDownList inside a ListView?

I have a DropDownList inside in ListView..
I wanted to get a data when command clicked.
this is my code..
protected void ListView2_ItemCommand(object sender, ListViewCommandEventArgs e){
string shipmethod = ((DropDownList)e.Item.FindControl("ShippingComapnyDDL")).SelectedValue;
}
but it always return null value..
I've googling about 3 hours, and try many function..
but still cant solve this bug..
please help me guys,
UPDATE
here's my aspx page
<asp:DropDownList ID="ShippingComapnyDDL" runat="server" SelectedValue='<%# Eval("ShippingCompany") %>'>
<asp:ListItem Text="" Value=""></asp:ListItem>
<asp:ListItem Text="FedEx" Value="FedEx"></asp:ListItem>
<asp:ListItem Text="UPS" Value="UPS"></asp:ListItem>
<asp:ListItem Text="Other" Value="Other"></asp:ListItem>
</asp:DropDownList>
DO you have headers set?try
if(e.Item.ItemIndex!=-1)
{
string shipmethod = ((DropDownList)e.Item.FindControl("ShippingComapnyDDL")).SelectedValue;
}
if not working then try
string shipmethod = (e.Item.FindControl("ShippingComapnyDDL") as DropDownList).SelectedValue;
Please try
<%#DataBinder.Eval(Container.DataItem,"ShippingCompany")%>
instead of
<%#Eval("ShippingCompany")%>
For more details:
http://aspadvice.com/blogs/joteke/archive/2008/08/24/Is-_2200_Databinding-methods-such-as-Eval_280029002C00_-XPath_280029002C00_-and-Bind_28002900_-can-only-be-used-in-the-context-of-a-databound-control_2E002200_-causing-you-grief_3F00_.aspx
try this:
DropDownList ddl = (DropDownList)e.Item.FindControl("ShippingComapnyDDL");
if (ddl != null)
{
//code here
}
<asp:ListView ID="lvwCoreConfigureData" runat="server" DataKeyNames="Course_Config_Id" OnItemCommand="lvwCore_Config_ItemCommand" OnItemDataBound="lvwCore_Config_ItemDataBound">
<LayoutTemplate>
<table class="table mobile-stacked mb-0">
<thead>
<tr role="row">
<th style="width: 240px">
<asp:Label runat="server" Text="<%$Lang:Resource.Core_Config_Course %>"></asp:Label>
</th>
</tr>
</thead>
<tbody>
<tr runat="server" id="itemPlaceholder" />
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr role="row">
<td data-th="Name">
<asp:DropDownList ID="ConfigCourseName" runat="server" AutoPostBack="true" CssClass="form-control" OnSelectedIndexChanged="ConfigCourseName_SelectedIndexChanged"></asp:DropDownList>
</td>
</tr>
</ItemTemplate>
</asp:ListView>
2 . This methos will be provide data binding to dropdown while edit mode
protected void lvwCore_Config_ItemDataBound(Object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
ListViewDataItem dataItem = (ListViewDataItem)e.Item; // load one row item
var CourseId = ((Edulearn.Model.CoreProgramme.CoreProgrammeConfigrationDM)dataItem.DataItem).CourseId; //
DropDownList ConfigCourseName = (e.Item.FindControl("ConfigCourseName") as DropDownList);
ConfigCourseName.DataSource = CoreProgrammeRepository.GetCoreProgrammeCourseList(TimeZoneId, new { Name = "TEST" }); // Get the data to dropdown (all data)
ConfigCourseName.DataTextField = "Name"; // assign here which one need to display
ConfigCourseName.DataValueField = "CourseId"; // assign here which one is the value for database save
ConfigCourseName.DataBind(); // bind the data
ConfigCourseName.SelectedValue = CourseId.ToString(); // Here selected values from database will be added
ConfigCourseName.Items.Insert(0, new ListItem("Please select")); // Default value only for display
}
}

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