What\'s the best way to go about providing a simple search capability for \"business objects\" in a .NET WinForms application?
By \"simple search\" I mean something
I don't know about the "best" way (I'd work at Google if I did). Given that, though, I did implement something similar in a proof-of-concept/customer demo a few months back that did the trick. Note that I was able to constrain the problem domain pretty effectively, especially wrt the immediately searchable dataset's size, so that performance wasn't an issue.
I created a FilterableListView
UserControl. I used a ListView in Detail mode, I dropped a TextBox immediately above it and used platform interop to give it some CueText (something like "Filter" or "Search"). I then updated the contents of the ListView
from a background thread (using the equivalent of my implementation of SafeInvoke) if there was a 0.5 second delay since the last TextChanged event from the filter box.
I did a simple, case-insensitive substring match against the contents of a specified field in the ListView
, it was quick, simple, and effective. I found Linq to Objects to be very useful.
A few things I would have done better for a more production-ready implementation:
IFilterable
interface?I think your approach of use a "Contains" method in each object is quite usefull.
You can give "weight" to the members of the object so that if the contains method finds a match, give a sort of "Score" as a return.
Other thing to take into account is whether the match is a full match or not... and assign more or less point to that score.
If you search accross multiple types of objects... may be you can assign higher values to the main objects (more business centric objects) in order to give them more priority.
Just thoughts...
As long as you don't have too many objects it would make sense to do what you're describing, just by looping through each object. You could go with a regular expression instead of just Contains to give it a little more flexibility. Contains is going to give you a match on an object instead of just a string value of a property inside your object. Matching the string would probably be more useful to you.
One thing you could do is make a method in your objects that is simply a concatenated string of all of the strings in that object you would want to search. Then apply the regular expression to search the value that results from that method. It's easily not going to be the greatest performing solution, but it would be quick and easy. Like I said, as long as you don't have too many objects it will be fine.
I would implement a simple interface on every class that simply returns a list of search terms describing the instance. Then you are able to get all your objects, ask them for their search terms and rank them based on the user supplied search terms.
This is close to your Contains interface idea, but keeps more logic out of the business classes. You could even examine the objects via reflection and may be just add some user attributes to the properties to give the search engine some hints which properties to include in the search.
But be aware that you will have to evaluate every search over all your objects. This is going to become really slow beyond about one hundred or so objects if you use a complex ranking function. Using reflection will make things even worse.
Another problem to solve is how to handle the search result in a meaningful way. If you have quite a few different classes, it might be a non-trival task to display the results and navigate the user to a place in the application where he can do something with that objects.