2

I'm using .NET with Windows Forms, but I believe there may be similar concerns with other toolkits.

Suppose we have a list of objects of a certain type. Using an example to make the following easier to read, suppose there is a Category class to represent them. We display a list of them to allow a user to filter articles by category. Binding the ListBox component to a data source of Category objects is a way to do so.

What would be the best way to add an entry labelled "All" in the same ListBox? Assume that it has to be in the list, and not as a separate option like a radio button.

I can think of the following approaches, but all of them seem to have a drawback.

  1. Create a "dummy" Category instance named "All" and an invalid ID.

This is the easiest way but it feels wrong conceptually, as "All" is not actually a category (no article belongs to a category named that). Also, depending on the framework the UI may not be allowed to create Category objects.

  1. Don't use data binding at all; populate the list box with strings and use the selection's index to get the object from the data source.

This may beat the point of having data bound controls, and adds potential problems: What if we also want to add a "None" entry in the future? We'll have to increment the list box's selected index by 2 instead of 1 to get the correct object from the data source.

  1. Use an intermediate class, CategoryListItem, to populate the list box with. It has a reference/pointer to a Category which is null for dummy entries.

This one may be more elegant, but it adds the overhead of creating a new list of CategoryListItem instances for every list of Category instances we want to display.

Is one of the above a recommended way to data bind to such a component, or perhaps a way I haven't thought of?

  • 1
    thanks for the upvote, but I will now remove my answer, and possibly rewrite it and un-remove it later, because I got carried away and ended up answering the wrong question. Complete brain failure. – Mike Nakis Sep 23 '15 at 17:10
1

Normally, a single-selection listbox offers a list-of-values interface for setting up, and a single-value interface for querying its state. You give it a list of values to present, and it tells you which one of them is selected. (Regardless of whether it is always-open or drop-down.) It is the same as a group-of-radio buttons: only one of the radio buttons may have a bullet in it at any given time.

What you want instead, is a control which again offers a list-of-values interface for setting up, but a set-of-values interface for querying its state. The range of possible values is again fixed, but you may select as many of them as you want, including none of them, or all of them. So, clearly, this control is backed by a Set data type. The kind of control which is normally used for that sort of thing is a group of checkboxes, or a listbox with checkmarks, or, in the old days, a multi-selection listbox. (That was before they realized that users can't be bothered with holding down the Ctrl key while clicking with the mouse.)

Now, for some reason you have decided to use a regular listbox for this job, which means that you do not care to give your user the ability to select two categories at the same time, all you want them to be able to do is select either one category, or all categories. (And perhaps no categories in the future.) That's fine, as long as you realize that this choice of yours should only affect the appearance and the user experience that the control offers to the user, it should not affect the interfaces that the control provides to your application. From your application's point of view, this control should still implement a list-of-values interface for setting up, and a set-of-values interface for querying its value. The question of whether it will contain a checkbox next to each choice, or special "select all" and "select none" entries, should be of absolutely no concern to your application. It should be possible for you to replace it in the future with a group of checkboxes, without altering the way your application interacts with it.

So, what I would do if I was in your shoes is that I would sublcass the existing listbox control, (or I would create an entirely new control which aggregates the existing control, I do not remember right now which approach is recommended in WinForms,) to create a new multi-selection-listbox control which looks like a list, but offers a set-of-values interface for querying its value.

I would have the new control add to itself the one or two extra pseudo-items needed so that it can easily select all of its contents, or none of its contents. That would most closely correspond to option #1 above, but it is irrelevant, because this approach is a lot more than doing option #1. Note how, when describing this control, we are now talking about "items" and not "categories": this is a general purpose control which can be used for anything you can think of besides categories: reusable, and also replaceable with something better if the need arises in the future.

The point behind my recommendation is to avoid ruining your application logic with fine-grained user interaction considerations. Keep things separate, and let the user experience be the sole responsibility of the GUI controls themselves. Let it be their problem. GUI controls should abstract the way they work behind nice, clean, and minimalistic interfaces that correspond to simple abstract data types, and the application logic should only have to interact with these abstract data type interfaces.

  • I like the suggestion for dealing with "commands" and entries separately. However I disagree with the idea that a "dummy" entry should never be in the same control. I would agree if it was an entry that created something new (which would fit better in a button) but in my example it is just another option (although one that doesn't correspond to a data object) and a list of options is where it belongs. – George T Sep 23 '15 at 15:06
  • @GeorgeT I rewrote my answer to get rid of references to "commands", since you are not using commands. (You might end up using commands in the future, if you decide to give users the ability to add a new category on the spot: the "Add New Category" option in the list box would be a command. We see things like that in Web interfaces. These rewritten recommendations should be useful to you in that case, too) – Mike Nakis Sep 23 '15 at 18:02
0

You seem to be confusing the concept of a business model with a view model. If the Category class is used as a business model, then an "All" entry makes no sense. However, if you are databinding them directly to the UI, then what you have is actually a view model. An "All" entry makes perfect sense here, because a view model simply models the data you want to get onto the screen, regardless of what it might be.

Your options 1, 2 and 3 are all attempts to make a distinction between these two types of model. As for the best one to pick, well, that depends on how you want to architect the rest of your application. Personally, I would make it explicit, and have two classes, e.g.

  • Models.Category - the underlying business data
  • ViewModels.Category - the business data plus an "All" line

Your presentation code is then responsible for translating back and forth between the two classes. Your view code only knows about ViewModels.Category, and your repository/back-end code only knows about Models.Category.

  • Unless I'm misunderstanding, you seem to be describing the 3rd option I suggested (in other words, create a new class whose instances can describe either the same thing as the business model class or a dummy entry). Could you clarify how it's different? – George T Sep 23 '15 at 14:27
  • @GeorgeT: I'm suggesting a 4th option - two separate classes that know nothing about each other, with the presentation code translating between Models.Category and ViewModels.Category. There is no real best answer here, it's about how you choose to architect your application. You might be writing a simple utility, in which case you could go for options 1 or 3, or you might be writing a large n-tier enterprise app, in which case you really need the encapsulation of option 4. – Christian Hayter Sep 24 '15 at 7:48
0

Do not bind your objects directly to the ListBox (I suppose you did that by adding each category object separately, because I don't know any way to set the DataSource property to a list of objects).

My suggestion:
Create an Enum EnumCategory, which contains values of all possible categories, including ‘all‘ and 'none' and whatever you like. Bind this Enum as DataSource to the ListBox (also works for a combobox).
By this you can enhance your Enum whenever you like without problems.

If you also need comfortable names (including spaces and other chars that do not belong into variable names) or multilanguage support, let me know. Both can be added easily.

  • You can add a list of objects as a datasource. List<MyClass> list = GetList(); listBox1.DataSource = list; (better to use a BindingList<> though, or a BindingSource inbetween). Also, an Enum is definitely not a good idea if you want objects loaded dynamically. – George T Sep 24 '15 at 22:35
  • Thanks for the info. I agree that there might be better solutions for dynamic listbox population, but I can't see that he is filling dynamically. The solution could be sufficient. – Tobias Knauss Sep 25 '15 at 19:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.