Tuesday, November 4, 2008

Help! My ComboBox Does Not Render Properly

The release of Silverlight 2.0 provided the much anticiopated ComboBox. Many frustrated developers (I was one of them) found themselves creating their own custom controls in order to have a drop down box in the UI's prior to the release of 2.0. When I found out 2.0 was finally released and it included a ComboBox, I immediately ripped out all of my temporary dropdown box controls from my current Silverlight application and replaced them with the new ComboBox control provided my Microsoft, and all was well.

When I ran the application, however, I realized that all was not well. The ComboBox control in Silverlight 2.0 has a very annoying bug. Now, the folks in the Silverlight team are aware of this bug and are working on a solution, so for the time being we are stuck with having to come up with a workaround. So here is the bug...

The Bug:
If you have a dynamically populated ComboBox, the height of the actual drop down is calculated only once. The very first time the drop down is displayed, it is measured and displayed properly. If the contents of that ComboBox change, however, the drop down is not remeasured. You are stuck with the same size drop down. This becomes a real problem with the first time the dropdown is shown there is only one item in the list and the second time there are 50! You are stuck with a very short dropdown and a scroll bar.

The Workaround:
Whenever you have to change the collection of items in a ComboBox, you need to rip that original ComboBox out of it's container, create a new one with all the same properties, add the appropriate items to the new ComboBox, and insert it back in the appropriate container.

I typically write a CloneComboBox method. Here is a sample:



This is the method I call imediately before I say cboMovies.ItemsSource = "myNewItemsSource".

It first removes the ComboBox form it's parent container (LayoutRoot in this case). Then I make a new ComboBox and I copy all of it's original properties. The easiest way to do this is copy the xaml which creates the original ComboBox, and make sure all of it's properties are being copied over to the new one. Here is my orinial xaml for that ComboBox:

<ComboBox x:Name="cboMovies" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" Margin="74,9,0,0" Width="206.333"> <ComboBox.ItemTemplate> ....</ComboBox.ItemTemplate> </ComboBox>

Note: I had to also add all of the attached properties (in this case Grid.Row) in order for it to render properly. Finally, make sure you hook up all of the approprieat event handlers to your new comboBox. Once all this is done, simply add the ComboBox back to the parent container... in this case LayoutRoot.

After this method is finished executing, I can give the ComboBox a new ItemsSource and the new drop down is rendered in the appropriate size.

Give it a shot and good luck. Hopefully this post will become obselete soon (I'm hoping for a fix from Microsoft soon!)

4 comments:

  1. this solution is hillarious...

    not because it's a solution - but because someone forced you to write it !!!

    i've found several bugs in the combobox by Microsoft : http://silverlight.net/forums/p/68429/166089.aspx#166089

    ReplyDelete
  2. Thanks for this! That bug is sooo dam anoying!!

    ReplyDelete
  3. calling .InvalidateMeasure() after you populate it works as well!

    ReplyDelete
  4. "calling .InvalidateMeasure() after you populate it works as well!"

    NO IT DOESN'T!!

    ReplyDelete