Retrieving Row Values From Dropdown list and BoundColumn in DataGrid (2 Viewers)

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
In asp.net 1.1...

I have a datagrid bound ti a database table.

Column(0) is a boundColum bound to Field1
Column(1) is a templateColumn which has a dropdownBox which is bound to Field2.

When I select a different value in the Dropdown I want it's 'OnSelectedIndexChanged' to trigger a function that gets the value of Field1 and the SelectedItem in the Dropdown on that slected row in the datagrid.

I need a function that captures these values but am having problems referencing them.

Many Thanks
 

dan-cat

Registered User.
Local time
Today, 22:13
Joined
Jun 2, 2002
Messages
3,433
First of all you need to call a routine from your dropdown list. Within your HTML have something like:

Code:
<asp:DropDownList id="myDrop" runat"server" OnSelectedIndexChanged="myDropChanged" AutoPostBack="True" />

Now in your code-behind file create a new routine called myDropChanged. Something like this in vb.net

Code:
Sub myDropChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) 

Dim d as DropDownList = sender, c as TableCell, item as DataGridItem
Dim val1 as string, val2 as string

c = d.Parent
item = c.Parent
val1 = item.Cells(0).Text
val2 = d.SelectedValue
End Sub

Thus d is your dropdownlist
c is the table cell (the parent control) in which your dropdown is contained
item is the parent control of c which is the datagrid item containing your dropdownlist. From there you can grab your values
 

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
Dan-Cat

Many thanks for your help.

Problem now is that I don't think the 'OnSelectedIndexChanged' on the ddl is kicking in. I have put a simple 'Response.Write in teh function but nothing is being displayed

