Repeater Button CommandArgument is Empty String - asp.net

Losing my mind with this one. My button gets a commandargument of empty string even though the commandargument gets set. I have verified it gets set to the correct ID in debug mode, but then when I go to access this commandargument later in the repeaters ItemCommand event the commandarguments are empty string. And I have no idea why. I end up getting a sq foreign key exception because it is inserting an ID of 0 from the empty string values. There is no other code regarding the repeaters buttons that would be resetting it.
Repeater:
<asp:Repeater ID="repeaterAddresses" ViewStateMode="Enabled" DataSourceID="sqlFacilityAddresses" runat="server">
<ItemTemplate>
<Select:Address ID="AddressControl" runat="server" />
<asp:Button ID="btnMarkAsBilling" runat="server" EnableViewState="true" CommandName="Billing" Text="Mark as billing address" />
<asp:button ID="btnMarkAsPhysical" runat="server" EnableViewState="true" CommandName="Physical" Text="Mark as physical address" />
</ItemTemplate>
</asp:Repeater>
Code behind:
Protected Sub repeaterAddresses_ItemCreated(ByVal sender As Object, ByVal e As RepeaterItemEventArgs) Handles repeaterAddresses.ItemCreated
If Not IsNothing(DirectCast(e.Item.DataItem, DataRowView)) Then
If (e.Item.ItemType = ListItemType.Item) Or (e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim addressControl As Address = DirectCast(e.Item.FindControl("AddressControl"), Address)
addressControl.AddressID = CInt(DirectCast(e.Item.DataItem, DataRowView)("Address_ID").ToString())
Dim btnBilling As Button = DirectCast(e.Item.FindControl("btnMarkAsBilling"), Button)
btnBilling.CommandArgument = CInt(DirectCast(e.Item.DataItem, DataRowView)("Address_ID").ToString())
Dim btnPhysical As Button = DirectCast(e.Item.FindControl("btnMarkAsPhysical"), Button)
btnPhysical.CommandArgument = CInt(DirectCast(e.Item.DataItem, DataRowView)("Address_ID").ToString())
End If
End If
End Sub
Protected Sub repeaterAddress_ItemCommand(ByVal sender As Object, ByVal e As RepeaterCommandEventArgs) Handles repeaterAddresses.ItemCommand
Dim conn As New SqlConnection(ConfigurationManager.ConnectionStrings("Trustaff_ESig2").ConnectionString)
Dim button As Button = CType(e.CommandSource, Button)
Select Case e.CommandName
Case "Billing"
Dim cmdBillingAddress As New SqlCommand("[SP_Facility_UpdateBillingAddress]", conn)
With cmdBillingAddress
.CommandType = CommandType.StoredProcedure
.Parameters.Add(New SqlParameter("#Facility_ID", DbType.Int32)).Value = sqlFacilityAddresses.SelectParameters("Facility_ID").DefaultValue
.Parameters.Add(New SqlParameter("#BillingAddress_ID", DbType.Int32)).Value = e.CommandArgument
End With
conn.Open()
cmdBillingAddress.ExecuteNonQuery()
conn.Close()
Case "Physical"
Dim cmdPhysicalAddress As New SqlCommand("[SP_Facility_UpdatePhysicalAddress]", conn)
With cmdPhysicalAddress
.CommandType = CommandType.StoredProcedure
.Parameters.Add(New SqlParameter("#Facility_ID", DbType.Int32)).Value = sqlFacilityAddresses.SelectParameters("Facility_ID").DefaultValue
.Parameters.Add(New SqlParameter("#PhysicalAddress_ID", DbType.Int32)).Value = e.CommandArgument
End With
conn.Open()
cmdPhysicalAddress.ExecuteNonQuery()
conn.Close()
End Select
PopulateBillingPhysicalAddresses(sqlFacilityAddresses.SelectParameters("Facility_ID").DefaultValue)
End Sub

Try this:
<asp:Button ID="btnMarkAsBilling" runat="server" EnableViewState="true"
CommandName="Billing" Text="Mark as billing address"
CommandArgument='<%# Eval("Address_ID") %>'/>
Note the single quotes around the attribute value. ASP.NET will not execute the server side data binding code if they are double quotes. You'll need to remove the CommandArgument assignments from your code behind.
Address_ID will need to be a property on the object you are databinding to the repeater.

Related

Edit Gridview update issue

I have got a gridview which when you press select on a row it transfers you to another gridview page,
which displays more columns from that table to give more detail about that row.
I know how to do this using:
<asp:HyperLinkField DataNavigateUrlFields="MISAppID" DataNavigateUrlFormatString="ApplicationsDetails.aspx?MISAppID={0}" Text="Select" />
In the 1st Gridview then using a Stored-procedure on the second page it displays the correct row using the ID field.
In my current site on the second page, I have added an edit button that does edit the row correctly in my database but on completion, it breaks the site and I can't work out how to get it to just refresh the gridview
This is the error I get:
Exception Details: System.NotSupportedException: Updating is not
supported by data source 'SqlDataSource1' unless UpdateCommand is
specified.
Is it the case that my BindGrid is missing something or is the way I am using my Stored-procedure?
Here is my VB code:
Public Sub BindGrid() Handles SqlDataSource1.Selecting
End Sub
Protected Sub OnRowEditing(sender As Object, e As GridViewEditEventArgs)
GridView1.EditIndex = e.NewEditIndex
Me.BindGrid()
End Sub
Protected Sub OnRowUpdating(sender As Object, e As GridViewUpdateEventArgs)
Dim row As GridViewRow = GridView1.Rows(e.RowIndex)
Dim misappId As Integer = Convert.ToInt32(GridView1.DataKeys(e.RowIndex).Values(0))
Dim application As String = TryCast(row.Cells(2).Controls(0), TextBox).Text
Dim url As String = TryCast(row.Cells(3).Controls(0), TextBox).Text
Dim access_group As String = TryCast(row.Cells(4).Controls(0), TextBox).Text
Dim creator_ein As String = TryCast(row.Cells(5).Controls(0), TextBox).Text
Dim data_location As String = TryCast(row.Cells(6).Controls(0), TextBox).Text
Dim purpose As String = TryCast(row.Cells(7).Controls(0), TextBox).Text
Dim active As String = TryCast(row.Cells(8).Controls(0), TextBox).Text
Dim business_owner As String = TryCast(row.Cells(9).Controls(0), TextBox).Text
Dim area As String = TryCast(row.Cells(10).Controls(0), TextBox).Text
Dim constr As String = ConfigurationManager.ConnectionStrings("myLocalConnectionString").ConnectionString
Using con As New SqlConnection(constr)
Using cmd As New SqlCommand("UPDATE tbl_AutomationCompassApplications SET Application = #Application, URL = #URL, Access_Group = #Access_Group, Creator_EIN = #Creator_EIN, Data_location = #Data_location, Purpose = #Purpose, Active = #Active, Business_Owner = #Business_Owner, Area = #Area WHERE MISAppID = #MISAppID")
cmd.Parameters.AddWithValue("#MISAppID", misappId)
cmd.Parameters.AddWithValue("#Application", application)
cmd.Parameters.AddWithValue("#URL", url)
cmd.Parameters.AddWithValue("#Access_Group", access_group)
cmd.Parameters.AddWithValue("#Creator_EIN", creator_ein)
cmd.Parameters.AddWithValue("#Data_location", data_location)
cmd.Parameters.AddWithValue("#Purpose", purpose)
cmd.Parameters.AddWithValue("#Active", active)
cmd.Parameters.AddWithValue("#Business_Owner", business_owner)
cmd.Parameters.AddWithValue("#Area", area)
cmd.Connection = con
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
GridView1.EditIndex = -1
Me.BindGrid()
End Sub
Ok, say we have a list of hotels - we want to display them, and then click on a row to eit.
(and you writing WAY too much code here).
So, lets say we drop in a gridview. Use the connection wizard - let it generate the markup.
THEN REMOVE the data source on the page, remove the datasource property of the gridview.
So, in less time then it takes me to write above? We have this markup:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="Edit"
PK = '<%# Container.DataItemIndex %>' OnClick="cmdView_Click" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
</Columns>
</asp:GridView>
Note the cool trick I used to get the PK row index.
When you are looking at the grid, you can't double click on the button to wire up a event (code behind), but you CAN DO THIS!!!!
Note VERY care full in above - I typed in OnClick "=", when you HIT "=", then NOTE the inteli-sense that popped up - the create NEW event is what we need. Click on create new event - NOTHING seems to happen, but if we NOW go to code behind, we have a code stub for the button!!!
And note how I needed/wanted the PK row value - so I just shoved in and created my OWN custom attribute for that button. ("PK").
Ok, so our code to load up the grid is now this - and I included the button click code:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
LoadGrid()
End If
End Sub
Sub LoadGrid()
Dim strSQL As String
strSQL = "SELECT * from tblHotels Order by HotelName"
Using cmdSQL As New SqlCommand(strSQL, New SqlConnection(My.Settings.TEST3))
cmdSQL.Connection.Open()
Dim MyTable As New DataTable
MyTable.Load(cmdSQL.ExecuteReader)
GridView1.DataSource = MyTable
GridView1.DataBind()
Session("MyTable") = MyTable
End Using
End Sub
Protected Sub cmdView_Click(sender As Object, e As EventArgs)
Dim MyBtn As Button = sender
Session("RowID") = MyBtn.Attributes.Item("PK")
Response.Redirect("~/EditHotel.aspx")
End Sub
Look how clean and simple the above is!!! I find this as easy say as MS-Access coding!!!
Ok, so the grid now looks like this:
Note the button click code.
So, our markup is this for the new page (to edit hte ONE row).
<div style="float:left;width:20%">
<div style="text-align:right">
First Name :<asp:TextBox ID="txtFirstname" runat="server" Width="150"></asp:TextBox> <br />
Last Name :<asp:TextBox ID="txtLastname" runat="server" Width="150"></asp:TextBox> <br />
Hotel Name :<asp:TextBox ID="txtHotel" runat="server" Width="150"></asp:TextBox> <br />
City :<asp:TextBox ID="txtCity" runat="server" Width="150"></asp:TextBox> <br />
Active :<asp:CheckBox ID="Active" runat="server" Width="150"></asp:CheckBox>
</div>
</div>
<div style="clear:both">
<br />
<asp:Button ID="cmdSave" runat="server" Text ="Save " />
<asp:Button ID="cmdCancel" runat="server" Text="Cancel" Style="margin-left:20px" />
</div>
</form>
and it looks like this:
and the load code and save button code for this page?
This:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
LoadInfo()
End If
End Sub
Sub LoadInfo()
Dim MyTable As DataTable = Session("MyTable")
Dim MyRow As DataRow = MyTable.Rows(Session("RowID"))
txtFirstname.Text = MyRow("FirstName")
txtLastname.Text = MyRow("LastName")
txtCity.Text = MyRow("City")
txtHotel.Text = MyRow("HotelName")
Active.Checked = MyRow("Active")
End Sub
Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
Dim MyTable As DataTable = Session("MyTable")
Dim MyRow As DataRow = MyTable.Rows(Session("RowID"))
MyRow("FirstName") = txtFirstname.Text
MyRow("LastName") = txtLastname.Text
MyRow("City") = txtCity.Text
MyRow("HotelName") = txtHotel.Text
MyRow("Active") = Active.Checked
Using cmdSQL As New SqlCommand("SELECT * from tblHotels where ID = 0",
New SqlConnection(My.Settings.TEST3))
Dim da As New SqlDataAdapter(cmdSQL)
Dim cmdUpdate As New SqlCommandBuilder(da)
da.Update(MyTable)
End Using
Response.Redirect("~/MyTours.aspx")
End Sub
Again, look how easy, clean and readable the code is.
Study the above example - you see that you don't need all that parameters code, and you see how little code is in fact required to select a row - jump to page to edit, and then you hit save - update the data and jump back to the grid row page.

Find the right value of textbox

I have a problem with inserting data inserting data into database.
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1" OnItemDataBound="Repeater1_ItemDataBound">
<ItemTemplate>
<!-- Some other data (text...) -->
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Eval("PostId") %>' />
<asp:TextBox ID="txtAddComment" runat="server" CssClass="textbox" Width="200px" />
<asp:Button ID="btnAddComment" runat="server" CssClass="button" Text="Comment" CausesValidation="false" OnClick="btnAddComment_Click"/>
</ItemTemplate>
</asp:Repeater>
Code behind:
Protected Sub btnAddComment_Click(sender As Object, e As EventArgs)
Dim HiddenField1 As HiddenField = DirectCast(Repeater1.Items(0).FindControl("HiddenField1"), HiddenField)
Dim txtAddComment As TextBox = DirectCast(Repeater1.Items(0).FindControl("txtAddComment"), TextBox)
Dim conn As New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString.ToString)
Try
If txtAddComment.Text = "" Then
Exit Sub
Else
conn.Open()
Dim cmd As SqlCommand = conn.CreateCommand()
cmd.CommandText = "INSERT INTO Comments (PostId, UserName, CommentText) VALUES (#PostId, #UserName, #Text)"
cmd.Parameters.Add("PostId", System.Data.SqlDbType.Int).Value = CInt(HiddenField1.Value)
cmd.Parameters.Add("UserName", System.Data.SqlDbType.NVarChar).Value = Context.User.Identity.Name
cmd.Parameters.Add("Text", System.Data.SqlDbType.NText).Value = MakeLink(HtmlRemoval.StripTagsCharArray(txtAddComment.Text))
cmd.ExecuteNonQuery()
End If
Catch ex As SqlException
Finally
conn.Close()
End Try
End Sub
I display some text, under the text there is textbox and button for comments. I am bounding textId in hiddenfield for inserting comments. The code works fine, but I can only add comment for the first row in database displayed by repeater. When I want to add comment for other rows (2, 3...), the page refreshes and the text in the TextBox stay there.
It is problem with this line of code:
Dim txtAddComment As TextBox = DirectCast(Repeater1.Items(0).FindControl("txtAddComment"), TextBox)
The ID from HiddenField is right. But the code doesn't perform because the line above references for the first textbox on the page and his value is null.
When I change the line of code like this:
Dim txtAddComment As TextBox = DirectCast(Repeater1.FindControl("txtAddComment"), TextBox)
It returns an error that Object reference not set to an instance of an object.
How to get the right textbox with right value?
Thanks for the answer
cast the sender to a button that sent it, then get the textbox from the parent. Example:
Protected Sub button_click(ByVal sender As Object, ByVal e As EventArgs)
Dim myButton As button= CType(sender, button)
Dim myTextBox as TextBox = CType(myButton Parent.FindControl("buttonName"), TextBox)
end sub

