Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Make Microsoft.VisualStudio.Diagnostics.UI.Controls.MultiSelectComboBox Work

What I Try to Achieve:

I'm developing a Visual Studio plugin, and I need a MultiSelectComboBox. I want to fit in with the look and feel of VisualStudio so it seemed a good idea to use their own class for this:

public class MultiSelectComboBox : UserControl, IComponentConnector, IStyleConnector
Name: Microsoft.VisualStudio.Diagnostics.UI.Controls.MultiSelectComboBox
Assembly: Microsoft.VisualStudio.Diagnostics.Common, Version=12.0.0.0

Microsoft uses this class in their Code Analysis page: View/Other Windows/Code Analysis.

The Problem:

Of course it just doesn't work right when I want to use it. :)

Here's a sample code how I used it:

public TestClass()
{
    InitializeComponent();
    multiSelectComboBox.ItemsSource = new string[] { "Item 1", "Item 2", "Item 3" };
    multiSelectComboBox.AllItemsText = "All items";
}

And here's the XAML markup:

<UserControl ...
    xmlns:vsUiControls="clr-namespace:Microsoft.VisualStudio.Diagnostics.UI.Controls;assembly=Microsoft.VisualStudio.Diagnostics.Common"
    ...>
    <vsUiControls:MultiSelectComboBox x:Name="multiSelectComboBox"/>
</UserControl>

Now the MultiSelectComboBox appear and you can interact with it, however, when you select some items, but not all, the items should be displayed like this: Item 1; Item 3 (assuming you selected all but Item 2). However, the displayed text is just Item 1Item 3, totally missing the separator.

The funny thing (that I have overlooked for quite a while) is that if you debug your code and ask for multiSelectComboBox.SelectedItemsText it returns the right values separated with the semicolon.

So the question is, if the value is stored right, why is it not displayed correctly when I use it in my code, but right when used by Microsoft on the Code Analysis page?

The XAML markup describing the style of MultiSelectComboBox contains only one instance of SelectedItemsText, which is a binding. Please see what I've got from .Net Reflector below:

<local:MultiSelectComboBox
    p1:UserControl.Name="_this"
    p1:AutomationProperties.Name="{Binding RelativeSource={RelativeSource Self},Path=AllItemsText}"
    xmlns:p1="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:local="clr-namespace:Microsoft.VisualStudio.Diagnostics.UI.Controls;assembly=Microsoft.VisualStudio.Diagnostics.Common,Version=12.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a">
    ...
    <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
        <local:CheckComboBox
            CheckComboBox.Name="_comboBox"
            p4:FrameworkElement.Style="{StaticResource ComboStyle}"
            p4:Control.HorizontalContentAlignment="Stretch"
            p4:KeyboardNavigation.DirectionalNavigation="Continue"
            p4:AutomationProperties.Name="{Binding ElementName=_this,Path=SelectedItemsText,Mode=OneWay}"
            xmlns:p4="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
            <ItemsControl.ItemTemplate>
                ...
            </ItemsControl.ItemTemplate>
        </local:CheckComboBox>
    </Grid>
</local:MultiSelectComboBox>

I am not sure why SelectedItemsText is bound to the AutomationProperties.Name (attached?) property, but this is what .Net Reflector gave me. If I debug my code, I can find the semicolon separated values stored in the Name property of CheckedComboxBox control within the MultiSelectComboBox.

The values seem to be stored right, binding seems to work, yet the text displayed to the UI does not contain the separator. I'm just puzzled...

like image 591
Shakaron Avatar asked Aug 25 '15 12:08

Shakaron


1 Answers

I took a look at decompiled sources and it seems that property SelectedItemsText is used only for UI automation (attached property AutomationProperties.Name). Real display text is showind with this XAML:

<TextBlock Name="PART_SummaryPartialSelection" Grid.Row="0" Style="{StaticResource DropDownTextBlockStyle}" Visibility="{Binding Path=AllItemsSelected, ElementName=_this, Converter={StaticResource booleanToVisibilityConverterNegative}}">
  <ItemsControl Name="PART_Items" Focusable="False" Background="#00FFFFFF" IsHitTestVisible="False" x:Uid="M113" ItemsSource="{Binding SelectedItems, ElementName=_this}" ItemTemplate="{Binding DisplayAreaTemplate, ElementName=_this}">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate x:Uid="M115">
        <StackPanel IsItemsHost="True" Orientation="Horizontal" x:Uid="M116" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  </ItemsControl>
</TextBlock>

So it is just horizontal StackPanel with items one by one without any separator. So you will need to modify this template or just add semicolon at your items (looks like Visual Studio does it this way as it shows semicolon event after last item - item1; item2;)

like image 82
Nikolay Avatar answered Oct 17 '22 18:10

Nikolay