The source data item is ONLY available during the binding events, and once that is is complete, then the binding source data goes out of scope, and is not available anymore. (you find that is is now empty after the binding events are done).
So, about the only thing you can do is say having in your listview is to include the PK id from the database, and use that. And for reasons of security, you don't need (or want) to include the PK data in the client side markup. So, you want to use the datakeys option.
Hence, say this markup:
<asp:ListView ID="ListView1" runat="server"
DataKeyNames="ID">
<ItemTemplate>
<tr id="onerow" runat="server">
<td><asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstName") %>' /></td>
<td><asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>' /></td>
<td><asp:Label ID="CityLabel" runat="server" Text='<%# Eval("City") %>' /></td>
<td><asp:Label ID="Desciption" runat="server" Text='<%# Eval("Description") %>' /></td>
<td>
<asp:Button ID="cmdView" runat="server" Text="View Hotel"
OnClick="cmdView_Click" CssClass="btn" />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server"
class="table table-hover">
<tr runat="server" style="">
<th runat="server">FirstName</th>
<th runat="server">LastName</th>
<th runat="server">City</th>
<th runat="server">Descripiton</th>
<th runat="server">View</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
And as noted, it is "unfortunate" that the data item source goes out of scope once data binding is complete. This means the data table (or class model) used to fill out the ListView is no longer available. So, you have to re-pull the data.
So, my button click code would thus become this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid()
End If
End Sub
Sub LoadGrid()
Dim strSQL As String =
"SELECT * FROM tblHotelsA
ORDER BY HotelName"
ListView1.DataSource = MyRst(strSQL)
ListView1.DataBind()
End Sub
Protected Sub cmdView_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim lvRow As ListViewItem = btn.NamingContainer
Dim intPK As Integer = ListView1.DataKeys(lvRow.DisplayIndex)("ID")
Dim strSQL As String = $"SELECT * FROM tblHotelsA WHERE ID = {intPK}"
Dim rstHotel As DataTable = MyRst(strSQL)
With rstHotel.Rows(0)
lblHotelName.Text = .Item("HotelName")
lblCity.Text = .Item("City")
End With
End Sub
So, the data that drives the ListView (dataitem) is no longer available after the binding events are complete.
So, then your only choice is to pull data from the ListView row, or better is to get the PK of that row, and pull the data from the database. So, you can't pass or set the data item source with a command object, nor even "pass" the data item, since as I noted, it goes out of scope after binding events are completed. This also quite much means there is LITTLE reason to use the command object, and as above shows I just dropped into the ListVview a good old fashioned plain regular asp button, and you can pick up the current row with "naming container".