<?xml version="1.0"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>BindingView Collection Class</Title>
      <Author>Andrew Renner</Author>
      <Shortcut>BSBindingView</Shortcut>
    </Header>
    <Snippet>
      <References>
        <Reference>
          <Assembly>BroncoSolutions.Components.dll</Assembly>
        </Reference>
      </References>
      <Imports>
        <Import>
          <Namespace>System.ComponentModel</Namespace>
        </Import>
        <Import>
          <Namespace>System.Reflection</Namespace>
        </Import>
        <Import>
          <Namespace>BroncoSolutions.Components.Windows.Collections</Namespace>
        </Import>
      </Imports>
      <Declarations>
        <Literal>
          <ID>BindingListClassName</ID>
          <ToolTip>Enter the class name</ToolTip>
          <Default>ClassName</Default>
        </Literal>
        <Literal>
          <ID>CollectionOfWhat</ID>
          <ToolTip>Enter the name of the object this is a collection of.</ToolTip>
          <Default>Object</Default>
        </Literal>
      </Declarations>
      <Code Language="VB" Kind="type decl"><![CDATA[#Region " $BindingListClassName$"
        Public Class $BindingListClassName$
            Inherits BindingList(Of $CollectionOfWhat$)
            Implements IBindingListView
            'Implements IRaiseItemChangedEvents

#Region " Private Variables "

            Private _Sorted As Boolean = False
            Private _Filtered As Boolean = False
            Private _PropertyName As String
            Private _FilterString As String = Nothing
            Private _SortDirection As ListSortDirection = ListSortDirection.Ascending
            Private _SortProperty As PropertyDescriptor
            Private _SortDescriptions As New ListSortDescriptionCollection()
            Private _OriginalCollection As New List(Of $CollectionOfWhat$)
#End Region

#Region " Add Support "

            Protected Overrides Function AddNewCore() As Object
                Dim e As New $CollectionOfWhat$()
                Add(e)
                Return e
            End Function
#End Region

#Region " Constructor "
            ''' <summary>
            ''' Initializes a new instance of the $BindingListClassName$ class.
            ''' </summary>
            Public Sub New()
                MyBase.New()
            End Sub

            ''' <summary>
            ''' Initializes a new instance of the $BindingListClassName$ class.
            ''' </summary>
            ''' <param name="originalCollection"></param>
            Public Sub New(ByVal originalCollection As List(Of $CollectionOfWhat$))
                MyBase.new(originalCollection)
            End Sub
#End Region

#Region " Find Support "

            Protected Overrides Function FindCore(ByVal prop As PropertyDescriptor, ByVal key As Object) As Integer
                For Each _currentItem As $CollectionOfWhat$ In Me.Items
                    If prop.GetValue(_currentItem).Equals(key) Then
                        Return IndexOf(_currentItem)
                    End If
                Next

                Return -1
            End Function
#End Region

#Region " Filter Support "


            Public Property Filter() As String Implements IBindingListView.Filter
                Get
                    Return _FilterString
                End Get
                Set(ByVal value As String)
                    If String.IsNullOrEmpty(value) Then
                        RemoveFilter()
                    Else
                        _FilterString = value
                        _Filtered = True
                        UpdateFilter()
                    End If
                End Set
            End Property

            Public Sub RemoveFilter() Implements IBindingListView.RemoveFilter
                If _Filtered Then
                    _FilterString = Nothing
                    _Filtered = False
                    _Sorted = False
                    _SortDescriptions = Nothing
                    _SortProperty = Nothing
                    Clear()
                    For Each _currentItem As $CollectionOfWhat$ In _OriginalCollection
                        Add(_currentItem)
                    Next

                    _OriginalCollection.Clear()
                End If
            End Sub



            Public ReadOnly Property SupportsFiltering() As Boolean Implements IBindingListView.SupportsFiltering
                Get
                    Return True
                End Get
            End Property

            Protected Sub UpdateFilter()
                Dim propDesc As PropertyDescriptor = Nothing
                Dim value As Object = Nothing
                Dim search() As String = BroncoSolutions.Components.StringLibrary.SplitStringIntoArray(_FilterString, " ")
                Dim field As String = search(0).ToString
                Dim logic As String = search(1).ToString
                Dim termsb As New StringBuilder
                Dim term As String
                For i As Integer = 2 To search.Length - 1
                    termsb.Append(String.Format(" {0}", search(i).ToString))
                Next

                ' trim whitespace from string
                term = termsb.ToString.Trim

                If _OriginalCollection.Count = 0 Then
                    _OriginalCollection.AddRange(Me)
                End If

                ' Get list to sort
                Dim _CurrentCollection As New List(Of $CollectionOfWhat$)(Me)

                For Each _currentItem As $CollectionOfWhat$ In _CurrentCollection
                    If IsNothing(propDesc) Then
                        ' Get a property descriptor for the filter property
                        propDesc = TypeDescriptor.GetProperties(_currentItem).Item(field)

                        If IsNothing(propDesc) Then
                            Throw New Exception(String.Format("The property {0} doesn't exist.", field))
                            Exit For
                        Else
                            Clear()
                        End If
                    End If

                    value = propDesc.GetValue(_currentItem)
					if Not IsNothing(value) then
	                    Select Case logic
    	                    Case "Equal"
        	                    If value.ToString = term Then
            	                    Add(_currentItem)
                	            End If
                    	    Case "NotEqual"
                        	    If value.ToString <> term Then
                            	    Add(_currentItem)
	                            End If
    	                    Case "Greater"
        	                    If value.ToString > term Then
            	                    Add(_currentItem)
                	            End If
                    	    Case "Less"
                        	    If value.ToString < term Then
                            	    Add(_currentItem)
	                            End If
    	                    Case "GreaterOrEqual"
        	                    If value.ToString >= term Then
            	                    Add(_currentItem)
                	            End If
                    	    Case "LessOrEqual"
                        	    If value.ToString <= term Then
                            	    Add(_currentItem)
	                            End If
    	                    Case "StartsWith"
        	                    If value.ToString.StartsWith(term) Then
            	                    Add(_currentItem)
                	            End If
                    	    Case "EndsWith"
                        	    If value.ToString.EndsWith(term) Then
                            	    Add(_currentItem)
	                            End If
    	                End Select
					End If
                Next
            End Sub

#End Region

#Region " Notification Support "
            '''' <summary>
            '''' ''' If you return true to indicate that you do raise item changed events, it is expected that you will raise ListChanged events when the items in your collection change. If the items in your collection implement the INotifyPropertyChanged interface as described earlier, this will happen automatically. But there is a way that you can continue to support item changed events even if the objects in your collection don't support INotifyPropertyChanged. However, you should be judicious about implementing the IRaiseItemChangedEvents interface: it can cause a significant performance hit for large collections, because you have to reflect on each object as it is added to your collection.
            '''' </summary>
            '''' <value></value>
            '''' <returns></returns>
            '''' <remarks>Uncomment these methods as well as the implements statement in directive. Implementation of Implements IRaiseItemChangedEvents.RaisesItemChangedEvents </remarks>
            'Public Overloads ReadOnly Property RaiseListChangedEvents() As Boolean
            '    Get
            '        Return True
            '    End Get
            'End Property

            'Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal newItem As $CollectionOfWhat$)
            '    For Each propDesc As PropertyDescriptor In TypeDescriptor.GetProperties(newItem)
            '        If (propDesc.SupportsChangeEvents) Then
            '            propDesc.AddValueChanged(newItem, AddressOf OnItemChanged)
            '        End If
            '    Next
            '    MyBase.InsertItem(index, newItem)
            'End Sub

            Protected Overrides Sub RemoveItem(ByVal index As Integer)
                Dim _currentItem As $CollectionOfWhat$ = Items(index)
                ' uncomment this section to use change events
                'Dim propDescs As PropertyDescriptorCollection = TypeDescriptor.GetProperties(_currentItem)
                'For Each propDesc As PropertyDescriptor In propDescs
                '    If propDesc.SupportsChangeEvents Then
                '        propDesc.RemoveValueChanged(_currentItem, AddressOf OnItemChanged)
                '    End If
                'Next
                RemoveItemInternal(index)
            End Sub

            Private Sub RemoveItemInternal(ByVal index As Integer)
                MyBase.RemoveItem(index)
            End Sub

            'Public Sub OnItemChanged(ByVal sender As Object, ByVal e As EventArgs)
            '    Dim index As Integer = Items.IndexOf(DirectCast(sender, $CollectionOfWhat$))
            '    OnListChanged(New ListChangedEventArgs(ListChangedType.ItemChanged, index))
            'End Sub
#End Region

#Region " Overloads "
            Public Overloads ReadOnly Property AllowNew() As Boolean
                Get
                    Return CheckReadOnly()
                End Get
            End Property

            Public Overloads ReadOnly Property AllowRemove() As Boolean
                Get
                    Return CheckReadOnly()
                End Get
            End Property

            Private Function CheckReadOnly() As Boolean
                If _Sorted OrElse _Filtered Then
                    Return False
                Else
                    Return True
                End If
            End Function
#End Region

#Region " Sorting Support "
            Protected Overrides Sub ApplySortCore(ByVal prop As PropertyDescriptor, ByVal direction As ListSortDirection)
                _SortDirection = direction
                _SortProperty = prop

                Dim pc As New PropertyComparer(Of $CollectionOfWhat$)(prop, direction)

                ApplySortInternal(pc)
            End Sub

            Private Sub ApplySortInternal(ByVal pc As PropertyComparer(Of $CollectionOfWhat$))
                If _OriginalCollection.Count = 0 Then
                    _OriginalCollection.AddRange(Me)
                End If

                ' Get list to sort
                Dim _CurrentCollection As List(Of $CollectionOfWhat$) = Me.Items

                ' Apply and set the sort, if items to sort
                If _CurrentCollection IsNot Nothing Then
                    _CurrentCollection.Sort(pc)

                    _Sorted = True
                End If

                Me.OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
            End Sub

            Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
                Get
                    Return True
                End Get
            End Property

            Protected Overrides ReadOnly Property IsSortedCore() As Boolean
                Get
                    Return _Sorted
                End Get
            End Property

            Protected Overrides Sub RemoveSortCore()
                If _Sorted Then
                    Clear()

                    For Each _currentItem As $CollectionOfWhat$ In _OriginalCollection
                        Add(_currentItem)
                    Next

                    _OriginalCollection.Clear()
                End If

                _Sorted = False
                _SortDescriptions = Nothing
                _SortProperty = Nothing
            End Sub

            Protected Overrides ReadOnly Property SortDirectionCore() As ListSortDirection
                Get
                    Return _SortDirection
                End Get
            End Property

            Protected Overrides ReadOnly Property SortPropertyCore() As PropertyDescriptor
                Get
                    Return _SortProperty
                End Get
            End Property

            Protected Overrides ReadOnly Property SupportsSearchingCore() As Boolean
                Get
                    Return True
                End Get
            End Property


            Public Sub ApplySort(ByVal sorts As ListSortDescriptionCollection) Implements IBindingListView.ApplySort
                _SortProperty = Nothing
                _SortDescriptions = sorts
                Dim pc As New PropertyComparer(Of $CollectionOfWhat$)(sorts)

                ApplySortInternal(pc)
            End Sub
            Public ReadOnly Property SortDescriptions() As ListSortDescriptionCollection Implements IBindingListView.SortDescriptions
                Get
                    Return _SortDescriptions
                End Get
            End Property

            Public ReadOnly Property SupportsAdvancedSorting() As Boolean Implements IBindingListView.SupportsAdvancedSorting
                Get
                    Return True
                End Get
            End Property
#End Region

        End Class
#End Region]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>
