vb.netdatagridviewienumerablebindingsourcebindinglist

Filter list datagridview via textbox using a second bindinglist class and set to bindingsource.datasource in vb.net


I'm trying to filter list datagridview via textbox using a second bindinglist class and set to bindingsource.datasource in vb.net.

The problem is when I filter in two event textboxes and then I I make clear or blank in one of the textboxes then the state of datagridview is not in the state in the filter.

RESULT FILTER WITH BINDINGLIST

Should be when I clear in textbox criteria2 then datagridview should keep filter state referring to textbox criteria1 as below screenshot should keep filter in criteria1 A.

Is there something wrong with my code?

RESULT FILTER WITH BINDINGLIST

Class SortableBindingList

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel


''' <summary>
''' Provides a generic collection that supports data binding and additionally supports sorting.
''' See http://msdn.microsoft.com/en-us/library/ms993236.aspx
''' If the elements are IComparable it uses that; otherwise compares the ToString()
''' </summary>
''' <typeparam name="T">The type of elements in the list.</typeparam>
Public Class SortableBindingList(Of T As Class)
        Inherits BindingList(Of T)

        Private _isSorted As Boolean
        Private _sortDirection As ListSortDirection = ListSortDirection.Ascending
        Private _sortProperty As PropertyDescriptor

        ''' <summary>
        ''' Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
        ''' </summary>
        Public Sub New()
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
        ''' </summary>
        ''' <param name="list">An <see cref="T:System.Collections.Generic.IList`1" /> of items to be contained in the <see cref="T:System.ComponentModel.BindingList`1" />.</param>
        Public Sub New(ByVal list As IList(Of T))
            MyBase.New(list)
        End Sub

        ''' <summary>
        ''' Gets a value indicating whether the list supports sorting.
        ''' </summary>
        Protected Overrides ReadOnly Property SupportsSortingCore As Boolean
            Get
                Return True
            End Get
        End Property

        ''' <summary>
        ''' Gets a value indicating whether the list is sorted.
        ''' </summary>
        Protected Overrides ReadOnly Property IsSortedCore As Boolean
            Get
                Return _isSorted
            End Get
        End Property

        ''' <summary>
        ''' Gets the direction the list is sorted.
        ''' </summary>
        Protected Overrides ReadOnly Property SortDirectionCore As ListSortDirection
            Get
                Return _sortDirection
            End Get
        End Property

        ''' <summary>
        ''' Gets the property descriptor that is used for sorting the list if sorting is implemented in a derived class; otherwise, returns null
        ''' </summary>
        Protected Overrides ReadOnly Property SortPropertyCore As PropertyDescriptor
            Get
                Return _sortProperty
            End Get
        End Property

        ''' <summary>
        ''' Removes any sort applied with ApplySortCore if sorting is implemented
        ''' </summary>
        Protected Overrides Sub RemoveSortCore()
            _sortDirection = ListSortDirection.Ascending
            _sortProperty = Nothing
            _isSorted = False
        End Sub

    ''' <summary>
    ''' Sorts the items if overridden in a derived class
    ''' </summary>
    ''' <param name="prop"></param>
    ''' <param name="direction"></param>
    Protected Overrides Sub ApplySortCore(ByVal prop As PropertyDescriptor, ByVal direction As ListSortDirection)
        _sortProperty = prop
        _sortDirection = direction

        Dim list As List(Of T) = TryCast(Items, List(Of T))
        If list Is Nothing Then
            Return
        End If

        list.Sort(AddressOf Compare)

        _isSorted = True
        'fire an event that the list has been changed.
        OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
    End Sub
    Private Function Compare(ByVal lhs As T, ByVal rhs As T) As Integer
            Dim result = OnComparison(lhs, rhs)
            'invert if descending
            If _sortDirection = ListSortDirection.Descending Then
                result = -result
            End If
            Return result
        End Function

        Private Function OnComparison(ByVal lhs As T, ByVal rhs As T) As Integer
            Dim lhsValue As Object = If(lhs Is Nothing, Nothing, _sortProperty.GetValue(lhs))
            Dim rhsValue As Object = If(rhs Is Nothing, Nothing, _sortProperty.GetValue(rhs))
            If lhsValue Is Nothing Then
                Return If(rhsValue Is Nothing, 0, -1) 'nulls are equal
            End If
            If rhsValue Is Nothing Then
                Return 1 'first has value, second doesn't
            End If
            If TypeOf lhsValue Is IComparable Then
                Return DirectCast(lhsValue, IComparable).CompareTo(rhsValue)
            End If
            If lhsValue.Equals(rhsValue) Then
                Return 0 'both are the same
            End If
            'not comparable, compare ToString
            Return lhsValue.ToString().CompareTo(rhsValue.ToString())
        End Function
    End Class

Public Class Form4
    Private StockCardsCache As List(Of StockCards)
    Private _criteriasBindingList As New SortableBindingList(Of StockCards)()
    Private bindingSource As BindingSource = Nothing
    Private Sub LoadData()
        StockCardsCache = New List(Of StockCards) From {
            New StockCards() With {
                .Invono = "PI0001",
                .InvoDate = New DateTime(2024, 2, 1),
                .Transaction = "PURCHASE",
                .CodeProduct = "TEST 1000",
                .Barcode = "1000",
                .Criteria1 = "A",
                .Criteria2 = "C",
                .Criteria3 = "E",
                .Criteria4 = "G",
                .IN = 10,
                .OUT = 0,
                .BLC = 10
            },
            New StockCards() With {
                .Invono = "PI0001",
                .InvoDate = New DateTime(2024, 2, 1),
                .Transaction = "PURCHASE",
                .CodeProduct = "TEST 1000",
                .Barcode = "1000",
                .Criteria1 = "B",
                .Criteria2 = "D",
                .Criteria3 = "F",
                .Criteria4 = "H",
                .IN = 12,
                .OUT = 0,
                .BLC = 22
            },
            New StockCards() With {
                .Invono = "PI0001",
                .InvoDate = New DateTime(2024, 2, 1),
                .Transaction = "PURCHASE",
                .CodeProduct = "TEST 1000",
                .Barcode = "1000",
                .Criteria1 = "A",
                .Criteria2 = "E",
                .Criteria3 = "G",
                .Criteria4 = "I",
                .IN = 12,
                .OUT = 0,
                .BLC = 34
            },
            New StockCards() With {
                .Invono = "PI0001",
                .InvoDate = New DateTime(2024, 2, 1),
                .Transaction = "PURCHASE",
                .CodeProduct = "TEST 1000",
                .Barcode = "1000",
                .Criteria1 = "B",
                .Criteria2 = "F",
                .Criteria3 = "H",
                .Criteria4 = "J",
                .IN = 12,
                .OUT = 0,
                .BLC = 46
            }
        }
        _criteriasBindingList = New SortableBindingList(Of StockCards)(StockCardsCache)
        bindingSource = New BindingSource With {.DataSource = _criteriasBindingList}
        DataGridView1.DataSource = bindingSource
    End Sub
    Private Sub Form4_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        LoadData()
    End Sub

    Private Sub txtcriteria1_TextChanged(sender As Object, e As EventArgs) Handles txtcriteria1.TextChanged
        Dim str = txtcriteria1.Text.Trim().ToLower()
        bindingSource.DataSource = If(String.IsNullOrEmpty(str), _criteriasBindingList, _criteriasBindingList.Where(Function(c) c.Criteria1.ToLower().Contains(str)).ToList())
    End Sub
    Private Sub txtcriteria2_TextChanged(sender As Object, e As EventArgs) Handles txtcriteria2.TextChanged
        Dim str = txtcriteria2.Text.Trim().ToLower()
        bindingSource.DataSource = If(String.IsNullOrEmpty(str), _criteriasBindingList, _criteriasBindingList.Where(Function(c) c.Criteria2.ToLower().Contains(str)).ToList())
    End Sub
End Class

Solution

  • Your code of

        Private Sub txtcriteria1_TextChanged(sender As Object, e As EventArgs) Handles txtcriteria1.TextChanged
            Dim str = txtcriteria1.Text.Trim().ToLower()
            bindingSource.DataSource = If(String.IsNullOrEmpty(str), _criteriasBindingList, _criteriasBindingList.Where(Function(c) c.Criteria1.ToLower().Contains(str)).ToList())
        End Sub
        Private Sub txtcriteria2_TextChanged(sender As Object, e As EventArgs) Handles txtcriteria2.TextChanged
            Dim str = txtcriteria2.Text.Trim().ToLower()
            bindingSource.DataSource = If(String.IsNullOrEmpty(str), _criteriasBindingList, _criteriasBindingList.Where(Function(c) c.Criteria2.ToLower().Contains(str)).ToList())
        End Sub
    

    does the following:

    Instead, implement a filtering function, like:

    Private Sub myFilter(str1 As String, str2 As String)
        If (String.IsNullOrEmpty(str1) AndAlso String.IsNullOrEmpty(str2)) Then
            bindingSource.DataSource = _criteriasBindingList
        Else If (String.IsNullOrEmpty(str1)) Then
            bindingSource.DataSource = _criteriasBindingList.Where(Function(c) c.Criteria2.ToLower().Contains(str2)).ToList()
        Else If (String.IsNullOrEmpty(str2)) Then
            bindingSource.DataSource = _criteriasBindingList.Where(Function(c) c.Criteria1.ToLower().Contains(str1)).ToList()
        Else
           bindingSource.DataSource = _criteriasBindingList.Where(Function(c) c.Criteria1.ToLower().Contains(str1) AndAlso c.Criteria2.ToLower().Contains(str2)).ToList()
        End If
    End Sub
    

    All in all, you will need to apply each and every criteria that's applicable.