Silverlight ComboBox Frequently Asked Questions


I’ve wanted to do a follow up to my original ComboBox post for a while now. I answered a number of the questions throughout the comments, but I thought I’d gather all the answers up and add some nice code samples. Hope this helps.

How do I use a ComboBox in a DataForm?

For most of the scenarios where you’ll be using a ComboBox in a DataForm a static data source will be sufficient. In our case, let’s assume we’re pulling a list of options from the server. We’ll add a method to our DomainService to get these items.

  public IEnumerable<string> GetCountryStrings()
  {
    return new[] { "UK", "USA" };
  }

Our next step is to create a data source to call the method. We can add the following snippet to our Silverlight page.

  <navigation:Page.Resources>
    <web:EmployeeDomainContext x:Key="employeeDomainContext"/>
    <ex:ComboBoxDataSource x:Key="countryDataSource"
DomainContext="{StaticResource employeeDomainContext}"
OperationName="GetCountryStrings" /> </navigation:Page.Resources>

It’s worth noting that we’ve made both the DomainContext and ComboBoxDataSource resources. This will allow us to share the DomainContext with the data source we use to load our data. Specifically, when we add a DomainDataSource that loads the entities, we’ll make sure that is uses the DomainContext declared in the resources.

  <dds:DomainDataSource AutoLoad="True"
Name="employeeDomainDataSource"
DomainContext="{StaticResource employeeDomainContext}"
QueryName="GetEmployeesQuery" />

The final step in using a ComboBox within a DataForm is to hook everything together within a DataField.

  <toolkit:DataForm AutoGenerateFields="False"
ItemsSource="{Binding ElementName=employeeDomainDataSource, Path=Data}"
Name="employeeDataForm"> <StackPanel> <toolkit:DataField Label="Title"> <TextBox Text="{Binding Path=Title, Mode=TwoWay}" /> </toolkit:DataField> <toolkit:DataField Label="Country"> <ComboBox
ItemsSource=
"{
Binding Data, Source={StaticResource countryDataSource}}" SelectedItem="{Binding Country, Mode=TwoWay}" ex:ComboBox.Mode="AsyncEager" /> </toolkit:DataField> </StackPanel> </toolkit:DataForm>

In this case, we’ve bound the ItemsSource to our data source, two-way bound the SelectedItem to a property on the entity, and set the ComboBox mode to AsyncEager.

It’s also worth noting we’ve set the DataField label to “Country”. If we were using the Display or Required attributes, we could set PropertyPath instead to ensure the metadata was applied to the DataField correctly.

Another point to highlight is I’m not using ElementName binding. It’s rarely explained, but ElementName binding has some limitations when used in templates (there are good reasons for this, but I won’t go into them here). It’s best to consider templates as a barrier for ElementName binding. Controls inside the template can bind to other controls inside the template. Controls outside the template can bind to other controls outside the template. However, controls inside the template cannot use ElementName binding to bind to controls outside the template (and vice-versa). This is another reason we chose to make the data source a resource above.

How do I use a ComboBox in a DataGrid?

Using a ComboBox in a DataGrid follows nearly the same pattern as above. First, define an operation on your DomainService to return the items. Second, define a data source to load the items; sharing a DomainContext as necessary. Finally, hook everything together within a DataGridTemplateColumn.

  <sdk:DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding ElementName=employeeDomainDataSource, Path=Data}"
Name="employeeDataGrid"> <sdk:DataGrid.Columns> <sdk:DataGridTextColumn x:Name="titleColumn"
Binding="{Binding Path=Title}" Header="Title" /> <sdk:DataGridTemplateColumn x:Name="countryColumn" Header="Country"> <sdk:DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ComboBox
ItemsSource=
"{
Binding Data, Source={StaticResource countryDataSource}}" SelectedItem="{Binding Country, Mode=TwoWay}" ex:ComboBox.Mode="AsyncEager" /> </DataTemplate> </sdk:DataGridTemplateColumn.CellEditingTemplate> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=Country}"/> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn> </sdk:DataGrid.Columns> </sdk:DataGrid>

