wpf ComboBox ItemTemplate 仅在下拉列表中工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8242312/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:11:43  来源:igfitidea点击:

ComboBox ItemTemplate only working in dropdown

wpfcombobox

提问by wilford

I am trying to show a ComboBox whose ItemsSource is a collection of Controls (it is part of a PropertyGrid, the ComboBox should display the names of the controls, and the user should be able to select one of the controls). Here is an extremely simplified reproduction of the problem:

我正在尝试显示一个 ComboBox,其 ItemsSource 是一个控件集合(它是 PropertyGrid 的一部分,ComboBox 应该显示控件的名称,并且用户应该能够选择其中一个控件)。这是问题的极其简化的再现:

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

GroupBoxes and SelectedGroupBox are DependencyProperties of type ObservableCollection and GroupBox.

GroupBoxes 和 SelectedGroupBox 是 ObservableCollection 和 GroupBox 类型的 DependencyProperties。

The Bindings work - the control names are displayed in the ComboBox-DropDown, and if I select a different item I can see that the SelectedGroupBox property is updated correctly. The problem: the selected item is never displayed in the ComboBox. Setting the SelectedGroupBox property from code also works as expected - the ComboBox raises SelectionChanged and its SelectedValue is correct, but it still doesn't display the current value.

绑定工作 - 控件名称显示在 ComboBox-DropDown 中,如果我选择不同的项目,我可以看到 SelectedGroupBox 属性已正确更新。问题:所选项目永远不会显示在 ComboBox 中。从代码设置 SelectedGroupBox 属性也按预期工作 - ComboBox 引发 SelectionChanged 并且其 SelectedValue 是正确的,但它仍然不显示当前值。

If I do the exact same thing with any other type of class, everything works as expected.

如果我对任何其他类型的课程做完全相同的事情,一切都会按预期进行。

Searching for an answer I came across many posts from people having similar sounding problems, but almost all of them were Binding proplems which is not the case here.

在寻找答案时,我遇到了许多来自有类似声音问题的人的帖子,但几乎所有帖子都是绑定问题,这里的情况并非如此。

Edit:

编辑:

To simplify trying it out, here's the code behind. Just drop the above XAML in a new Window, and the code below in the code behind.

为了简化尝试,这里是后面的代码。只需将上面的 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

回答by icirellik

The ComboBox, for some very complex reasons exposes a read-only property called SelectionBoxItem. The content presenter in the ComboBox template binds on this property. It is the SelectionBoxItem that exposes the string representation of non-UI elements allowing you to see the selected value. The use of this property is what prevents the content presenter from using data templates. This is why the template applies to the drop down but not the selected item. Here is the part of the default ComboBox template causing the issue:

由于某些非常复杂的原因,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}"/>

You can however create your own ComboBox style that overrides the default ContentPresenter and uses the SelectedItem instead of SelectionBoxItem and ItemTemplate instead of SelectionItemBoxTemplate. This will resolve the issue.

但是,您可以创建自己的 ComboBox 样式来覆盖默认的 ContentPresenter,并使用 SelectedItem 代替 SelectionBoxItem 和 ItemTemplate 代替 SelectionItemBoxTemplate。这将解决问题。

回答by Snowbear

Use DisplayMemberPathinstead of binding to name:

使用DisplayMemberPath而不是绑定到名称:

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

The reason for the behaviour you see probably is that you need to set another property for selected item's template: http://msdn.microsoft.com/en-us/library/system.windows.controls.combobox.selectionboxitemtemplate.aspx

您看到的行为的原因可能是您需要为所选项目的模板设置另一个属性:http: //msdn.microsoft.com/en-us/library/system.windows.controls.combobox.selectionboxitemtemplate.aspx



Update: I've written my answer without checking your code, sorry for that. Now I've read your code and noticed that you're binding SelectedValueproperty. I do no think this is the best property to bind in your case, usually property SelectedItemshould be used. I remember that I never had to do anything with SelectionBoxItemstuff mentioned in other answer, that's probably because SelectedValueand SelectedItemproperties behave differently and I tend to use SelectedItemwhenever I can. In your case I would use it too.

更新:我在没有检查您的代码的情况下写了我的答案,很抱歉。现在我已经阅读了您的代码并注意到您正在绑定SelectedValue属性。我不认为这是在您的情况下绑定的最佳属性,通常SelectedItem应该使用属性。我记得我从来没有对SelectionBoxItem其他答案中提到的东西做任何事情,这可能是因为SelectedValueSelectedItem属性的行为不同,我倾向于尽可能使用SelectedItem。在你的情况下,我也会使用它。