将非数据元素包含到WPF数据绑定组合框中

将非数据元素包含到WPF数据绑定组合框中,wpf,collections,wpf-controls,Wpf,Collections,Wpf Controls,我在解决方案中使用了两个不同的组合框(部门和名称),这些组合框当前绑定到从外部服务引用返回的列表集合。我有一个问题,我需要在组合框中插入其他元素,而不是API提供的元素 例如,除了显示所有部门名称外,我还需要组合框中可见的第一个元素为“选择部门…” 在做一些研究(无论是在这里还是在网上)时,我似乎可以使用一个复合集合来完成这项工作 我的问题是,如果我只有一个项目需要作为组合框中的第一个项目显示,这是最好的方法吗?或者我还需要考虑其他方法吗 提前感谢,我使用一个复合类在组合框中包含嵌入式协助(“

我在解决方案中使用了两个不同的组合框(部门和名称),这些组合框当前绑定到从外部服务引用返回的列表集合。我有一个问题,我需要在组合框中插入其他元素,而不是API提供的元素

例如,除了显示所有部门名称外,我还需要组合框中可见的第一个元素为“选择部门…” 在做一些研究(无论是在这里还是在网上)时,我似乎可以使用一个复合集合来完成这项工作

我的问题是,如果我只有一个项目需要作为组合框中的第一个项目显示,这是最好的方法吗?或者我还需要考虑其他方法吗


提前感谢,

我使用一个复合类在组合框中包含嵌入式协助(“选择部门…”),我认为它工作得很好


一旦用户选择了一个部门,我建议删除嵌入的辅助功能。

听起来好像您希望某个元素在未选择任何内容时可见,并显示为组合框的一部分,但在进行选择时不可见

最简单的是,您可以设计一个UserControl,其中包含您的ComboBox(如果您要在代码中添加项目,而不是一些静态XAML标记)和一个包含提示的TextBlock。像这样:

<Grid>
    <ComboBox x:Name="ComboBoxControl"
              SelectionChanged="ComboBoxControl_SelectionChanged"
              HorizontalAlignment="Left" VerticalAlignment="Top" 
              MinWidth="{Binding ElementName=UnselectedText, Path=ActualWidth}">
        <ComboBoxItem>One</ComboBoxItem>
        <ComboBoxItem>Two</ComboBoxItem>
        <ComboBoxItem>Three</ComboBoxItem>
    </ComboBox>
    <TextBlock IsHitTestVisible="False" 
               x:Name="UnselectedText" 
               HorizontalAlignment="Left" 
               Text="Select an option..." 
               VerticalAlignment="Top" Margin="4" 
               Padding="0,0,30,0" />
</Grid>
在TextBlock上设置
ishitestvisible=“False”
dependencProperty可以让鼠标事件通过,以便您可以单击组合框,并在代码隐藏中将可见性设置为
Hidden
,以防止在提示文本隐藏时默认组合框的外观布局跳转


当然,通过创建一个MyComboBox自定义控件(从ComboBox继承),并添加一个“UnselectedPromptProperty”作为依赖属性,也可以实现所有这些。然后,显示或隐藏“UnselectedPromptProperty”的逻辑将来自DP上的验证回调。这更高级,但它允许您将非默认样式模板传播到您的控件中,允许其他人重新构建它

您可以通过更改ComboBox ControlTemplate直接在XAML中执行此操作,而不是为了在UI中显示临时值而将数据弄得一团糟。可以在模板中设置触发器,以便在未选择任何内容时交换值

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="SelectedIndex" Value="-1"/>
        <Condition Property="IsDropDownOpen" Value="false"/>
        <Condition Property="HasItems" Value="True"/>
    </MultiTrigger.Conditions>
    <Setter Property="Content" TargetName="Presenter" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"/>
</MultiTrigger>

此版本的另一个优点是,它不允许在进行选择后选择空值。可以通过将标记设置为默认消息来使用它

<ComboBox Tag="Select department..." Template="{StaticResource ComboBoxSelectTemplate}" ItemsSource="{Binding Departments}"/>

这是一个基于默认Aero模板的完整版本,需要添加dll引用和xmlns:Microsoft_Windows_Themes=“clr namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero”(可以用Border和DropShadow效果替换ButtonChrome和SystemDropShadowChrome,以避免添加引用):

m00l3.54l7.0z

使用复合类是我采取的方法。工作得很好,但是我注意到的一件事是,在使用组合集合时,您需要确保每个集合中的类型名称相似,以便在Listbox控件或combobox中显示它们,或者在需要调用DisplayMemeberPath的地方显示它们。我花了大约一个小时来尝试解决这个问题,在返回编写UserControl之前@randyc,我认为这是对你问题的“最终”答案,这就是为什么我增加了投票数。它最接近微软推荐的调整控件的模式,并允许Blend用户进一步修改它。但是,伙计,这是多大的额外XAML啊。是啊,这太烦人了,需要这么多XAML才能在一个部分中对这些复杂的模板做一点小小的更改(Slider更糟糕)。这甚至是剥离下来,以删除所有的组合框可编辑的东西。幸运的是,它都是从Blend为您生成的,您可以在创建它后将其隐藏在ResourceDictionary的某个地方。@Rob回复得很好,非常感谢您花时间用xaml显示完整的示例。您的问题在于,它确实会使用一个组合的集合来破坏数据。我在与此进一步合作中发现,在我的情况下,我需要使用组合集合。这背后的原因是,应用程序要求对非数据绑定元素(即第二个collecton)的事件进行键控,因此我编写了逻辑来评估这些数据绑定之外的选定项。再次感谢您对修改控件的深入了解,这将在未来的项目中派上用场!
<ComboBox Tag="Select department..." Template="{StaticResource ComboBoxSelectTemplate}" ItemsSource="{Binding Departments}"/>
<Geometry x:Key="DownArrowGeometry">M 0 0 L 3.5 4 L 7 0 Z</Geometry>
<Style x:Key="ComboBoxReadonlyToggleButton" TargetType="{x:Type ToggleButton}">
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="IsTabStop" Value="false"/>
    <Setter Property="Focusable" Value="false"/>
    <Setter Property="ClickMode" Value="Press"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}">
                    <Grid HorizontalAlignment="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
                        <Path x:Name="Arrow" Fill="Black" HorizontalAlignment="Center" Margin="3,1,0,0" VerticalAlignment="Center" Data="{StaticResource DownArrowGeometry}"/>
                    </Grid>
                </Microsoft_Windows_Themes:ButtonChrome>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="true">
                        <Setter Property="RenderPressed" TargetName="Chrome" Value="true"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Fill" TargetName="Arrow" Value="#AFAFAF"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<ControlTemplate x:Key="ComboBoxSelectTemplate" TargetType="{x:Type ComboBox}">
    <Grid x:Name="MainGrid" SnapsToDevicePixels="true">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
        </Grid.ColumnDefinitions>
        <Popup x:Name="PART_Popup" Margin="1" AllowsTransparency="true" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Grid.ColumnSpan="2">
            <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}" Color="Transparent">
                <Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
                    <ScrollViewer CanContentScroll="true">
                        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.DirectionalNavigation="Contained"/>
                    </ScrollViewer>
                </Border>
            </Microsoft_Windows_Themes:SystemDropShadowChrome>
        </Popup>
        <ToggleButton Style="{StaticResource ComboBoxReadonlyToggleButton}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
        <ContentPresenter x:Name="Presenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" IsHitTestVisible="false" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"/>
    </Grid>
    <ControlTemplate.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="SelectedIndex" Value="-1"/>
                <Condition Property="IsDropDownOpen" Value="false"/>
                <Condition Property="HasItems" Value="True"/>
            </MultiTrigger.Conditions>
            <Setter Property="Content" TargetName="Presenter" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"/>
        </MultiTrigger>
        <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
            <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
            <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
        </Trigger>
        <Trigger Property="HasItems" Value="false">
            <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            <Setter Property="Background" Value="#FFF4F4F4"/>
        </Trigger>
        <Trigger Property="IsGrouping" Value="true">
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>