Checkbox update in GridView

When people search on my website using a GridView I would like to have a checkbox column that they click on which will change the value in a column called STATUS to U. I'm having a heck of a time finding code that works so I was hoping you guys could help. I'm a COMPLETE NOOB so please be descriptive if you know the answer.
Code for Checkbox button - Currently when I search it comes back saying that it cannot convert string to boolean.
<asp:TemplateField HeaderText="Successful Contact?">
<EditItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" checked='<%#Bind("status")%>' AutoPostBack="true" />
</EditItemTemplate>
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" checked='<%#Bind("status")%>'
Enabled="False" /></ItemTemplate>
</asp:TemplateField>
This is the vb code
Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs)
For Each GridViewRow In GridView1.Rows
Dim row As GridViewRow = GridView1.Rows(e.RowIndex)
Dim value As Boolean
value = DirectCast(GridView1.Rows(e.RowIndex).Cells(0).FindControl("CheckBox1"), CheckBox).Checked
Dim connectionString As String = ConfigurationManager.ConnectionStrings("Data Source=server;Initial Catalog=i3FCC01;Integrated Security=True;").ConnectionString
Dim com_sql As New SqlClient.SqlCommand
Dim insertSql As String
insertSql = "Update CallQueueFCC Set Status='U' where Id = #id"
Using myConnection As New SqlConnection(connectionString)
myConnection.Open()
Dim myCommand As New SqlCommand(insertSql, myConnection)
myCommand.Parameters.AddWithValue("#status", value)
myCommand.ExecuteNonQuery()
myConnection.Close()
End Using
Next
GridView1.EditIndex = -1
DataBind()
End Sub
You are binding Status value for check box checked attribute which takes Boolean value.
But status has string value as you are binding string to Boolean it is throwing error.
Like Kiran mentioned earlier, status has a string value so you need to do some firefighting in the row databound event.
Markup
<asp:TemplateField HeaderText="Successful Contact?">
<EditItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="true" />
</EditItemTemplate>
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server"
Enabled="False" /></ItemTemplate>
</asp:TemplateField>
Code behind
Protected Sub GridView1_RowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
'Evaluate the state of the check box, true when status =U , and false otherwise
Dim itemstatus As Boolean=If(DataBinder.Eval(e.Row.DataItem, "Status"), True, False)
Dim CheckBoxItemTemp As CheckBox=CType(e.Row.FindControl("CheckBox1"), CheckBox)
CheckBoxItemTemp.Checked=itemstatus
End if
If e.Row.RowState & DataControlRowState.Edit Then
'same as above but now for edit item template
Dim editstatus As Boolean=If(DataBinder.Eval(e.Row.DataItem, "Status"), True, False)
Dim CheckBoxEditTemp As CheckBox=CType(e.Row.FindControl("CheckBox1"), CheckBox)
CheckBoxEditTemp.Checked=editstatus
End if
End Sub

