【发布时间】:2013-11-11 17:29:57
【问题描述】:
在我们的应用程序中,我们有一个屏幕设计功能,它由一个自定义 ScreenDesignPanel 和一个顶部带有 ComboBox 的属性网格组成,它指向 ScreenDesignPanel 上的选定项目。这允许用户通过 ComboBox 或鼠标选择 UIElement 来设置其属性。我们通过将 ComboBox 的 ItemsSource 绑定到 ScreenDesignPanel 的 Children 集合,然后将它们的 SelectedItem 绑定在一起来实现这一点。这很好用。
但是,无论出于何种原因,如果SelectedItem 是ContentControl 或Button 之类的子类,则为ItemTemplate 指定的ComboBox 将被“选定项目区域”忽略,但在以下情况下应用在下拉列表中显示项目。如果SelectedItem 不是ContentControl,则在这两种情况下都使用模板。
这似乎也特定于ComboBox。如果我们使用任何其他选择器控件:ListBox、ListView、ItemsControl...甚至第三方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.Content 和 ContentControl.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