2010-06-29 33 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它。