2

Apologies for the slightly convoluted title.

Basically, I have a project where I have a database connected to it. I'm displaying some of the contents of the database using a GridView, which is all up and running, but the way I'm designing the page I need to be able to click a button in each row that in essence exports the value of one of the cells in the row to a subroutine.

I've tried googling it quite a bit and trying related things I found here, but nothing I could find would function like I would like it to.

The relevant code is below.

Markup:

<asp:GridView ID="Staffgv" runat="server" AutoGenerateColumns="false" OnRowCommand="Staffgv_RowCommand" AllowPaging="true" PageSize="20" OnPageIndexChanging="Staffgv_PageIndexChanging" BackColor="#f9f9f9" CssClass="gvStyle" >

   <Columns>

         <asp:TemplateField HeaderText="Start" InsertVisible="False" SortExpression="DateTimeStart">
                <HeaderStyle Width="70px"   CssClass="hdrGvStart"/>
                <ItemTemplate>

                         <asp:Label ID="lblDateTimeStart" runat="server" Text='<%# Bind("DateTimeStart", "{0:t}") %>'></asp:Label>

                </ItemTemplate>      

          </asp:TemplateField>

          <asp:TemplateField HeaderText="Finish" SortExpression="DateTimeEnd">
                 <HeaderStyle Width="70px"   CssClass="hdrGvFinish"/>
                 <ItemTemplate>

                         <asp:Label ID="lblDateTimeEnd" runat="server" Text='<%# Bind("DateTimeEnd", "{0:t}") %>'></asp:Label>

                 </ItemTemplate>

          </asp:TemplateField>

          <asp:TemplateField HeaderText="Forename" SortExpression="Forename">
                 <HeaderStyle Width="140px"  CssClass="hdrGvForename"/>
                 <ItemTemplate>

                         <asp:Label ID="lblForename" runat="server" Text='<%# Bind("Forename") %>'></asp:Label>

                 </ItemTemplate>               

          </asp:TemplateField>  

          <asp:TemplateField HeaderText="Surname" SortExpression="Surname">
                  <HeaderStyle Width="140px"   CssClass="hdrGvSurname"/>
                  <ItemTemplate>

                         <asp:Label ID="lblSurname" runat="server" Text='<%# Bind("Surname") %>'></asp:Label>

                  </ItemTemplate>               

          </asp:TemplateField>  

          <asp:TemplateField>
                  <HeaderStyle CssClass="gvHeaderEdit" />
                  <ItemTemplate>

                         <asp:Button ID="Btnapptid" runat="server" Text=""  CssClass="btnGVEdit"  CommandName="FillStaffTables" CommandArgument="<%# CType(Container,GridViewRow).RowIndex %>"/>

                  </ItemTemplate>
          </asp:TemplateField>

     </Columns>
 </asp:GridView>

And the relevant VB code:

Private Sub Staffgv_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles Staffgv.RowDataBound
    Select Case e.Row.RowType
        Case DataControlRowType.DataRow
            Dim row = DirectCast(e.Row.DataItem, DataRowView)
            Dim apptid As Integer = Integer.Parse(row("AppointmentID").ToString)
            Dim Btnapptid = DirectCast(e.Row.FindControl("Btnapptid"), Button)
            'Btnapptid.Text = apptid
            Btnapptid.ToolTip = apptid
    End Select
End Sub

Protected Sub Staffgv_RowCommand(ByVal sender As Object, e As GridViewCommandEventArgs)
    If (e.CommandName = "FillStaffTables") Then
        Dim index As Integer = Convert.ToInt32(e.CommandArgument)

        lblTxtTester.Text = "AppointmentID"
        TextboxTester.Text = index
    End If
End Sub

If anyone would like more code like the code used to fill the GridView I'll post it, just didn't want to post too much irrelevant code.

Thanks

Fruitbat
  • 764
  • 2
  • 5
  • 19
Michael Dono
  • 61
  • 1
  • 8

1 Answers1

1

Solution A

When you only want 1 value from the gridview row when the button is clicked.

