Get the value from a cell in a detailsview row without knowing the index

Hi Experts,
   I need to do something like this:

        If  personDetails.Rows(16).Cells(0).Text = "some text" Then  ...

  But rather than referring to rows(16), I'd like to be able to refer to Rows("columnName").
  This should be easy but I can't find it!  Is there a way of doing this?

Gail HL
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

I don't think you can.

Since all rows are the same you cannot give it a name.

I think you are getting confused between columns and rows.

Rows are vertical and columns horizontal.
gailhlAuthor Commented:
Thanks for your reply, Gavin ...

I don't think I am mixing up columns and rows, just sloppy in wording the question.  
The above example I gave works  - the problem with it is that it means any time a new field is added to the DetailsView, I've got to remember to change the code to reflect the new position of "rows(16)".  So I'd rather refer to it by some sort of key name, and as so much else in .NET is based on dictionaries, I'm guessing that the detailsview control might have keys somewhere that I can access, if only I knew the syntax.

Gail HL
I just did a quick test on my machine and to me Rows is the collection of DataRows in the details view.

So if I have 10 records returned I get 10 rows. It doesn't care about me changing the amount of fields returned only that amount or records.

I still say you cannot give the rows object a name instead of an index.
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

gailhlAuthor Commented:
Sorry, I still think we aren't talking about the same thing.
I'm talking about the new DetailsView control in ASP.Net 2.0, Visual Studio 2005.

There is only one row in a detailsview.  Its "rows" (as referred to in original question) are actually the "columns" of the underlying "table" (or dataview).  In other words, the rows and columns are inverted in the detailsview control.
Therefore, rows(16) refers to the value in the 15th column (0 based) for the one record which is bound to the detailsview.  Whenever I add a new column to the stored procedure that is the source of the data, the number of items in the rows collection will change.

So if I want to base a condition on the value in that field for that single record, I have to use the syntax
               If  personDetails.Rows(16).Cells(0).Text = "some text" Then  ...

But that's dodgy because at some future point, if the underlying procedure is changed, that field could be in rows(17) rows(23) -- in the detailsview control, that is (not in the underlying table).  

But being a bit of a newbie to ASP.NET and to Visual Studio 2005, I don't actually know how to query the value in the cell any other way (I don't know the syntax for querying the underlying data before the detailsview control inverts it).
But I'm guessing that there probably IS a better way than what I am doing.

Gail HL
Okay lets just ignore the row section :)

You are worried that the SQL will change which will then stop you code from working?

Easiest way to avoid this, which I would always recommend you do, is to be specific about what you want to display. For example
<asp:DetailsView    DataSourceID="DetailsSource" AutoGenerateRows="false" Runat="Server">
            <asp:BoundField DataField="LastName" HeaderText="Last Name:" />
            <asp:BoundField DataField="FirstName" HeaderText="First Name:" />
            <asp:BoundField DataField="Extension" HeaderText="Extension:" />

Now image the DataSource "DetailsSource" return 10 fields in it's SQL and you only want to show 3. Just specify the 3 exact fields you want. So when someone updates the stored proc to return 12 fields your grid is still the same as when you develope it. (Unless someone changes the proc and no longer returns the required fields.)

In regard to your second question, to query the data before it is bound you can put your code in the DetailsView.OnItemDataBound event. Then you can easily loop through the recorsd there and do what you like.

The Row object does not have a dictionary so in reply to your original question

[But rather than referring to rows(16), I'd like to be able to refer to Rows("columnName")]

You can't.

Hope I have cleared up everything here :), if not just yell and we can sort it out.
gailhlAuthor Commented:
Well...perhaps I'm completely losing my mind.  Or totally unobservant.  But as far as I can tell, there is no OnItemDataBound event in the DetailsView control.

Are we both talking about Visual Studio 2005 and VB?


PS What I am trying to do is color-code the text displayed in a cell depending on the data value.  The orginal example I posted works but this is a project being built and the procs are not final.  The client is still adding and removing fields etc. so the position changes, and I've already had to change the code twice.
Take a look here....

It is the DataBound event and not ItemDataBound


void DetailsView1_DataBound(object sender, EventArgs e)
          if(((DetailsView)sender).CurrentMode== DetailsViewMode.Edit)
                DropDownList ddl=(DropDownList)((DetailsView)sender).FindContro l("DropDownList1");
                if (ddl1 !=null) //you found the dropdownlist
                    //execute statements to add the desired data to it

This example is in C# and for aa DropDown but it should get you going

This is what the online C# --> VB.Net generator gave me. It is normally accurate but sometimes get's it wrong

    Private Sub DetailsView1_DataBound(ByVal sender As Object, ByVal e As EventArgs)
        If (CType(sender,DetailsView).CurrentMode = DetailsViewMode.Edit) Then
            Dim ddl As DropDownList = CType(CType(sender,DetailsView).FindContro,DropDownList)
            If (Not (ddl1) Is Nothing) Then
                'execute statements to add the desired data to it
            End If
        End If
    End Sub
Okay I posted an attempted answer to two different questions here :)...

Please ignore the DetailsViewMode.Edit part because that does not apply to you, you can cast your label using the findcontrol option and then change it as you like (Change DropDown to label)

Other than that it should work with no problems.
gailhlAuthor Commented:
Sorry, it just doesn't work.  The field I'm trying to access in the condition isn't a template field;  it's an asp:checkbox which is databound.

This works - but I don't like the reference by index.

            Dim lblPN As Label = Me.personDetails.FindControl("lblPersonNotes")
            If Not (lblPN Is Nothing) Then
                Dim ckb As CheckBox = Me.personDetails.Rows(16).Cells(1).Controls(0)
                If ckb.Checked = True Then
                    lblPN.ForeColor = Drawing.Color.Red
                    lblPN.ForeColor = Drawing.Color.Black
                End If
            End If

Perhaps FindControl would work if I change it to a template field -- but I still find it impossible to believe that there is no straightforward way to address the value of an asp databound control without referring to it by index or converting it to a template field.  
Since it is not actually a CheckBox but a bound column that renders like a checkbox I don't think you can use FindControl unless you change it to be a template column.

The normal way would be to use the index of the column, since bound columns do not have an ID you cannot reference it in that way.

I am doing something very similar where depending on what the bound column ends up being I change the forecolor of that label


            private void dgResults_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
                  if( e.Item.ItemType != ListItemType.Header)
                        e.Item.Cells[3].ForeColor = e.Item.Cells[3].Text == "Rejected" ?  System.Drawing.Color.Red : System.Drawing.Color.Green;

Basically exactly what you have, I use the index to find the cell and then check what it says and change the colour accordingly.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.