I assume it triggers as soon as you select a different value in the ddl (which is what I want to happen?

Here is my ddl...

<asp: DropDownList ID="cboPriority"
OnSelectedIndexChanged="cboPriority_Update"
AutoPostBack="True"
DataValueField="Priority"
SelectedIndex='<%# DataBinder.Eval(Container.DataItem, "Priority") %>'
runat="server">
<asp:ListItem Value="0" />
<asp:ListItem Value="1" />
<asp:ListItem Value="2" />
<asp:ListItem Value="3" />
<asp:ListItem Value="4" />
<asp:ListItem Value="5" />
<asp:ListItem Value="6" />
<asp:ListItem Value="7" />
<asp:ListItem Value="8" />
</asp: DropDownList>

I think the problem lies in the fact that the ddl selected index value is bound to a field?
Many Thanks
 
Last edited:

dan-cat

Registered User.
Local time
Today, 22:13
Joined
Jun 2, 2002
Messages
3,433
KevinM said:
I assume it triggers as soon as you select a different value in the ddl (which is what I want to happen?

Indeed it does but unfortunatuely you have the selectedindex hard-coded into your dropdownlist HTML. Thus the dropdownlist selectedindex will never change unless the 'Priority' data value changes. Thus the OnSelectedIndexChanged event will never fire.

Personally I never hard-code the DataValueField or SelectedIndex parameters.
To start with I'd remove the lines highlighted in red.
By the way your SelectedIndex coding suggests you're still thinking in asp. ie Embedding server side code in your html. I would recommend not going this route as it encourages spaghetti code.

Code:
<asp: DropDownList ID="cboPriority"
OnSelectedIndexChanged="cboPriority_Update"
AutoPostBack="True"
[COLOR="Red"]DataValueField="Priority"
SelectedIndex='<%# DataBinder.Eval(Container.DataItem, "Priority") %>'[/COLOR]
runat="server">
[COLOR="red"]<asp:ListItem Value="0" />
<asp:ListItem Value="1" />
<asp:ListItem Value="2" />
<asp:ListItem Value="3" />
<asp:ListItem Value="4" />
<asp:ListItem Value="5" />
<asp:ListItem Value="6" />
<asp:ListItem Value="7" />
<asp:ListItem Value="8" />[/COLOR]
</asp: DropDownList>

Now I'm assuming that you would like to have options 1-8 in your ddl but have the selected value as some value contained in the Priority field of some table. So first up I would create a sub-routine which would populate my ddl.

Something like this:

Code:
Private Sub populateMyDrop()
Dim strSQL as string, myConn as SqlClient.SqlConnection
Dim myComm as SqlClient.SqlCommand, myDataReader as SqlClient.SqlDataReader, strConn as string, intPriority as integer = 0
Dim i as integer, d as DropDownList, intCustId as integer

' declare your dropdownlist
d = me.cboPriority

' set an arbitary value for customer id - I've made this up for later
intCustId = Session("CustId")

' Add the options to the dropdownlist
' Add a blank value to start with

d.Items.Add(New ListItem(String.Empty,String.Empty))
' Now add 1-8 options
For i = 1 To 8
d.Items.Add(New ListItem(i,i))
Next

' Create a datareader to find your required value.
' I'm assuming sql server is being used and you know your 
' connection string properties

strSQL = "SELECT Priority FROM myTable" & _
" WHERE CustomerId = @intCustId"
myConn = New SqlClient.SqlConnection(strConn)
myComm = New SqlClient.SqlCommand(strSQL,myConn)
' Always use parameters if using SQL strings - SQL injection attacks are a pain in the ass.
myComm.Parameters.Add(New SqlClient.SqlParameter("@intCustId",intCustId))
myConn.Open()
myDataReader = myComm.ExecuteReader

' Set the dropdownlist selectedindex dependant on value retrieved
Select Case myDataReader.HasRows()
    Case False
    'no value found leave the ddl to default to zero index (blank value)
    Case True
    ' we've found a value but must make sure this value contained within ddl
    ' I'm assuming only one row will be returned ie. CustId is primary key
     Do While myDataReader.Read
      Select Case myDataReader.IsDbNull(0)
       Case True
        ' null value found - leavethe ddl to default to zero index
       Case False
       ' found a value - define intPriority variable
       intPriority = myDataReader.GetInt32(0)
     Loop

' close your datareader and connection
myDataReader.Close()
myConn.Close()

' Now to make sure we don't get an error when setting the selecedindex
' we place the code within a Try clause. This means if an error is raised ie hte intPriority variable is not contained within the dropdownlist we can catch it and do as we wish with it.

' First check if we found a Priority value at all
Select Case intPriority > 0
Case False
d.SelectedIndex = 0
Case True
Try
' attempt to set the selectedvalue
d.SelectedValue = intPriority
Catch ex as Exception
' For some reason we failed - we could do several things
' ie. If Throw an error then uncomment the line below
' Throw New Exception(ex.Message)
' Or just set the ddl to zero index
d.SelectedIndex = 0
End Try
End Sub

I've assumed lots of things here about your db structure etc but hopefully it will lead you to the thinking that if your are going to use server-side code then full control needs to be instantiated in the code-behind files. Try to use as litle embedded server-side code in your HTML as possible as you will lose control of how .net renders your HTML.
 

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
Dan

Many thanks for your very detialed reply and advice.

I'm falling at the first hurdle...

It 's not recognising the DDL in the datagrid....

On the line 'me.cboPriority' I get an error I get is ...

BC30456: 'cboPriority' is not a member of 'mypage.aspx'.

I think cos it's nested in a datagrid well as a form (?)

There was a similar problem I was having in the first place (before posting) which forced me into hardcoding the DDL rather than use a seperate routine to populate it as you have rightly suggested.

Basically I couldn't get 'FindControl' to work, which I think is what is still needed in the above routine .
(any ideas ?).

As you can tell i've only recently made the move from classic asp to asp.net and slowly getting used to the differences!
 

dan-cat

Registered User.
Local time
Today, 22:13
Joined
Jun 2, 2002
Messages
3,433
Yep, my mistake really 'cos my code assumed it was a standalone ddl not embedded in a datagrid.

Am I right in thinking that the Priority field is contained within the datasource of your datagrid? Get back to me and we can go from there.
 

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
dan-cat said:
Yep, my mistake really 'cos my code assumed it was a standalone ddl not embedded in a datagrid.

Am I right in thinking that the Priority field is contained within the datasource of your datagrid? Get back to me and we can go from there.

Yes it is, so I assume I can use the same dbConn/SQL string & therefore same DataReader for the datagrid and DDL, just close & re open the same DataReader for each?

I've actually changed your routine slightly to accomodate this.

I've not actually added a whole new sub for populating the DDL, i've just included it in the PageLoad event where the Datagrid gets bound.
I've simply tagged it on the end so I don't have to re-open the same datasource as mentioned above.
 

dan-cat

Registered User.
Local time
Today, 22:13
Joined
Jun 2, 2002
Messages
3,433
KevinM said:
Yes it is, so I assume I can use the same dbConn/SQL string & therefore same DataReader for the datagrid and DDL, just close & re open the same DataReader for each?

No! We can now do this with a different event. It is called the OnItemDataBound event. This event is triggered each and everytime a row of the datagrid is rendered. Within the html of your datagrid add the following pairing

Code:
OnItemDataBound="myDataGridDB"

Now within your code-behind file add a sub-routine like this.

Code:
 Sub myDataGridDB(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs)

Dim d as dropdownlist, intPriority as integer
Select CAse e.item.itemtype
 CAse ListItemType.AlternatingItem, ListItemType.Item
 d = e.item.findcontrol("cboPriority")
 intPriority = e.item.dataitem("Priority")
End Select


End Sub

Ok do you see where I am going with this?
Now the datagrid will call the routine myDataGridDB each time it renders a row. So first off you check that the row (item) is not a header or footer. Then you can find your ddl by using the e argument of the event and the findcontrol command. Again the Priority value can be found using similar method because that row is bound to the specific rowof your datasource.

You now have your ddl reference and your priority value. so you can populate that ddl as you like. Call the indexchanged routine I showed you earlier and you should be good to go.
 

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
Dan

Really appreciate your time & patience on this.

Implemented all your changes but now getting the following error on the DDL populate routine...

Compiler Error Message: BC30408: Method 'Private Sub cboPriority_Populate()' does not have the same signature as delegate 'Delegate Sub EventHandler(sender As Object, e As System.EventArgs)'.

I callt the above routine 'Private Sub cboPriority_Populate()' from the ddl as follows...

OnSelectedIndexChanged="cboPriority_Populate"
'cboPriority_Populate()' gives a 'paranthese not required' error !

I often get this with routines in asp.net!
I'm not asking for any arguments in the sub and not sending any arguments, so why is there a conflict?

I assume it's then caused by the OnItemDataBound function which starts...

Private Sub dg_ItemDataBound(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs)

Incidentally I already have a OnItemDataBound function which shows a 'Confirm msg' box when the delete button in the grid is clicked.

Anyway I've added the code to the OnItemDataBound as you suggested in your last post.
Can I populate the DDL (0 to 8) here or in the DDL populate routine as you first suggested?

Basically what I am trying to do here is diaplay a simple datagrid bound to a database.
The datagrid consists of the usual bound columns plus a delete button column which works fine plus a dropdown list of numbers (0-8) bound to the priority field and showing the current row value.

What I'm trying to achieve here is to allow the user to be able to quickly change the 'Priority' field value by means of the said DDL so as soon as they change to a different value it will update the underlying value in the table and then postback and display the updated datagrid

Incidentally my initial plan was to put in the above 'UPDATE routine' in the 'DDL on Change event' routine.

I'm ok with the 'UPDATE' routine, it's just referencing the DDL and getting the 'onChange' event to kick in (as you know!).


I used to be able to do this so easily in classic asp :(
 
Last edited:

dan-cat

Registered User.
Local time
Today, 22:13
Joined
Jun 2, 2002
Messages
3,433
KevinM said:
I used to be able to do this so easily in classic asp :(

Keep trying - once you've sussed out what's going on you'll never use asp again trust me.

ok - from the beginning.

1) remove all the code to do with the selectedindexchanged property of the ddl. This is both in the html and code-behind file. We're going to just master the population of the nested ddl first ok?

2) Get rid of the Private Sub cboPriority_Populate routine also

Now we're just interested in the onitemdatabound event. So within your databound routine have the following.

Code:
 Sub myDataGridDB(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs)
Dim d as dropdownlist, intPriority as integer
Select CAse e.item.itemtype
 CAse ListItemType.AlternatingItem, ListItemType.Item
 d = e.item.findcontrol("cboPriority")
 intPriority = e.item.dataitem("Priority")

populatemyddl(d,intPriority)
End Select

End Sub

Now create a new sub-routine like this:

Code:
Private Sub populatemyddl(d as dropdownlist,intPriority as integer)
Dim i as integer

d.items.add(new ListItem(string.empty,string.empty))
For i = 1 to 8
d.items.add(new ListItem(i,i))
Next

Try
d.selectedvalue = intPriority
Catch
throw new exception(intPriority & " not found in " & d.ClientId)
End Try
End Sub

Ok so:

1) In the myDataGridDB event we find the ddl and assign it to the variable d
2) In the myDataGridDB event we find the Priority value and assign it to the integer variable. I've assumed it always to be a number, if not use string.
3) Now we call another routine called populatemydll passing through the d and intPriority variables to it
4) We populate the dropdown list using the d and intpriority variables.