As above, we’ve bound the ItemsSource to our data source, two-way bound the SelectedItem to a property on the entity, and set the ComboBox mode to AsyncEager.

Additionally, you might notice we’ve created two templates. We need to set up the CellEditingTemplate to use a ComboBox, but the CellTemplate used for reading the value can have anything in it. In this case it was easiest to display the value using a TextBlock.

What are the modes Async and AsyncEager and am I using them correctly?

There have been a number of questions along the lines of “I only see the selected item in my pick list. Why aren’t the items loading correctly?” In nearly every case, the inquirer is using the AsyncEager mode and it is masking the underlying failure (which tends to be the SelectedItem isn’t available in the ItemsSource). I figured I’d take a second to explain the modes.

Async mode makes sure the ComboBox’s SelectedItem will be reselected any time the ItemsSource changes. By default the control will stop binding any time the SelectedItem is not in the Items. This can be inconvenient in scenarios where you’re loading the ItemsSource asynchronously as the burden of correctly ordering the load completion and then establishing the binding always falls on you. With the Async mode, the ItemsSource can be loaded before or after the binding is created and the ComboBox will work fine regardless of the order. For this mode, the ComboBox will remain blank with an empty pick list until the ItemsSource is loaded.

AsyncEager mode goes one step farther then Async mode to improve the UI experience by addressing the selection ‘flicker’ that can occur when the ItemsSource is loaded asynchronously. If the SelectedItem is not in the ItemsSource, the ItemsSource will be replaced with a single-item list containing only the SelectedItem. The assumption is that in the near future, the ItemsSource will be updated with a list that does contain the SelectedItem. In this mode, the ComboBox will have a single-item pick list containing only the SelectedItem until the ItemsSource is loaded.

In both modes, it is important to note that equality is often based on referential comparison. Entities loaded in different DomainContext instances are not referentially equal. If you load the ItemsSource in one context and the SelectedItem in another, the entity will not be selected correctly in the ComboBox. For this reason (among others) it is important to share the DomainContext when loading the ItemsSource (see my last post for an example).