Adding DataBound DropDownList to DataGrid

I have a DataGrid bound to a DataView which, among other columns has, an ID Column and ParentID Column, I need the user to be able to specify a ParentID using using a DropDownList (ComboBox).
Now, I have already added the DropDownList to the DataGrid like this:
<Columns>
[...]
<asp:TemplateColumn HeaderText="Parent" >
<ItemTemplate>
<asp:DropDownList ID="ddlParentID"
runat="server"
DataValueField="ID"
DataTextField="Short_Description"
Width="100%"
DataSource="<%# dsDV %> ">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
In the code-behind I have the following a method:
Protected dsDV As New DataView
Protected Sub PopulateDropDownList()
Dim conn As SqlClient.SqlConnection = New SqlClient.SqlConnection(myConnString)
Dim comm As SqlClient.SqlCommand = New SqlClient.SqlCommand("SELECT * FROM myTable", conn)
comm.CommandType = CommandType.Text
Dim myTableTable As New DataTable
conn.Open()
myTableTable.Load(comm.ExecuteReader)
Me.dsDV = myTableTable.DefaultView
End Sub
That PopulateDropDownMethod is called on the form Load Event but, albeit DDLs do show, they show empty, as if no DataBinding is being made.
How can I properly bind the DDL with a dataSource in the codebehind? Or, if that's not the issue, how do I properly fill the DDL?
Update 1
After the first answer I went ahead and tried this (still no luck):
Protected Sub dg_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles dgData.ItemDataBound
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Dim ddl As DropDownList = CType(e.Item.Cells(3).FindControl("ddlParentID"), DropDownList)
Me.PopulateDropDownList(ddl)
End If
End Sub
Protected dsDV As New DataView
Protected Sub PopulateDropDownList(ddl As DropDownList)
Dim conn As SqlClient.SqlConnection = New SqlClient.SqlConnection(myConnString)
Dim comm As SqlClient.SqlCommand = New SqlClient.SqlCommand("SELECT * FROM myTable", conn)
comm.CommandType = CommandType.Text
Dim myTableTable As New DataTable
conn.Open()
myTableTable.Load(comm.ExecuteReader)
ddl.DataSource = myTableTable.DefaultView
ddl.DataBind()
End Sub
Note that I also removed the call to PopulateDropDownList from the Form Load Event handler.
you may try to call ddlParent.DataBind() after setting the datasource.
I don't why but taking the binding code from the aspx to the aspx.vb fixed the issue, so it all looks like this now:
<asp:TemplateColumn HeaderText="Parent" >
<ItemTemplate>
<asp:DropDownList ID="ddlParentID" runat="server" Width="100%" >
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateColumn>
And for the code-behind, for each row:
Dim ddl As DropDownList = CType(e.Item.Cells(3).FindControl("ddlParentID"), DropDownList)
ddl.DataValueField = "ID"
ddl.DataTextField = "Short_Description"
ddl.DataSource = myTable.DefaultView
ddl.DataBind()

