Based on a post by a user who wondered how to "generize" this sample, I did some investigation. The included sample attempts two methods to handle this. The attached project has the results.Background
The problem this solution is addressing is when a table has a FK to another table that is very large...too big for a combo (which is a great way to handle this for things like categories, regions ect...small number of fairly defined values). This sample allows you lookup the FK using the SF BrowseDialog.
The sweet thing about the BrowseDialog is that is pretty much defined and used declaratively. SF has some sweet designer forms to setup it up. When using it, there is little code (you have to call it and get the result...see the click handler in the user control).
But to do this sort of work you always have to define two things: what are you searching and how. If you want this to be generic, you still have to, at some point, define these two things. In the SF world, these are defined via a BrowseDialog (it defines both the BO and the search settings). it also happen to take care of the actual work of performing the search, which is very nice. Using a BrowseDialog makes searching data pretty easy.Original Solution
If you look at Ivan's code, what he's done is first define subclasses of the BrowseDialog for specific searches. I.e. the CustomersBrowseDialog is subclassed and he's defined the BO type (CustomersBO) and setup what is going to get searched (first and last names). The code is trivial:
Public Class CustomersBrowseDialog
However, if you open the designer and look at the properties, this is where he's configured the browse dialog with the type and search fields. Basically this thing is completely configured via designers.
Then he builds a user control based on this. Here he drops on a CustomersBO and his custom browse dialog (already configured), sets the BO to be the BusinessObjectToPopulate on the dialog and writes the code to manage the lookup.
The strengths of this are that the BrowseDialog is really, really easy to setup via the designer. By creating inherited classes for each dialog that would be needed, this is really simplifies life (I tried doing the configuration in code...not as easy...it's a complicated control and the designer hides all that from you).
The user control he provided is also nice, but it's specific to Customers. This means that if you need a widget lookup, you'd need to recreate this control for widgets. Creating the inherited BrowseDialog would be cake, but the user control has a fair bit of code in it that needs to be recreated. This is what we are trying to solve with now.Solution 1: Generics
The GenericLookupControl is a generic control that requires a type argument that defines the BrowseDialog type. Since the BrowseDialog class will have both the business object type and the search setup defined, nothing else is needed. I also parametrized the description shown, so you can setup a String.Format template and then define the fields used to fill it.
There's one catch with this solution: you can't drop a generic control on a form. It has no way for the designer to know what the generic type(s) is. So, this requires you to subclass the generic control for each BrowseDialog desired. The subclass is just a class definition (all it needs to work is the BrowseDialog type):
Public Class CustomersLookupControl
Inherits GenericLookupControl(Of CustomerBrowseDialog)
Once this class is created and the project containing it are built, drop it on a form, set the template and fields for the description, setup binding and you're done.
However, I not sure I like having my project filled with a million three-line classes to handle this. It doesn't feel like it makes life easier. (It was fun to build though.) Plus, this requires that you subclass the BrowseDialog, even if just used once. The next solution builds on this to allow a single lookup control to be used for any lookup. Solution 2: General Lookup using a BrowseDialog Property
The GeneralLookupControl uses most of the code from the GenericLookupControl, with one significant change: it use property to allows the user to set the BrowseDialog to be used. This has a bunch of advantages:
- It can be used with any BrowseDialog. If you want to sub class the BrowseDialog to standardize a particular search, no problem. If you have a one off search, no problem.
- As a consequence, you don't need as many classes, your project is simpler.
- It is easy to drop general lookup control and a browse dialog on the form and configure the browse dialog, then assign it to the lookup control.
- Only one lookup control. One place to change behavior, or fix bugs. Conclusion
The lesson for me was to be careful what you try to encapsulate. Encapsulate that which does not change. Expose that which does. As I recall, this is a basic principal of OOP. The last solution exposes a property that allows you to set the BrowseDialog, which is what will be changing (that and its bindings of course). The generic solution tried to hide that, but because it was changing all the time, actually saved no work and potentially complicated the project.
Basically, as Ivan said (in the original post), don't fight the framework.