Comments (22)

  1. Sample request says:

    Can we please have a sample using something like AdventureWorks so we can follow this exactly .. and thank you for your efforts.

  2. kylemc says:

    I'll have one soon based on Northwind and I'll add a link when it's posted.

  3. Peter Wone says:

    As useful as this sample is, it doesn't address the scenario in which the combobox list is provided by another datasource. Some months ago I finally understood why ElementName binding doesn't work unless you define the datasource inside the template (which is hideously inefficient): a template instance does not share namescope with its container because if it did, you would get name collisions using it in a list. So namescope is of necessity broken, and we must resort to declaring the combobox list datasource as a static resource, and refer to it that way. I don't think the nature of problem is widely understood, because once you understand what's wrong, the solution is obvious and easy.

  4. kylemc says:

    Great point, I've updated the post with some explanation of the issue surrounding ElementName binding.

  5. Mark Tompkins says:

    Peter..thank you for your post – it was a watershed moment and allowed me to move a project forward.  Now I'm struggling with getting the validation up from the web side through to the combox implementation which isn't easy.

  6. kylemc says:

    Jeff just did a whole series on RIA Services validation (jeffhandley.com/…/default.aspx) that is definitely worth checking out.

  7. Mark Tompkins says:

    Thanks Kyle – I'm deep into it.  I was just hoping there was a way to incorporate it into your combobox solution without "heavy lifting".

  8. kylemc says:

    @Mark

    It would be nice to know the areas that make server-side validation trickiest. Feel free to send either Jeff or I feedback and we'll see if there are things we can improve.

  9. Will Vega says:

    Hi Kyle,

    I have been reading through many of your posts in the forums regarding the ComboBox. I have been myself hitting my head against the wall trying to make this component work.  My scenario involves having a DomainDataSource for a "Products" list and a DomainDataSource/ComboBoxDataSource for a Categories List, then in the form which is in a ChildWindow I have a DataGrid, a DataPager and a DataForm with AutoEdit set to True and AutoCommit set to False.

    Setting the DataItem in the ComboBox always threw an error 4009 saying "the element is already child of another element" After days dealing with it and posting in the forums at no avail, I dediced to create a usercontrol that would have both a combobox and an invisible textbox to bind twoway and then move the values from / to the combobox with code.  

    Then I realized the Bindings didnt work always, and after a while they didnt at all.  Then I added a dependency property to my project with a binding to the DataContext component to get a Custom DataContextChanged event inside the control, so I could set the bindings there.  After a lot of trial and error I could get the component to work in an almost 'clean' way.  Now when I load the ChildWindow and move from record to record on the grid the values for the combobox field (foreign key) change in what really appears to be a random fashion.

    Is there any way I can send you my project for you to take a look? This thing is making me crazy and really don't know what else to do at this point.  I would really appreciate if you could take just 5 mins to check this as probably will take you just one to know what is wrong. Please let me know how can I upload my project or send it to  you. Thanks so much in advance!

  10. kylemc says:

    @Will

    Use the 'Email blog author' link above and I'll email you back.

  11. Alomax says:

    Hi Kyle,

    Did you ever manage to organise a Northwind sample as mentioned back on the 11-02-2010?

    I would certainly be interested.

  12. kylemc says:

    Yep, it's linked off my Silverlight TV: Episode 52 post. blogs.msdn.com/…/silverlight-tv-52-ria-services-q-a.aspx

  13. Hiral says:

    How to we get the default value which is selected in a combobox?

    Basically I am creating automation test cases for our app, and I have tried doing –

    ComboBox.SelectedItem  – but this gives me a value ' …….ComboBoxEntity' so I assume the value are binded to some control.

    So now, how do I read the default selected value of the combobox?

  14. kylemc says:

    @Hiral

    Which binding are you using to select the item, is it SelectedValue or SelectedItem? You should be able to use the same one you're binding with.

  15. BDors says:

    Kyle,

    I implemented your library today and attempted to added two separate comboboxes to my dataform one representing Role entities and the other representing Subscriber entities that are tied to my User entity in the dataform. I have custom validation on my Role and Subscriber entities so that only certain Subscribers can have certain Roles. The validation works fine. My problem is this:

    When the validation returns an error, in my validation summary my label is shown as "SelectedItem" for both Role and Subscriber rather than "Role" and "Subscriber". I bound the labels of both datafields that the comboboxes reside in to the right PropertyPaths. What am i doing wrong?

  16. kylemc says:

    @BDors

    I'm not positive how the ValidationSummary works, but this sounds like it might be related to your custom validation. Make sure you're returning the property member name in the ValidationResult (take a look at the validation in this post for an example blogs.msdn.com/…/using-ria-services-with-comboboxes-and-enums.aspx).

  17. mond says:

    Hello kyle,

    good afternoon. would like to ask if you have a vb.net 2010 version of your How do I use a ComboBox in a DataForm?

    I really cant find a good sample except yours, however i am new in Silveright programming and really would like to implement something like what you successfully implemented.

    Thanks in advance.

  18. kylemc says:

    @mond

    Unfortunately I don't have a VB version available. There are a few decent web sites that convert C# to VB, though. You should be able to take the C# sample and run the files you're interested in through one of those converters.

  19. almond says:

    Kyle, have you ever tried using the extension in a child window? Can you please guide us on how to implement in a child window with dataform?

    Thanks in advance kyle. 🙂

  20. mond says:

    hello again Kyle, i would just like to ask if you have tried using the extension in a SL4 Child window with a dataform? Could you guide us on now to go about it?

    Thanks in advance.

  21. Carlos says:

    hello again Kyle, i would just like to ask if you have tried using the combobox extension in a SL4 Child window with a dataform? Could you guide us on now to go about it?

  22. Almond says:

    @Carlos

    have you started in anyway in trying the comboboxes in SL4? I have successfully implemented them using ChildWindow hoever now what I want to do is select the past item or record of the 2nd combobox.

    Where are having problems?

    Thanks.

    Almond

Skip to main content