ASP.NET: Bind HyperLinkColumn to more than one field

Using ASP.NET and the DataGrid, how do I bind a HyperLinkColumn to more than one field?
Dim detail As New HyperLinkColumn
With detail
.Text = "View Details"
.HeaderText = ""
.NavigateUrl = "\TeamDetail.aspx?Account={0}&Broker={1}"
.DataNavigateUrlField = "AccountKey, BrokerNumberKey"
End With
I was hoping for an data-binding event on HyperLinkColumn but no such luck.
You need to use a TemplateColumn. This will give you named controls you can work with in the ItemDataBound event.
ASP
<asp:TemplateColumn>
<ItemTemplate>
<asp:HyperLink runat="server" ID="LinkColumn" NavigateUrl="" Text="View Details"></asp:HyperLink>
</ItemTemplate>
</asp:TemplateColumn>
VB
Private Sub ReportGrid_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles ReportGrid.ItemDataBound
Const target = "/TeamsDetail.aspx?Account={0}&Broker={1) Select Case e.Item.ItemType
Case ListItemType.Item, ListItemType.AlternatingItem
Dim ctrl = CType(e.Item.FindControl("LinkColumn"), HyperLink)
Dim row = CType(e.Item.DataItem, DataRowView)
If ctrl IsNot Nothing Then
Dim accountKey = CInt(row("PrincipalAccountKey"))
Dim brokerNumberKey = CInt(row("BrokerNumberKey"))
ctrl.NavigateUrl = String.Format(target, accountKey, brokerNumberKey)
End If
End Select
End Sub

Resources