【问题标题】:Why does this ComboBox ignore the DataTemplate when SelectedItem is a ContentControl?为什么当 SelectedItem 是 ContentControl 时,此 ComboBox 会忽略 DataTemplate?
【发布时间】:2013-11-11 17:29:57
【问题描述】:

在我们的应用程序中,我们有一个屏幕设计功能,它由一个自定义 ScreenDesignPanel 和一个顶部带有 ComboBox 的属性网格组成,它指向 ScreenDesignPanel 上的选定项目。这允许用户通过 ComboBox 或鼠标选择 UIElement 来设置其属性。我们通过将 ComboBox 的 ItemsSource 绑定到 ScreenDesignPanel 的 Children 集合,然后将它们的 SelectedItem 绑定在一起来实现这一点。这很好用。

但是,无论出于何种原因,如果SelectedItemContentControlButton 之类的子类,则为ItemTemplate 指定的ComboBox 将被“选定项目区域”忽略,但在以下情况下应用在下拉列表中显示项目。如果SelectedItem 不是ContentControl,则在这两种情况下都使用模板。

这似乎也特定于ComboBox。如果我们使用任何其他选择器控件:ListBoxListViewItemsControl...甚至第三方ComboBox控件...它们都按预期工作,正确应用@ 987654338@。 ComboBox 在内部做一些其他控件没有做的事情。

注意:下面是一个过度简化的示例,仅用于说明问题。如上所述,这不是我们实际使用它的方式。

还要注意:在 ComboBox.ItemTemplate 的 DataTemplate 中,我们只使用属性(即示例中的 Foreground),而不显示 DataContext(即实际的 ContentControl)本身。 这很重要,因为实际控件已经存在于 ScreenDesignPanel 上,因此 不能 用于在 ComboBox 的 ItemTemplate 中显示,因为它有两个父级允许。换句话说,它在这里纯粹用作数据。

最后一件事...我们的应用程序中有一个可行的解决方案,即在将 Children 绑定到 ComboBox.ItemsSource 之前对其进行包装。但是,我仍然很好奇为什么 ComboBox 的行为方式是 特别是我要问的。 (换句话说,我不是在为这个设计寻找其他解决方案。我们已经有了一个可行的解决方案。我正在寻找关于 ComboBox 本身的奇怪行为的清晰说明。)

进入代码!

在下面的第一个示例中,请注意数据模板如何应用于下拉列表中的所有内容,但如果所选项目不是ContentControl,则所选项目区域仅使用模板。

<ComboBox>

    <ComboBox.ItemTemplate>

        <DataTemplate>
            <TextBlock Text="I am the template" Foreground="{Binding Foreground}" />
        </DataTemplate>

    </ComboBox.ItemTemplate>

            <!-- Four 'Data' items for example only -->
    <TextBlock Text="I am a Red TextBox" Foreground="Red"/>

    <ListBox Foreground="Purple">
        <ListBoxItem>I am a Purple ListBox</ListBoxItem>
    </ListBox>

    <ContentControl Content="I am a Blue ContentControl" Foreground="Blue" />

    <Button Content="I am a Button with Green text" Foreground="Green" />

</ComboBox>

第二个示例表明,使用UIElement 作为ContentPresenter 的内容并且仍然使用DataTemplate(通过ContentTemplate)是完全可以接受和完全支持的,因此您可以纯粹地使用它-data 角色,允许模板自己定义视觉外观而不显示 UIElement 本身,这里纯粹用作数据。

<ContentPresenter>

    <ContentPresenter.ContentTemplate>

        <DataTemplate>
            <TextBlock Text="I am the ContentTemplate" Foreground="{Binding Foreground}" />
        </DataTemplate>

    </ContentPresenter.ContentTemplate>

    <ContentPresenter.Content>
        <Button Content="I am the button" Foreground="Green" />
    </ContentPresenter.Content>

</ContentPresenter>

同样,这个问题特定于ComboBox. 我想知道为什么数据模板不适用于这种情况,以及如何强制应用它(如果可能) .

值得注意的是,ComboBox 确实定义了 SelectionBoxItemTemplate,它与常规的 ItemTemplate 是分开的,但问题是它是只读的,因此您无法设置它。我们真的不想重新设计 ComboBox 模板,因为这会弄乱正确的主题。

【问题讨论】:

  • 这可能是因为ContentControl.Content 是一个对象,在使用前被包裹在ContentPresenter 中,而您不能使用StringFormat 对象。 ContentPresenter 有效,因为在渲染时,它只显示 Content 属性,没有包装控件,因此值为 string。有关详细信息,请参阅 ContentPresenter.ContentContentControl.Content 上的 MSDN 文章
  • 见我上面的澄清。 content 属性没有什么特别之处。它只是一个对象。我们的代码实际上使用了一个专门创建的附加属性来提供组合,但由于没有应用模板,因此绑定永远不会命中,并且永远不会读取附加属性。这就是问题所在......如果所选项目是 ContentControl 的子类,则模板永远不会应用于所选项目。
  • 嗨@Rachel,我已经用更多代码示例更新了这个,显示这是特定于ComboBox,而不是ContentPresenters。还有其他想法吗?
  • 这是一个XY problem。请描述您实际尝试实现的目标,因为当前的解决方案不是所讨论的 WPF 构造的预期用途,因此会出现不一致的行为。 UI is not data.
  • nmclean,我知道 MVVM。有问题的 UI 不是 UI。它数据。它是一组恰好被 ELSEWHERE 用作 UI 的类,但不是在这里。所以不,这不是 XY 问题,也不适用于您链接到的“UI 不是数据”问题。

标签: c# wpf binding datatemplate


【解决方案1】:

您是否尝试过将DataTemplate 显式设置为ContentControl.ContentTemplate 属性?:

<UserControl.Resources>
    <DataTemplate x:Key="DataTemplate">
        <TextBlock Text="{Binding Content, 
            StringFormat='Displayed via template: {0}'}" />
    </DataTemplate>
</UserControl.Resources>
...
<ContentControl Content="ContentControl" 
    ContentTemplate="{StaticResource DataTemplate}" />

【讨论】:

  • 你搞错了。 ContentControl 是 ComboBox 的 Items 集合中的一个项目。换句话说,ContentControl 被用作数据,而不是 UI 项。
  • 只是让您知道我在问题中添加了更多内容以更好地解释/演示问题。关于为什么 ComboBox 有这种奇怪行为的任何想法?
  • 抱歉,我无法解释这种情况……这是你在那里发现的一个奇怪的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-25
  • 1970-01-01
  • 2011-11-08
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
相关资源
最近更新 更多