locked
Modifying ListView datasource via VB.NET code RRS feed

  • Question

  • User695372294 posted

    I recently created a web form containing a ListView controlled entirely via html markup. These templates were created semi-automatically via Visual Studio. The purpose of the web form is to display two columns of a SQL Server table, with one of these columns being editable using an Edit button placed at the beginning of each record. The ListView uses a LinqDataSource and my initial design works fine, but I hit problems when I tried to sort the data displayed in the ListView. I failed to find a way to redefine my LinqDataSource in html to include sorting. Perhaps there is a way around that problem, but that is not the question I wish to ask here.

    My chosen solution was to define the LinqDataSource in the VB.NET coding for this web form and bind that to my ListView. I had no problem with sorting this version of the LinqDataSource and my data is displayed correctly in the ListView. However, when I click any one of the Edit buttons I get the following error.

    The ListView 'ListView1' raised event ItemEditing which wasn't handled.

    I never previously needed to have code for the ItemEditing event. Does the fact that the datasource is now defined in code prevent the existing <EditItemTemplate> in my markup from working as it did before?

    David

    Here is an extract from the html markup for my ListView:

    <asp:ListView ID="ListView1" runat="server" 
         EnableModelValidation="False" DataKeyNames="EntryID" >        
    		
    		<ItemTemplate>
    			<tr style="background-color:#DCDCDC;color: #000000;">
    				<td style="width: 10%;">
    					<asp:Button ID="Button2" runat="server" Text="Edit" CommandName="Edit" Height="22px" Font-Size="Smaller" />
    					</td>
    				<td style="text-align: left">
    					<asp:Label ID="EntryTitleLabel" runat="server" 
    						Text='<%# Eval("EntryTitle") %>' />
    				</td>
    				<td style="text-align: left">
    					<asp:Label ID="OrigEntryTitleLabel" runat="server" 
    						Text='<%# Eval("EntryTitle_Orig") %>' />
    				</td>                
    			</tr>
    		</ItemTemplate>
    		
    		<AlternatingItemTemplate>
    			<tr style="background-color:#FFF8DC;">                
    				<td style="width: 10%;">
    					<asp:Button ID="Button1" runat="server" Text="Edit" CommandName="Edit" Height="22px" Font-Size="Smaller" />
    					</td>
    				<td style="text-align: left">
    					<asp:Label ID="EntryTitleLabel" runat="server" 
    						Text='<%# Eval("EntryTitle") %>' />
    				</td>
    				<td style="text-align: left">
    					<asp:Label ID="OrigEntryTitleLabel" runat="server" 
    						Text='<%# Eval("EntryTitle_Orig") %>' />
    				</td>
    			</tr>
    		</AlternatingItemTemplate>
    		
    		<EditItemTemplate>
    			<tr style="background-color:#008A8C;color: #FFFFFF;">
    				<td style="width: 10%;">
    					<asp:Button ID="UpdateButton" runat="server" CommandName="Update" Text="Update" Font-Size="Smaller" />
    					<asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Cancel" Font-Size="Smaller" />
    				</td>
    				<td style="text-align: left">
    					<asp:TextBox ID="EntryTitleTextBox" runat="server" 
    						Text='<%# Bind("EntryTitle") %>' Width="300px" />
    				</td>
    				<td style="text-align: left">
    					<asp:Label ID="OrigEntryTitleLabel" runat="server" 
    						Text='<%# Eval("EntryTitle_Orig") %>' />
    				</td>
    			</tr>
    		</EditItemTemplate>

    Friday, December 30, 2016 1:00 PM