You could simply utilize the CommandArgument of your button (Btnapptid). This assumes that you don't need the gridview row index for when the button is clicked. If you do need this, then please see Solution B, otherwise continue here.

First, you'd need to modify your button's CommandArgument in the aspx page

ASPX

<asp:Button ID="Btnapptid" runat="server" Text=""  CssClass="btnGVEdit"
    CommandName="FillStaffTables" CommandArgument='<%# Bind("AppointmentID") %>'/>

Then you should be able to grab the AppointmentID like this

VB (inside Staffgv_RowCommand())

If (e.CommandName = "FillStaffTables") Then
    txtAppointmentID.Text = e.CommandArgument
End If

Solution B

When you need more than 1 value from the gridview row when the button is clicked

Please note that this solution requires a couple changes on your end

  1. Create an additional control (in the gridview) which should hold the value that you want to get when the button is clicked.
  2. Fill said control with the value you want (via Bind() in the UI or in RowDataBound in the codebehind).

Next, in your RowCommand you'd be able to grab the newly created control with the help of the index variable (from your example) like so

Staffgv.Rows(index).FindControl("YOUR_CONTROLS_ID")

Example

Say that you decide to create a HiddenField control in which to store the value from your database

ASPX (hidden field should be somewhere inside the gridview - right under Btnapptid should be fine)

<asp:HiddenField ID="hfMyControl" runat="server" Visible="False" 
    Value='<%# Bind("SOME_DB_COLUMN") %>'/>

VB (inside Staffgv_RowCommand())

Dim hfMyControl As HiddenField = _
    DirectCast(Staffgv.Rows(index).FindControl("hfMyControl"), HiddenField)

Then simply use the value of hfMyControl

hfMyControl.Value

You could also repeat all this using multiple controls in order to potentially access multiple DB values stored in controls in the gridview.

