2010-06-29 61 views
1

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

例如,除了显示所有部门名称之外,我还需要组合框中可见的第一个元素为“Select department ...” 在进行一些研究时(这里和在线),看起来好像我可能是能够使用复合集合来做到这一点。

http://zamjad.wordpress.com/2010/05/18/using-composite-collection-in-c/

我的问题是情况,我只需要提交一个项目作为组合框中的第一个项目,这是最好的办法?或者还有其他一些我需要看的方法吗?

由于提前,

回答

2

您可以通过更改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}"/> 

下面是基于默认的航空模板,这就需要添加dll引用和xmlns一个完整的版本:Microsoft_Windows_Themes = “CLR-名称空间:Microsoft.Windows.Themes;装配= PresentationFramework.Aero”(该ButtonChrome和SystemDropShadowChrome可以替换为边框和DropShadow效果以避免添加引用):

<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> 
+0

在回写UserControl之前,我花了大约一个小时试图解决这个问题。 @randyc,我会称这为你的问题的“最终”答案,这就是为什么我增加了一个投票权。它最接近Microsoft建议的用于调整控件的模式,并允许Blend用户进一步修改它。但是,男人,这是多少额外的XAML。 – 2010-06-29 15:31:36

+0

是的,这太令人讨厌了,它需要这么多的XAML才能对这些复杂模板的一个部分进行小的更改(滑块更糟糕)。这甚至可以删除所有的ComboBox可编辑的东西。幸运的是,它们都是从Blend为您创建的,您可以在创建它时将它隐藏在ResourceDictionary的某处。 – 2010-06-29 21:34:00

+0

@Rob很好的答复和非常感谢,抽出时间在xaml中显示完整的示例。你的看法在于,它确实使用了一个组合的集合来分解数据。我在这方面发现的进一步是在我的情况下,我需要使用联合收集。其原因是应用程序需要将事件从非数据绑定元素(即第二集合)键入。因此,除了这些数据绑定之外,我已经编写了评估这些选定项的逻辑。再次感谢修改控制的见解,这将在未来的项目中派上用场! – rlcrews 2010-06-30 01:25:56

0

我使用的复合类,包括嵌入式援助在组合框(“选择部门...”),我觉得它工作得很好。

一旦用户选择一个部门,我建议删除嵌入式协助。

+0

使用组合类是我采用的方法。工作很好,但我注意到的一件事是,当使用Combined集合时,需要确保每个集合中的类型名称与需要在Listbox控件或组合框中显示它们的情况类似,或者需要调用DisplayMemeberPath 。 – rlcrews 2010-06-29 12:49:27

1

听起来好像你想要的是某些元素在没有被选中时可见,并且看起来是组合框的一部分,但是在进行选择时不可见。最简单的,你可以设计一个拥有你的ComboBox的UserControl(如果你在代码中添加项目而不是一些静态的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> 

然后,在代码隐藏,插入一些逻辑在事件处理程序:

Private Sub ComboBoxControl_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) 
    If ComboBoxControl.SelectedIndex = -1 Then 
     UnselectedText.Visibility = Windows.Visibility.Visible 
    Else 
     UnselectedText.Visibility = Windows.Visibility.Hidden 
    End If 
End Sub 

上的TextBlock设置IsHitTestVisible="False"的DependencyProperty通过让鼠标事件,以便您可以点击组合框,并在代码隐藏中将可见性设置为Hidden,可在隐藏提示文本时保持默认组合框外观的布局不会跳跃。

当然,所有这些也都可以通过创建一个MyComboBox自定义控件来完成,该控件从ComboBox继承,添加了“UnselectedPromptProperty”作为依赖属性。然后,显示或隐藏“UnselectedPromptProperty”的逻辑将来自DP上的验证回调。这是更先进的,但它可以让你传播非默认风格模板到你的控制,允许其他人reskin它。