All replies

  • User-271186128 posted

    Hi haggis999,

    The ListView 'ListView1' raised event ItemEditing which wasn't handled.

    I never previously needed to have code for the ItemEditing event. Does the fact that the datasource is now defined in code prevent the existing <EditItemTemplate> in my markup from working as it did before?

    As far as I know, if we are bound the ListView with a data source control (e.g <asp:ListView DataSourceID="SqlDataSource2"), when click the Edit button with commandName is "Edit", the ListView will enter the Edit mode and bind data automatically.

    If we are not using the data source control, as it appears is your case, then the ListView doesn't know how to retrieve the data.  In this case you'll need to handle the ItemEditing/ItemUpdating/ItemCancelling/etc events and do wire everything up manually. You could use the following code:

        Protected Sub ListView1_ItemEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewEditEventArgs) Handles ListView1.ItemEditing
            ListView1.EditIndex = e.NewEditIndex
            BindListView()
    
    
        End Sub

    Best regards,
    Dillion

    Monday, January 2, 2017 7:43 AM
  • User695372294 posted

    Hi Dillion,
    Thanks for your help on this.

    At first, your code suggestion for the ItemEditing event caused me a problem as it generated the compilation error "'BindListView()' is not declared. It may be inaccessible due to its protection level." However, I fixed this by using ListView1.DataBind() instead of BindListView().

    Can you also provide some sample code for the ItemUpdating and ItemCancelling events? I'm simply trying to duplicate what was previously done automatically via the ListView's html markup.

    Monday, January 2, 2017 7:12 PM
  • User-271186128 posted

    Hi haggis999,

    Can you also provide some sample code for the ItemUpdating and ItemCancelling events? I'm simply trying to duplicate what was previously done automatically via the ListView's html markup.

    You could check the official document, it contains some samples:

    https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.itemupdating.aspx

    https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.itemcanceling.aspx

    https://msdn.microsoft.com/en-us/library/bb398790.aspx

    Best regards,
    Dillion

    Wednesday, January 4, 2017 9:35 AM
  • User695372294 posted

    Hi Dillion,
    I had already looked at those links, but they don't appear to help in my situation.

    As mentioned in my OP, I get a compilation error if there is no sub defined to handled the ItemEditing event. The same applies for the ItemUpdating and ItemCanceling events. These compilation errors disappeared as soon as I created those three subs, even though the subs initially contained no coding.

    Your ItemUpdating link simply suggests code for cancelling the update operation if any of the fields is empty or null and for converting an email address to lower case, neither of which I need at present. The page I am designing is a website admin tool for my own use and all I want is for an update to work, just as it did when the ListView was fully controlled by the html markup. At present, updates don't work and your linked page appears to offer no relevant code suggestions.

    A similar situation applies in the case of the ItemCanceling event. I'm forced to have event handling code, but no obviously mandatory code is suggested in the link you provided. However, I found some code suggestions elsewhere and they appear to work.

    My current vb.net code is as follows.

    Partial Class ReviewTitles
    	Inherits PageBase
    
    	Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load		
    		Using myDBC As CompDataSQLDataContext = New CompDataSQLDataContext()
    			Dim LinqDataSource1 = From ent In myDBC.Entries Where ent.CompID = 11
    								  Order By ent.CreationDate Descending
    								  Select ent
    
    			ListView1.DataSource = LinqDataSource1
    			ListView1.DataBind()
    		End Using
    	End Sub
    
    	Protected Sub ListView1_ItemEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewEditEventArgs) Handles ListView1.ItemEditing
    		'The following code was suggested by Dillion		
    		ListView1.EditIndex = e.NewEditIndex
    ListView1.DataBind() End Sub Protected Sub ListView1_ItemUpdating(sender As Object, e As System.Web.UI.WebControls.ListViewUpdateEventArgs) Handles ListView1.ItemUpdating
    'Don't know what code is needed here! End Sub Protected Sub ListView1_ItemCanceling(sender As Object, e As System.Web.UI.WebControls.ListViewCancelEventArgs) Handles ListView1.ItemCanceling ListView1.EditIndex = -1 e.Cancel = True ListView1.DataBind() End Sub End Class

    So far, I have not seen anything useful in your third link.

    Wednesday, January 4, 2017 2:17 PM
  • User695372294 posted

    Hi Dillion,
    Your third link (the ListView Web Server Control Overview) recommends binding data to a ListView using a DatasourceID, i.e. via the html markup. All it says about my current choice to bind data via the Datasource property is that it requires me to write code for any additional functionality such as sorting, paging and updating. However, no code suggestions are provided.

    Until someone can suggest what code is missing from my current non-functional solution, I have reverted to using a DatasourceID, with the addition of a Sort button. I have not yet found a way to enforce my desired default sort direction of 'Descending', so I have to press the Sort button every time I open the page.

    David

    Friday, January 6, 2017 3:07 PM
  • User-271186128 posted

    Hi haggis999,

    Based on your code and description, if you don't use DataSource control. You could refer to the following code to update records in ListView:

                <asp:ListView ID="ListView1" runat="server"
                    OnItemUpdating="ListView1_ItemUpdating"
                    OnItemCanceling="ListView1_ItemCanceling"
                    OnItemEditing="ListView1_ItemEditing" DataKeyNames="ID">
                    <AlternatingItemTemplate>
                        <tr style="">
                            <td>
                                <asp:Label ID="IDLabel" runat="server" Text='<%# Eval("ID") %>' />
                            </td>
                            <td>
                                <asp:Label ID="NameLabel" runat="server" Text='<%# Eval("Name") %>' />
                            </td>
                            <td>
                                <asp:Button ID="EditButton" runat="server" CommandName="Edit" Text="Edit" />
                                <asp:Button ID="DeleteButton" runat="server" CommandName="Delete" Text="Delete" />
                            </td>
                        </tr>
                    </AlternatingItemTemplate>
    

    Code behind:

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If Not IsPostBack Then
                'when page is first loaded, set the default SortDirection and SortExpression
                ViewState("SortDirection") = "ASC"
                ViewState("SortExpression") = "ID"
                BindListView()
    
            End If
        End Sub
        Protected Sub BindListView()
            Using db As VBTestDBEntities = New VBTestDBEntities()
    
                Dim linqresource = (From ee In db.Table3
                                    Select ee).ToList()
    
    
                ListView1.DataSource = linqresource
                ListView1.DataBind()
    
            End Using
        End Sub
    
        Protected Sub ListView1_ItemEditing(sender As Object, e As ListViewEditEventArgs)
            ListView1.EditIndex = e.NewEditIndex
            BindListView()
        End Sub
    
    'In this method, you need to find the edited value and update database, then exit the edit mode and rebind the gridview. Protected Sub ListView1_ItemUpdating(sender As Object, e As ListViewUpdateEventArgs) 'use findcontrol method to get the primary key Dim id As Int32 = Convert.ToInt32(CType(ListView1.Items(e.ItemIndex).FindControl("IDLabel1"), Label).Text) 'use findcontrol method to get the edited value Dim name As String = CType(ListView1.Items(e.ItemIndex).FindControl("NameTextBox"), TextBox).Text ' If (Not String.IsNullOrEmpty(id) And Not String.IsNullOrEmpty(name)) Then 'find the edited item Using db As VBTestDBEntities = New VBTestDBEntities() Dim item As Table3 = (From tt In db.Table3 Where tt.ID = id Select tt).FirstOrDefault() item.Name = name 'change the value db.SaveChanges() 'save change End Using End If 'exit the edit mode ListView1.EditIndex = -1 BindListView() 'rebind the ListView. End Sub Protected Sub ListView1_ItemCanceling(sender As Object, e As ListViewCancelEventArgs) 'Check the operation that raised the event If (e.CancelMode = ListViewCancelMode.CancelingEdit) Then ListView1.EditIndex = -1 e.Cancel = True BindListView() End If End Sub

    If you want to sort the list view, in the listview header, you could use LinkButton to display the title. Then, in the linkbutton click event, you could get the SortDirection and SortExpression, and rebind the listview.

    Like this:

                   <LayoutTemplate>
                        <table runat="server">
                            <tr runat="server">
                                <td runat="server">
                                    <table id="itemPlaceholderContainer" runat="server" border="0" style="">
                                        <tr runat="server" style="">
                                            <th runat="server">
                                                <asp:LinkButton ID="lbnID" OnClick="ListViewSorting" CommandArgument="ID" runat="server">ID</asp:LinkButton>
                                            </th>
                                            <th runat="server">
                                                <asp:LinkButton ID="lbnName" OnClick="ListViewSorting" CommandArgument="Name" runat="server">Name</asp:LinkButton>
                                            </th>
                                            <th runat="server"></th>
                                        </tr>
                                        <tr id="itemPlaceholder" runat="server">
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                            <tr runat="server">
                                <td runat="server" style=""></td>
                            </tr>
                        </table>
                    </LayoutTemplate>

    and:

       Protected Sub ListViewSorting(sender As Object, e As EventArgs)
            Dim currentLink As LinkButton = CType(sender, LinkButton)
    
    
        End Sub

    You could use ViewState to store the previous SortDirection and SortExpression, then based on it to change your query statement.

    Here is an article about GridView sorting, you could refer to it: https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.sorting(v=vs.110).aspx

    Best regards,
    Dillion

    Saturday, January 7, 2017 3:40 AM
  • User695372294 posted

    Hi Dillion,
    Many thanks for your very comprehensive reply. I have not yet had the time to study it in detail, but I will let you know in due course how I get on with implementing your suggestions.

    David

    Saturday, January 7, 2017 10:38 AM
  • User695372294 posted

    Hi Dillion,
    You started your last post with "Based on your code and description, if you don't use DataSource control. You could refer to the following code...". I think you really meant to write 'if you use DataSource control instead of DatasourceID'.

    Before attempting to make a DataSource-based solution work, I decided to start by making an attempt to do no more than change the default sort direction to 'DESC' in my version of the page that binds data to my ListView using a DatasourceID, i.e. via the html markup.

    My interpretation of your last post was that the following code might do this job, but it doesn't have any effect. The default sort direction is still 'ASC'.

    	Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
    		If Not IsPostBack Then
    			'when page is first loaded, set the default SortDirection and SortExpression
    			ViewState("SortDirection") = "DESC"
    			ViewState("SortExpression") = "CreationDate"
    			ListView1.DataBind()
    		End If
    
    	End Sub

    I then tried to use the following code derived from https://msdn.microsoft.com/en-us/library/bb398790.aspx#SortingDataDisplayedByTheListViewControl. This successfully enforces a permanent sort direction of 'DESC', but only after I have pressed the Sort button. Is there any way to get the initial display of my ListView sorted in descending order?

    	Protected Sub ListView1_Sorting(sender As Object, e As ListViewSortEventArgs) Handles ListView1.Sorting
    
    		If (String.IsNullOrEmpty(e.SortExpression)) Then Return
    
    		Dim direction As String = ""
    		direction = "DESC"
    
    		ViewState("SortDirection") = direction
    
    		Dim sortColumns As String() = e.SortExpression.Split(","c)
    		Dim sortExpression As String = sortColumns(0) & " " & direction
    		Dim i As Integer
    		For i = 1 To sortColumns.Length - 1
    			sortExpression += ", " & sortColumns(i) & " " & direction
    		Next i
    		e.SortExpression = sortExpression
    
    	End Sub

    Saturday, January 7, 2017 3:04 PM
  • User-271186128 posted

    Hi haggis999,

    This successfully enforces a permanent sort direction of 'DESC', but only after I have pressed the Sort button. Is there any way to get the initial display of my ListView sorted in descending order?

    After setting the default SortDirection and SortExpression in the page load event, you need to based on the value to change your query statement in the BindListView() method. Like this:

        Protected Sub BindListView()
            Using db As VBTestDBEntities = New VBTestDBEntities()
                 Dim linqresource
    'get the SortExpression and SortDirection from ViewState 'if statement, if the SortDirection is DESC and SortExpression is ID linqresource = (From ee In db.Table3 Order By ee.ID Descending Select ee).ToList()
    'if the SortDirection is ASC and SortExpression is ID ListView1.DataSource = linqresource ListView1.DataBind() End Using End Sub

    Best regards,
    Dillion

    Tuesday, January 10, 2017 8:39 AM
  • User695372294 posted

    Hi Dillion,
    I think that you have misunderstood my last question. It's probably my own fault for trying to discuss two separate scenarios in the same thread! There are two ways of data binding a ListView and that choice makes a difference in how sorting is controlled. For my own educational reasons, I am interested in learning more about how to exploit both ways of binding a ListView.

    Scenario 1:  Binding a ListView using a DataSource defined in the code

    This was the topic raised in my original post. As I said back then, I already know how to sort the data in the LinqDataSource that was created in my vb.net code. The ListView in this version of my web form is always sorted in descending CreationDate order and I have no need of a Sort button. However, I have not yet had the time to try out your suggestions for making the update process work correctly in this scenario.

    Scenario 2:  Binding a ListView using a DataSourceID defined in the html markup

    This is the method recommended by Microsoft in the third link you gave me on 4 January (https://msdn.microsoft.com/en-us/library/bb398790.aspx). I know how to create a Sort button in this situation, but I don't yet know how to control the sort direction for the initial display of the ListView.

    My last post raised a question about sorting in Scenario 2, but you appear to have provided an answer that relates to Scenario 1.

    Best regards,
    David

    Tuesday, January 10, 2017 10:47 AM