Как сделать Microsoft.VisualStudio.Diagnostics.UI.Controls.MultiSelectComboBox Work

Что я пытаюсь достичь:

Я разрабатываю плагин Visual Studio, и мне нужен MultiSelectComboBox. Я хочу соответствовать стилю VisualStudio, поэтому было бы неплохо использовать для этого свой класс:

открытый класс MultiSelectComboBox: UserControl, IComponentConnector, IStyleConnector
Имя: Microsoft.VisualStudio.Diagnostics.UI.Controls.MultiSelectComboBox
Сборка: Microsoft.VisualStudio.Diagnostics.Common, Version = 12.0.0.0

Microsoft использует этот класс на странице "Анализ кода": "Просмотр/другой анализ Windows/кода".

Проблема:

Конечно, это просто не работает, когда я хочу его использовать.:)

Вот пример кода, как я его использовал:

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

И здесь разметка XAML:

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

Теперь появляется MultiSelectComboBox, и вы можете взаимодействовать с ним, однако, когда вы выбираете некоторые элементы, но не все, элементы должны отображаться следующим образом: Item 1; Item 3 (при условии, что вы выбрали все, кроме пункта 2). Однако отображаемый текст просто Item 1Item 3, полностью отсутствует разделитель.

Забавно (что я пропустил довольно долгое время) заключается в том, что если вы отлаживаете свой код и запрашиваете multiSelectComboBox.SelectedItemsText, он возвращает правильные значения, разделенные точкой с запятой.

Итак, вопрос в том, правильно ли хранится значение, почему он не отображается правильно, когда я использую его в своем коде, но правильно, когда он используется Microsoft на странице анализа кода?

Разметка XAML, описывающая стиль MultiSelectComboBox, содержит только один экземпляр SelectedItemsText, который является связующим. Посмотрите, что я получил от .Net Reflector ниже:

<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>

Я не уверен, почему SelectedItemsText привязан к свойству AutomationProperties.Name (прикрепленный?), но это то, что дал мне Reflector.Net. Если я отлаживаю свой код, я могу найти значения, разделенные точкой с запятой, хранящиеся в свойстве Name элемента управления CheckedComboxBox в MultiSelectComboBox.

Значения, похоже, сохранены правильно, привязка, похоже, работает, но текст, отображаемый в пользовательском интерфейсе, не содержит разделителя. Я просто озадачен...

Ответ 1

Я посмотрел на декомпилированные источники, и кажется, что свойство SelectedItemsText используется только для автоматизации пользовательского интерфейса (вложенное свойство AutomationProperties.Name). Текст реального отображения отображается с помощью этого 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>

Таким образом, это просто горизонтальный StackPanel с элементами один за другим без разделителя. Таким образом, вам нужно будет изменить этот шаблон или просто добавить точку с запятой в свои объекты (похоже, что Visual Studio делает это так, поскольку она показывает событие с запятой после последнего элемента - item1; item2;)