Can You see how I have found the ddl and priority value and called a routine to perform tasks on the ddl object?

The html on your ddl should look something like this:

Code:
<asp: DropDownList ID="cboPriority"
AutoPostBack="True"
runat="server">
</asp: DropDownList>

Remove all other events from it.
 

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
Dan

Great stuff, working fine now :)

Yes, I follow how you've found the ddl and priority value with the two routines and when they're kicking in.

I've noticed that when I select a different value in a DDL that the page seems to reposts, although I hadn't added a 'OnSelectedIndexChanged'.

OK, getting back to the original problem...

Getting the OnSelectedIndexChanged to kick in with the values of the ProjectID and Priority (DDL selected value) passed to a DDL_Update routine.

I've tried your original routine but it's still not kicking in

Here is your (modified) routine which should update the Priority value in the underlying table to the DDL selected value...

Code:
OnSelectedIndexChanged="cboPriority_Update"....

Sub cboPriority_Update(ByVal sender As System.Object, ByVal e As System.EventArgs)

Dim strConnection as String =ConfigurationSettings.AppSettings("MyConn")
Dim objConnection As New SqlConnection(strConnection)
Dim strSQL  as string
Dim dbComm as SqlCommand

Dim d as DropDownList = sender, c as TableCell, item as DataGridItem
Dim intPriority as string
Dim intProjectID As Int32 =Convert.ToInt32(item.Cells(0).Text)

