# .NET and More > WPF, WCF, WF >  [RESOLVED] Filtering WPF viewsource versus winforms bindingsource

## trevorjeaton

Hi all,

As you no doubt can see by the postings i've been making, i'm trying to get my head around the differences between wpf and winforms development.  The lights are slowly coming on, but as i encounter each problem, a new speedbump in the road to learning presents itself.  Hence my next question.

In my previous winforms app, i had a bindingsource attached to a combobox, and based on a variable i would filter that bindingsource to in turn filter the items in the combobox - example:



```

if salesrep = true
   CustomerBindingSource.filter = "Territory = '" & territory & "'"
else
   CustomerBindingSource.removefilter()
endif
```

that code would filter the contents of the combobox to only be the currently logged in sales reps customers.

On the WPF side in the window_activated event, i've added the following:



```

 Dim CustomerViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CustomerViewSource"), System.Windows.Data.CollectionViewSource)

If salesrep = True 
   CustomerViewSource.View.Filter = territory  'show only that reps customers
Else
    CustomerViewSource.View.Filter = Nothing  'show all customers
End If
```

which of course does not work.....so my question is, is a viewsource the route i should take to try and duplicate the behavior of a bindingsource i mentioned above or is there another route, and if so, how do you filter the viewsource if its the right way to go?

as usual, thanks a million.

----------


## trevorjeaton

okay, so i think i'm getting closer, but still not successful.  I added the "Filter" tag in the xaml where my CustomerViewSource is defined as follows:



```

<CollectionViewSource x:Key="CustomerViewSource" Source="{Binding Path=Customer, Source={StaticResource MyDataSet}}" Filter="FilterCompanies" />
```

then added my function on the codebehind in mainform.xaml.vb as follows:



```

Private Sub FilterCompanies(ByVal sender As Object, ByVal e As FilterEventArgs)
    Dim companyname As String = TryCast(e.Item, String)
    If canseeall = True Then
         e.Accepted = True
    Else
         e.Accepted = territory
    End If

End Sub
```

in the code above, canseeal is a public variable that that is associated with the user account and is a boolean that when true means "don't filter anything" and show all customers - territory is also a public variable for the logged in user that is attached to the customerviewsource as well (its one of the fields in the database to determine what territory that customer falls under)

Thus, when a user logs in, it should check the canseeal variable and trigger a filter to only show customers in that users territory.

The above code of course craps out and i'm not sure why........but i'm also digging like crazy on this one to find the wpf equivalent of what was a one line piece of code in winforms - looks like the learning curve is going to be intense on this transition.....

----------


## chris128

I made a WPF app a while ago that had a listbox that could be filtered - I dont remember exactly how I did it but I'm sure it did not involve a ViewSource and was relatively simple, so I'll dig out the code tonight and post it here.

----------


## chris128

Actually I just had a little play around and came up with this, which I think is very similar to what I had done in my previous app. Hopefully it helps with what you are trying to do - note that it might look long but I've included absolutely everything and plenty of comments so that you can see exactly what is going on. In reality its only a couple of lines that you actually need to do the filtering.


vb Code:
Class MainWindow 
     'An example class that we will create instances of and add to the combobox
    Private Class SomeItem
        Public Property Territory As String
        Public Property SomeOtherProperty As Integer
        Public Overrides Function ToString() As String
            Return Territory
        End Function
    End Class
      'Add some items to the combobox when the window loads and set the territory of each item
    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        cbo1.Items.Add(New SomeItem With {.Territory = "Somewhere"})
        cbo1.Items.Add(New SomeItem With {.Territory = "Somewhere"})
        cbo1.Items.Add(New SomeItem With {.Territory = "SomewhereElse"})
        cbo1.Items.Add(New SomeItem With {.Territory = "SomewhereElse"})
        cbo1.Items.Add(New SomeItem With {.Territory = "AnotherSomewhereElse"})
    End Sub
     'When we click Button1, the filter gets set so that only items that have a territory that matches
    'what is entered into Textbox1 will be shown in the combobox
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
        cbo1.Items.Filter = New Predicate(Of Object)(AddressOf FilterFunction)
    End Sub
     'When we click Button2, the filter gets cleared so all items in the combobox are visible
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button2.Click
        cbo1.Items.Filter = Nothing
    End Sub
     'This function will get called once for each item in the combobox when we apply the filter in the Button1 click event handler
    Private Function FilterFunction(ByVal CurrentItem As Object) As Boolean
        If DirectCast(CurrentItem, SomeItem).Territory = TextBox1.Text Then
            'This item has a territory that matches the text in textbox1 so return True so that it is included in the filter
            Return True
        Else
            Return False
        End If
    End Function
 End Class

