Over on our forums, many of you have reported difficulty with the ComboBox control when using RIA Services. Kyle McClellan (@KyleMcClellan) suggested that we drill into various ComboBox scenarios to see what works well and what doesn’t. Our goal was to produce some samples that address common scenarios, and to offer general guidance for ComboBox usage.
Here are a few scenarios we looked at:
- Async loading of ItemsSource with a SelectedItem/SelectedValue binding;
- Cascading drop-downs such as selecting Year - Make - Model for a car;
- Binding a ComboBox to a list of non-Entity types, such as an IEnumerable<string>.
Should I Use DomainDataSource for a ComboBox?
Short answer: No
While I rejected the notion at first, as did the DomainDataSource’s PM, Deepesh Mohnani (@DeepeshM), we all came to the conclusion that the DomainDataSource control doesn’t do a very good job integrating with the ComboBox for the above scenarios. There are a few things getting in the way.
Async Data Loads
When you bind the ComboBox’s ItemsSource to a DomainDataSource and then invoke the load, the ComboBox doesn’t handle bindings to the SelectedItem or SelectedValue because the item/value doesn’t yet exist in the list. The selection is bound synchronously, but the items are loaded in asynchronously. This mismatch will cause you all sorts of frustration.
Load Blocking
The DomainDataSource halts its data loads once there are changes to the DomainContext. There is some background on this issue in this blog post, where I solicited feedback about mixing data loads with pending changes. We made the decision to block loads once changes exist, to prevent some nasty conflicts from occurring.
The load blocking becomes a problem with ComboBox because you are usually editing or adding an entity—as soon as you’ve started doing this, HasChanges becomes true, and subsequent loads for the DomainDataSource will be blocked. This problem is exacerbated when dealing with cascading drop-downs where you want to allow the user to drill down to make a selection.
Non-Entity Types
DomainDataSource has no support for loading lists scalar types—it’s limited to EntityQuery operations. So if you have an [Invoke] operation on the server that returns a collection of scalar values, there’s no way to use the DomainDataSource to load and expose this data.
But It Works For Me
We’ve seen (and written) many samples where DomainDataSource is used to successfully populate a ComboBox, but it really seems that once you grow beyond the simplest scenarios, it just breaks down. It’s probably not wise to use a solution that isn’t going to scale with your scenarios.
What Should I do?
Short answer: Subscribe to Kyle’s Blog
Kyle put together a blog post that includes a sample application, a ComboBoxDataSource control, and a ComboBox extension class that drastically simplifies many scenarios. Go read his post now.
As an aside, Kyle is taking over as the primary developer of the DomainDataSource feature for RIA Services. I have thoroughly enjoyed this feature, and I’ll still be involved, but Kyle is the new dev owner. Kyle did some heavy lifting in the feature area in V1 too, including the removal of ControlParameter and all of the support for ICommand and other Silverlight 4 niceties.
Will DomainDataSource Support ComboBox in the Future?
Short Answer: You tell us… should it?
Kyle and I spent some time talking through what we could do to improve the ComboBox support for DomainDataSource. There are a couple of ideas we wanted to put out there to get feedback.
Read-Only Mode for DomainDataSource
As I alluded to, we found many reasons why the DomainDataSource should not perform data loads when the DomainContext has changes. But we’re considering offering an IsReadOnly property on the control that would indicate that the data to be loaded is read-only data. When IsReadOnly is set to true, that would have the following effects on the control’s behavior:
- Loads would not get blocked when the DomainContext.HasChanges property is true;
- The DomainDataSource would not support Add or Remove actions against in read-only mode.
We think this read-only mode would help in the ComboBox scenarios because you can now have the ComboBox ItemsSource bound to a DomainDataSource that can load data after the user begins adding or editing entities. Cascading/drill-down selections would be possible because the loads would never be blocked. We’d still have the async loading problem to deal with though.
DataSource Control for non-Entity types
The DomainDataSource control is limited to calling EntityQuery load operations. Much of the functionality of DomainDataSource could be extracted out into another control that could work against any InvokeOperation though. Imagine having a method on the server that returns an IEnumerable<int> to return the list of years for car selection - there’s no reason to make an Entity out of Year just so that you can put a Query method on it for the DomainDataSource to be able to call it?
In fact, Kyle’s sample includes a ComboBoxDataSource control that handles both Query and Invoke operations. This is a very light-weight solution. Perhaps it’s enough.
What Say You?
Is this an area that we need to invest in? Would you like to see these scenarios addressed with the DomainDataSource, a separate DataSource, or in some other way? How do you think ComboBox should behave when ItemsSource is bound to an async collection? Does Kyle’s sample give you what you need?