c = d.Parent
item = c.Parent
intPriority = d.SelectedValue

'Response.Write("ProjectID=" & intProjectID & "<br>")
'Response.Write("Priority=" & intPriority & "<br>")

strSQL="UPDATE MyTable SET Priority = ' " & intPriority & "'" _
& " WHERE ProjectID = " & intProjectID

dbComm= New SqlCommand(strSQL,objConnection) 

objConnection.Open()
dbComm.ExecuteNonQuery()
objConnection.Close

End Sub

No errors given, just not updating data or even doing a simple 'response.write of the values.

Thanks again for all your help.
 
Last edited:

dan-cat

Registered User.
Local time
Today, 22:13
Joined
Jun 2, 2002
Messages
3,433
Sorry for not getting back to you sooner - have been arguing in the watercooler. :D

Ok you're getting the postback to the server because the ddl html has the pairing "AutoPostBack=True"

Now you have to make the code-behind file recognise the dropdowns event. So you do the following:

For the Html of the ddl.

Code:
<asp: DropDownList ID="cboPriority"
AutoPostBack="True"
runat="server">
OnSelectedIndexChanged="cboPriority_Update"
</asp: DropDownList>

Now for the code-behind file...

Code:
Sub cboPriority_Update(ByVal sender As System.Object, ByVal e As System.EventArgs)

Dim d as DropDownList
d = sender
response.write(d.ClientId)
End Sub

Ok this is really straightforward to start with. All we are doing is adding the event to the html of the ddl then creating the routine that that event calls to the code-behind file. The routine simply grabs the sender object (ie the ddl) and writes the clientid to the screen.

See if you can get this to work.
 

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
Hi Dan

No, still nothing, tried something similar before.

I've added your routine above and nothing appears.

I've even tried a normal Response.Write("hello") string and a Respone.Redirect in the routine....nothing, no errors, just reposts page.!

Incidentally, today I've have added another two DDLs and another datagrid to the page. All from a seperate datasource
This new DG will list available projects that the students can select.
The two new DDLs simply filter the DG....BUT.....their OnSelectedIndexChanged works a treat, no problems, however they are simple 'standalone' DDLs and not withun any datagrid.

There's no conflict as I was still getting nothing before I added the above.

What I'm trying to achieve (on one page) is for students to add Projects from a 'available projects' list (DG 2)
Their projects will appear in DG1 where they can then change the 'Priority' order (via the DDL) of their chosen projects (the problem I am having!).

So i'm sort of working backwards withe the DGs if you know what I mean


Sorry this is dragging on.
 
Last edited:

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
Dan, i'm finishing work now but will probably have a look in over the weekend.

Thanks for sticking with me on this.
 

KevinM

Registered User.
Local time
Today, 22:13
Joined
Jun 15, 2000
Messages
719
Ok, success..

The values are being passed to the 'on change' routine.

Problem seemed to be that I needed 'If Not IsPostBack Then' on the Page_Load routine, but now the initial datagrid is not updating (obviously!) and is not showing the new values in the datagrid.

How can I force this?

Many Thanks
 
Last edited:

Users who are viewing this thread

Top Bottom