ComboBox ItemTemplate работает только в выпадающем меню - программирование
Подтвердить что ты не робот

ComboBox ItemTemplate работает только в выпадающем меню

Я пытаюсь показать ComboBox, чей элемент ItemsSource представляет собой набор элементов управления (он является частью PropertyGrid, ComboBox должен отображать имена элементов управления, и пользователь должен иметь возможность выбрать один из элементов управления). Вот чрезвычайно упрощенное воспроизведение проблемы:

<ComboBox ItemsSource="{Binding GroupBoxes}" SelectedValue="{Binding SelectedGroupBox}">
  <ComboBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
  </ComboBox.ItemTemplate>          
</ComboBox>

GroupBoxes и SelectedGroupBox - DependencyProperties типа ObservableCollection и GroupBox.

Работа Bindings - имена элементов управления отображаются в ComboBox-DropDown, и если я выберу другой элемент, я вижу, что свойство SelectedGroupBox обновлено правильно. Проблема: выбранный элемент никогда не отображается в ComboBox. Установка свойства SelectedGroupBox из кода также работает должным образом - ComboBox вызывает SelectionChanged и его SelectedValue верен, но он все еще не отображает текущее значение.

Если я делаю то же самое с любым другим типом класса, все работает так, как ожидалось.

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

Edit:

Чтобы упростить проверку, вот код позади. Просто оставьте выше XAML в новом окне и код ниже в коде.

public MainWindow() {
    InitializeComponent();
    this.DataContext = this;
    this.GroupBoxes = new ObservableCollection<GroupBox>();
    this.GroupBoxes.Add(new GroupBox() { Name = "AAA", Header = "AAA", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "BBB", Header = "BBB", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "CCC", Header = "CCC", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "DDD", Header = "DDD", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "EEE", Header = "EEE", Height = 100, Background = Brushes.Purple });
}

#region GroupBoxesProperty

public static readonly DependencyProperty GroupBoxesProperty = DependencyProperty.Register(
    "GroupBoxes", typeof(ObservableCollection<GroupBox>), typeof(MainWindow)
);

public ObservableCollection<GroupBox> GroupBoxes {
    get { return (ObservableCollection<GroupBox>)GetValue(GroupBoxesProperty); }
    set { SetValue(GroupBoxesProperty, value); }
}

#endregion

#region SelectedGroupBoxProperty

public static readonly DependencyProperty SelectedGroupBoxProperty = DependencyProperty.Register(
    "SelectedGroupBox", typeof(GroupBox), typeof(MainWindow),
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => (s as MainWindow).OnSelectedGroupBoxChanged())
);

public GroupBox SelectedGroupBox {
    get { return (GroupBox)GetValue(SelectedGroupBoxProperty); }
    set { SetValue(SelectedGroupBoxProperty, value); }
}

void OnSelectedGroupBoxChanged() {
    Console.WriteLine("selection is now " + this.SelectedGroupBox.Name);
}

#endregion
4b9b3361

Ответ 1

ComboBox по некоторым очень сложным причинам предоставляет свойство только для чтения, называемое SelectionBoxItem. Презентатор содержимого в шаблоне ComboBox связывается с этим свойством. Именно SelectionBoxItem предоставляет строковое представление элементов, отличных от UI, что позволяет вам видеть выбранное значение. Использование этого свойства - это то, что препятствует тому, чтобы контент-презентатор использовал шаблоны данных. Вот почему шаблон применяется к выпадающему, но не выбранному элементу. Вот часть шаблона ComboBox по умолчанию, вызывающая проблему:

<ContentPresenter IsHitTestVisible="false"
    Margin="8,1,1,1"
    Content="{TemplateBinding SelectionBoxItem}"
    ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
    ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>

Однако вы можете создать свой собственный стиль ComboBox, который переопределяет ContentPresenter по умолчанию и использует SelectedItem вместо SelectionBoxItem и ItemTemplate вместо SelectionItemBoxTemplate. Это решит проблему.

Ответ 2

Используйте DisplayMemberPath вместо привязки к имени:

 <Combobox DisplayMemberPath="Name" ... />

Причина видимого вами поведения заключается в том, что вам нужно установить другое свойство для выбранного шаблона элемента: http://msdn.microsoft.com/en-us/library/system.windows.controls.combobox.selectionboxitemtemplate.aspx


Обновление: я написал свой ответ, не проверяя ваш код, извините за это. Теперь я прочитал ваш код и заметил, что вы привязываете свойство SelectedValue. Я не думаю, что это лучшее свойство для привязки в вашем случае, обычно свойство SelectedItem должно использоваться. Я помню, что мне никогда не приходилось ничего делать с телом SelectionBoxItem, упомянутым в другом ответе, вероятно, потому, что свойства SelectedValue и SelectedItem ведут себя по-разному, и я стараюсь использовать SelectedItem всякий раз, когда могу. В вашем случае я тоже буду использовать его.