----------


## trevorjeaton

much appreciated - i'm gonna keep steamrolling forward here too - i removed the filter tag in the xaml (i'm trying to save any eye candy for xaml only and use code for any functionality only)

and I've added this to the window_activated event (accesslevel and canseeall are just booleans attached to the user when they log in):



```

 Dim view As ListCollectionView = CType(CollectionViewSource.GetDefaultView(cbCompanyName.ItemsSource), ListCollectionView)
        
If accesslevel = True Or canseeall = True Then
    view.Filter = Nothing
Else
    view.Filter = New Predicate(Of Object)(AddressOf FilterCompanies)
End If
```

then i created the function 'FilterCompanies' as follows:



```

Public Function FilterCompanies(ByVal item As Object) As Boolean
        Dim territory As String = CType(item, String)
        Return territory = territory
End Function
```

one of the obvious unsolved problems with this code so far is that i haven't referenced anything about the territory field on the data side of things in the combobox - perhaps i should set its displaymember to Company Name, which it already is, and then perhaps set the valuemember to territory......

----------


## trevorjeaton

that's awesome, thanks!  diving in to it now.....will post the results as soon as i get through it.....

----------


## chris128

No worries, let me know how you get on.

Oh and also, was my last reply in this thread any use to you? http://www.vbforums.com/showthread.php?t=628818

----------


## trevorjeaton

okay, almost there - here's what i have in window_activated:



```

If accesslevel = True Or canseeall = True Then
    cbCompanyName.Items.Filter = Nothing
Else
    cbCompanyName.Items.Filter = New Predicate(Of Object)(AddressOf FilterCompanies)
End If
```

and the function:



```

Public Function FilterCompanies(ByVal item As Object) As Boolean
        If DirectCast(CurrentItem, CompanyName).Territory = territory Then
            Return True
        Else
            Return False
        End If
End Function
```

i'm erroring out on "currentitem is not declared and a second error of of type 'companyname' is not defined.

The combobox is databound, and is displaying the company name field and that table also has a field in it called territory - the public variable territory is what i am trying to filter the table on against the territory field in the table......

----------


## trevorjeaton

and yes, for your post #7 above, it was perfect - it gives a very clear parallel between the two technologies - the winforms guys will hopefully get great use out of these postings. you're a winforms savior when it comes to looking for migration advice to wpf.... :-)

----------


## chris128

