views:

2605

answers:

3

I have two combo boxes on a SL page. When Combo 1 updates, a service is called and populates Combo 2.

On the first call, 3 results are returned. When the combo box is expanded, you can see all 3 options.

On the second call, 4 results are returned. When the combo box is expanded, you can see 3 options, with a vertical scroll bar.

If I reload and do those steps in reverse, I get 4 rows the first call and 3 rows + a blank row on the second call. (No, the blank is not a record. It cannot be selected.)

It appears that the drop down list size keeps the first generated height.

How can I refresh the combo box max items shown after each service call?

Thanks!

Edit #1

The code follows the M-V-VM pattern. When the page loads, the Group1 populates the first combo box, and nothing is selected. When the user makes a selection, that selection is bound to Group1Selection.

<ComboBox ItemsSource="{Binding Path=Group1}" SelectedItem="{Binding Path=Group1Selection}" />
<ComboBox ItemsSource="{Binding Path=Group2}" SelectedItem="{Binding Path=Group2Selection}" />

In the viewmodel, in the set accessor of the Group1Selection property, I have something like

set
{
    if (group1Selection != value)
    {
        group1Selection = value;
        PopulateGroup2();
        OnPropertyChanged("Group1Selection");
    }
}

Where PopulateGroup2 performs my service call async, gets the data, and puts that data into the exposed property of Group2.

Under "normal" conditions, this isn't a problem, since most options have dozens of possible selections. However, a couple of the Group1 choices only have 3 or 4 child choices. If one of those is selected first, then the height of the ComboBox, for the rest of that application instance is set to 3 or 4, respectively, instead of maxing out at 8 shown items.

Following the M-V-VM pattern, there is no code in the code-behind.

A: 

I think the problem is that Silverlight doesn't fully realize that the data behind ComboBox 2 has changed. Maybe try adding OnPropertyChanged("Group2") to the set for Group1 - that should help Silverlight to realize that it needs to update the bindings for ComboBox 2.

It also might help to call OnPropertyChanged for Group2Selection, since the previous value is no longer valid.

Andy
+3  A: 

This is a known bug in the ComboBox in Silverlight 2. I think its been fixed in SL 3.

You can fix this by doing the following:

  1. Inherit from the ComboBox

    public class MyComboBox : ComboBox

  2. Get a reference to the "Popup" part of the ComboBox inside the OnApplyTemplate() method

        Popup thePopup = GetTemplateChild("Popup") as Popup;
        FrameworkElement thePopupContent = thePopup.Child as FrameworkElement;
    
  3. Override the OnItemsChanged method

  4. Inside the overridden OnItemsChagned method reset the Height & Width dependency properties on the Popup using the ClearValue(DP) method.

            thePopupContent.ClearValue(FrameworkElement.WidthProperty);
            thePopupContent.ClearValue(FrameworkElement.HeightProperty);
    

You can clear the Max and Min Height & Width properties if you are worried about those too.

markti
Total pain - but much better than the alternative of destroying the combobox and adding a new one to the children.
Jarrett Meyer
This is the best solution to this issue that I've seen. Thanks!
Jeff Yates
Yeah, I totally agree...but you gotta do what you gotta do :o)SL2, I love you, but I can't wait for SL3 to RTM!
markti
You can also just obtain PopupBorder (which is the Popup's child) directly. Still a great solution.
Jeff Yates
+1  A: 

That was a perfect solution. Thank you markti.

For those interested the class would look like this:

using System.Windows.Controls.Primitives; 

public class WorkAroundComboBox: ComboBox
{
    FrameworkElement thePopupContent;

    public override void OnApplyTemplate()
    {
        Popup thePopup = GetTemplateChild("Popup") as Popup;
        thePopupContent = thePopup.Child as FrameworkElement;
        base.OnApplyTemplate();
    }

    protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        thePopupContent.ClearValue(FrameworkElement.WidthProperty);
        thePopupContent.ClearValue(FrameworkElement.HeightProperty);
        base.OnItemsChanged(e);
    }
}

}

Oliver