Mr.Z
  • 542
  • 2
  • 5
  • 18
  • Thanks, just wanted to ask a question about your solutions. I have a SQL command that pulls in AppointmentID amongst other things, and while it isn't used in the GridView I had some code before (that I was trying to use to test a few means of doing this) that managed to display the correct ID. All I really need the code to do is find 1 value in the row that was clicked, and pass it through as a variable to I can display other data from the database to the user. Does this mean Solution A might be the best in this case, because I tried something similar to it before and it was crashing? – Michael Dono Feb 19 '16 at 10:58
  • I've tried to build Solution B into my project but clicking the buttons doesn't cause a value to show up. My code is `If (e.CommandName = "FillStaffTables") Then Dim index As Integer = Convert.ToInt32(e.CommandArgument) Dim hfMyControl As HiddenField = DirectCast(Staffgv.Rows(index).FindControl("hfMyControl"), HiddenField) txtAppointmentID.Text = hfMyControl.Value End If` – Michael Dono Feb 19 '16 at 11:22
  • 1
    In reply to your first comment: in your case, yes, **Solution A** would be ideal. It would lead to less code too. For your second comment: I'm wondering if `hfMyControl` is not being filled with a value in the first place. Try setting a breakpoint _right after_ the line `Dim hfMyControl As HiddenField = DirectCast(Staffgv.Rows(index).FindControl("hfMyControl"), HiddenField)`. Check that 1) The variable `hfMyControl` is not `Nothing` and 2) `hfMyControl.Value` has something in it. – Mr.Z Feb 19 '16 at 14:38
  • Hmm, what sort of code would I need for A then? I'm pretty new to GridView and ASP.NET in general, sorry if I'm a hassle haha – Michael Dono Feb 19 '16 at 14:51
  • 1
    Is it correct to assume that you want `AppointmentID` when `Btnapptid` is clicked? – Mr.Z Feb 19 '16 at 14:58
  • 1
    I've edited **Solution A** based on the assumption that you're looking for `AppointmentID`. – Mr.Z Feb 19 '16 at 15:58
  • Thanks, seems to be just want I wanted, except when clicking the button I get a crash `Server Error in '/' Application. Invalid postback or callback argument. Event validation is enabled using in configuration or <%@ Page EnableEventValidation="true" %> in a page.` I changed the value in my config but then nothing happens when the button is pressed? – Michael Dono Feb 19 '16 at 16:24
  • 1
    It's difficult to tell what's going on just based on this, but here are a few things to try: try adding this to your button `UseSubmitBehavior="False"` If that doesn't work, undo that change and try flipping your button into a `LinkButton` instead, see if that gets you anywhere. See related answers: [here](http://stackoverflow.com/a/275724/1204599) & [here](http://stackoverflow.com/a/5055843/1204599). – Mr.Z Feb 19 '16 at 17:50
  • 1
    Make sure that if you _do_ flip it to a `LinkButton`, that you fill-in the empty string in the `Text=""` part! I don't think anything will display if this text attribute remains empty like this. – Mr.Z Feb 19 '16 at 18:02
  • Both changing `UseSubmitBehavior` to `false` and Using a `LinkButton` seems to function correctly - to a certain extent. I have another external button that changes the SQL statement to display appointments from only the selected staff member; When using the initial state where all appointments are displayed, the correct ID is displayed upon clicking the corresponding button in the `GridView`. However, changing over to using the filter and clicking the button in the row yields an incorrect number. It looks to me as though it is taking the number from the previous `GridView` for some reason. – Michael Dono Feb 19 '16 at 18:15
  • Further testing, in which I changed the initial state of the `GridView` to only show a certain staff member displayed the correct ID. Changing the `GridView` to display all results in the same behaviour I described, where it displays the ID of the appointment that was shown _before_ I changed the filter. – Michael Dono Feb 19 '16 at 18:20
  • Just checking through my code, and one of the possible issues I've identified is that the `GridView` might not be getting cleared as cleanly as it should. What is the best practice to refresh the `GridView` so that it contains no data at all, before it is filled with new data? – Michael Dono Feb 19 '16 at 18:26
  • Hmm, tried clearing the `GridView`'s DataSource by setting it to Nothing and it didn't seem to clear up the problem. I can't really see any obvious issues in my code, unless you can think of anything? – Michael Dono Feb 19 '16 at 18:32
  • 1
    To clear out the gridview completely, run `Staffgv.DataSource = Nothing` followed by `Staffgv.DataBind()`. However, if you just want to replace the data inside, then `Staffgv.DataSource = myNewDataTable` followed by `Staffgv.DataBind()` should do the trick and leave no traces of the previous data. – Mr.Z Feb 19 '16 at 19:47
  • yeah I did that and didn't fix my problem unfortunately – Michael Dono Feb 19 '16 at 19:49
  • 1
    I'd really need to see the code for your other button to make a good determination of what is going on. Either add the code for said button to your original question or perhaps start a new question. – Mr.Z Feb 19 '16 at 19:50
  • OK, I'll make a new question else this thread is going to get pretty long, I'll link it here – Michael Dono Feb 19 '16 at 19:53
  • 1
    Also, it would helpful if you could list off the UI path you're taking e.g., are you doing this: **Case A**: press `Btnapptid` -> get correct `AppointmentID` -> press `BtnFilter` -> press `Btnapptid`-> get incorrect/previous `AppointmentID` ? **Or is it perhaps Case B**: press `Btnapptid` -> get correct `AppointmentID` -> press `BtnFilter` -> get incorrect/previous `AppointmentID` ? – Mr.Z Feb 19 '16 at 19:55
  • New thread here http://stackoverflow.com/questions/35514245/strange-behavior-from-gridview-in-asp-net – Michael Dono Feb 19 '16 at 20:20
  • And also, I don't understand the different between Case A and Case B? – Michael Dono Feb 19 '16 at 20:21
  • 1
    Look closely, the difference between the two cases is that in case B, after clicking the filtering button, `Btnapptid` _isn't_ being clicked. Is this the path you're taking? If so, then this might explain why the textbox is keeping it's old value. – Mr.Z Feb 20 '16 at 07:02
  • 1
    If you think my answer has earned it, please vote up / accept as answer. I'll start taking a look at the next question that you've linked. – Mr.Z Feb 20 '16 at 07:04