> ```
> 
> Public Function FilterCompanies(ByVal item As Object) As Boolean
>         If DirectCast(CurrentItem, CompanyName).Territory = territory Then
>             Return True
>         Else
>             Return False
>         End If
> End Function
> ...


Thats because as the error says, you have not declared CurrentItem anywhere in that function. You have an argument named "item" but then in the DirectCast call you pass in an object called "CurrentItem"... which doesnt exist. You should be passing "item" in to the DirectCast call instead.

As for the second issue, CompanyName not existing, that is because you presumable do not have a class named CompanyName anywhere, which leads me to the next question - what is your combobox databound to? As you can see in my example I defined a class named SomeItem which I then created instances of and added to the combobox - its these instances that hold information (such as the territory) that we want to see in the combobox and its this type (SomeItem) that my filter function casts the argument to by using DirectCast. So you need to work out what your equivalent type is - I presume you must have defined a similar type and created a collection of them which you then bind the combobox to?

----------


## trevorjeaton

makes sense - my combobox is ultimately bound to a sql table if you follow it all the way back to the database - but its source is "CustomerViewSource"

so having said that, how do we pull the various fields from that table (or viewsource in this case) because i'll be doing processing on the company name, the territory, etc etc eventually and using many of the fields in the customer table for processing.

----------


## trevorjeaton

lol, duh, i shoulda caught that one......okay so i fixed it to reflect 'item,' but what about the second argument to point it to the territory field of the database?

----------


## trevorjeaton

its looking for an "Object as Type" for the second argument - which i'm presuming will be how we get the territory from the view/table, then all is well.....?  i'm just scratching my head as to how - i'm going through the intellisense and calling the CustomerDataSet and CustomerTable adapter, but no joy.

the table itself is called customer, and the territory field in that table is just called territory...nothing fancy....also, this combobox was added to the window by drag and drop databinding where i simply pulled it over from the datasources window and dropped it on to the grid.

----------


## chris128

Ah well the fact that you are binding to a DataSet makes things a little more tricky for me as I've not done that. However, I'm sure there must still be a way to do it... we just need to know what Type each item in the Combobox actually is and then we should be able to work out how we can get the Territory from that (hopefully).
If you just stick this in your FilterCompanies function (comment out what is already in there for now and ignore any warnings etc as this is just a very temporary test) what does it show in the messagebox?

vb Code:
MessageBox.Show(item.GetType.ToString)

----------


## trevorjeaton

hmmmm....the messagebox isn't firing - its like it isn't calling the function.....i threw a breakpoint at the messagebox and at the call to the function - would it make a difference that the code that calls the function is in the window_activated event versus the window_loaded?

----------


## chris128

> hmmmm....the messagebox isn't firing - its like it isn't calling the function.....i threw a breakpoint at the messagebox and at the call to the function - would it make a difference that the code that calls the function is in the window_activated event versus the window_loaded?


Well just try sticking the code where you set the filter in a button click event handler as a test

----------


## trevorjeaton

sorry about the delay - my company was doing inventory today and based on our locations, it looks like a pretty good time zone difference.

okay, so i attached the call to a button clickevent as follows:



```

Private Sub btnTest_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnTest.Click
        cbCompanyName.Items.Filter = New Predicate(Of Object)(AddressOf FilterCompanies)
End Sub
```

The error that triggered was "NotSupportedException was unhandled", followed by a "Specified method is not supported"

the function only calls the messagebox, all other code is commented out for the moment as per your instructions

----------


## chris128

Hmm I guess you cant do it that way when bound to a dataset/viewsource then  :Frown:  sorry I've only ever done it when binding to a list or collection and assumed it would be the same. Have you had a look for any tutorials online that cover this kind of thing? I'm sure its a fairly common thing to want to do..

----------


## trevorjeaton

yeah i'm still digging - strange that a one-liner winforms solution is turning in to the equivalent of a phd thesis in wpf......i'll post results if i find them - thanks for everything

----------


## chris128

Yeah unfortunately with any new technology there are going to be some things that are just not as easy or simple to do. I'm sure when you find out how to do it then it will make sense, but probably just not very intuitive or obvious (as seems to be the case with a lot of things in WPF). You might get some joy from the "WPF Forms Over Data" videos on MSDN: http://msdn.microsoft.com/en-us/vbasic/ff718210.aspx
or the wealth of WPF videos here: http://windowsclient.net/learn/videos_wpf.aspx - perhaps this one in particular (though I haven't watched it so can't say exactly how relevant it is) : http://windowsclient.net/learn/video.aspx?v=287008

----------


## trevorjeaton

got it!  what a pain lol.....

it turns out its faster and easier (and also a one liner) to just filter the dataset itself versus the viewsource - here's the code for the class itself before window_initialized:



```

Class MainWindow

Private customerdata As New CustomerDataSet
Private tacust As New CustomerDataSetTableAdapters.CustomerTableAdapter
...
...
End Class
```

then in the window_initialized event i filled the table adapter and then filtered it based on the condition - in this case the field name is territory and a global variable that contains a string that holds the sales reps territory when they log in is used for the filter.



```

Me.tacust.Fill(Me.customerdata.Customer)

If accesslevel = True Or canseeall = True Then
    customerdata.Customer.DefaultView.RowFilter = Nothing
Else
    customerdata.Customer.DefaultView.RowFilter = "territory = '" & territory & "'"
End If
```


Many thanks to Chris and all others that helped on this one.....

----------


## chris128

Cool thanks for sharing the solution  :Smilie:

----------

