2010-02-06 8 views
7

Ich möchte eine benutzerdefinierte Vorlage/ein Element als ausgewähltes Element in ComboBox anzeigen (dieses Element existiert nicht tatsächlich in der Liste der Elemente und wird anders aktualisiert). Dies muss nicht einmal ein Gegenstand sein, nur wenn eine benutzerdefinierte Ansicht funktionieren würde.WPF: So passen Sie SelectionBoxItem in ComboBox

Wie kann ich dies tun, während ich im aktuellen ComboBox-Design bleibe (also kein ControlTemplate-Austausch möglich)? Soweit ich sehe, sind alle SelectionBox * -Eigenschaften nicht editierbar und ComboBox verwendet intern den unbenannten ContentPresenter.

+0

Dies ist lickly Benutzer zu verwirren, erwarten die Menschen eine Combro Box als Combro Box zu verhalten. –

+0

Nun, es ist eine ComboBox mit CheckBoxes, die ungewöhnlich sein könnte, aber ich würde nicht sagen, dass dies zu verwirrend ist (oder Evil). Das Verwenden eines zusätzlichen Popup-Fensters fühlt sich an wie ein Overkill und dieses Element ist einfach nicht wichtig genug, um eine CheckBox-Liste voller Größe zu sein. –

+0

Offensichtlich kann ich ein ausgewähltes Element nicht anzeigen, da ich kein einzelnes ausgewähltes Element habe. –

Antwort

18

Ich würde es tun, wie folgt:

<Window.Resources> 

    <DataTemplate x:Key="NormalItemTemplate" ...> 
    ... 
    </DataTemplate> 

    <DataTemplate x:Key="SelectionBoxTemplate" ...> 
    ... 
    </DataTemplate> 

    <DataTemplate x:Key="CombinedTemplate"> 
    <ContentPresenter x:Name="Presenter" 
     Content="{Binding}" 
     ContentTemplate="{StaticResource NormalItemTemplate}" /> 
    <DataTemplate.Triggers> 
     <DataTrigger 
     Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}" 
     Value="{x:Null}"> 
     <Setter TargetName="Presenter" Property="ContentTemplate" 
       Value="{StaticResource SelectionBoxTemplate}" /> 
     </DataTrigger> 
    </DataTemplate.Triggers> 
    </DataTemplate> 

</Window.Resources> 

... 

<ComboBox 
    ItemTemplate="{StaticResource CombinedTemplate}" 
    ItemsSource="..." 
    ... /> 

Der Grund dieser Arbeiten ist, dass CombinedTemplate normalerweise NormalItemTemplate nur verwendet, um seine Daten zu präsentieren, aber wenn es keine ComboBoxItem Vorfahren nimmt es in der Auswahlbox so Es verwendet SelectionBoxTemplate.

Beachten Sie, dass die drei DataTemplates in jeder Ebene der ResourceDictionary berücksichtigt werden kann (und nicht nur auf der Ebene Window) oder sogar direkt im ComboBox, je nach Ihren Wünschen.

+0

Danke, ich werde es definitiv versuchen. –

+0

Es ist eine elegante * und * funktionierende Lösung, vielen Dank! –

+2

Dies erzeugt jedoch eine Bindungsausnahme: 'Quelle für Bindung mit Verweis nicht gefunden 'RelativeSource FindAncestor, AncestorType =' System.Windows.Controls.ComboBoxItem ', AncestorLevel =' 1'''. Ich denke, die Einstellung 'ItemTemplateSelector' ist ein besserer Ansatz. Hier ein Beispiel: http://social.msdn.microsoft.com/Forums/vstudio/en-US/0467c9ca-efb2-4506-96e7-08ce3356860a/combobox-one-template-for-selected-item-one-for -die-dropdown-list? forum = wpf –

-1

Sie müssen in Triggers und Styles suchen. Sie könnten auch in einige meiner älteren Fragen hier auf Stackoverflow sehen möchten, dass mich diese Probleme zu überwinden half:

+0

Danke, das war leider etwas zu abstrakt im Vergleich zu anderen Antworten. Ich habe eine allgemeine Vorstellung davon, wie Auslöser funktionieren, es war die {x: Null} -Lösung, die ich nicht erfinden konnte. –

0

Wenn ich diese gerade haben, möchten Sie eine Steuerung, hat etwas willkürlich angezeigt zusammen mit einem Dropdown-Button, der eine Liste von Elementen mit Kontrollkästchen neben ihnen anzeigt?

Ich würde nicht einmal versuchen, eine ComboBox zu reformieren, um dies zu erreichen. Das Problem ist, dass ComboBox ist mehr spezialisiert auf einen anderen Weg als was Sie brauchen. Wenn Sie sich die ComboBox ControlTemplate Example ansehen, sehen Sie, dass es einfach ein Popup Steuerelement verwendet, um die Liste der möglichen Werte anzuzeigen.

Sie können Teile dieser Vorlage als Anleitung zum Erstellen einer UserControl nehmen, die einfacher zu verstehen ist und besser bietet, was Sie wollen. Sie können sogar eine SelectedItems Eigenschaft hinzufügen und so, dass ComboBox nicht zur Verfügung stellt.

Ein Beispiel dafür, was ich unter Anleitung verstehe: Die Popup hat eine IsOpen Eigenschaft. In der Steuerelementvorlage ist es auf {TemplateBinding IsDropDownOpen} festgelegt, was bedeutet, dass die ComboBox Klasse eine IsDropDownOpen Eigenschaft aufweist, die geändert wird, um das Erweitern/Zusammenfalten der zu steuern.

+0

Das Problem mit benutzerdefinierten Steuerelementen besteht darin, dass sie nicht über integrierte Stile formatiert sind. Ich habe bereits ein benutzerdefiniertes Steuerelement mit SelectedItems erstellt, aber im Inneren beruht es auf einer ComboBox, da ich mit Standardstilen arbeiten möchte, ohne sie zu wiederholen. –

0

Alexey Mitev Kommentar zu Ray Burns answer mich inspiriert die folgende überschaubaren Utility-Klasse zu schreiben, die ich jetzt in meinem WPF-Projekte verwenden:

public class ComboBoxItemTemplateSelector : DataTemplateSelector 
{ 
    public List<DataTemplate> SelectedItemTemplates { get; } = new List<DataTemplate>(); 
    public List<DataTemplate> DropDownItemTemplates { get; } = new List<DataTemplate>(); 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     return GetVisualParent<ComboBoxItem>(container) == null 
      ? ChooseFrom(SelectedItemTemplates, item) 
      : ChooseFrom(DropDownItemTemplates, item); 
    } 

    private static DataTemplate ChooseFrom(IEnumerable<DataTemplate> templates, object item) 
    { 
     if (item == null) 
      return null; 
     var targetType = item.GetType(); 
     return templates.FirstOrDefault(t => (t.DataType as Type) == targetType); 
    } 

    private static T GetVisualParent<T>(DependencyObject child) where T : Visual 
    { 
     while (child != null && !(child is T)) 
      child = VisualTreeHelper.GetParent(child); 
     return child as T; 
    } 
} 

Damit in der Toolbox ist es möglich, schreiben XAML wie folgt aus:

<UserControl.Resources> 
    <DataTemplate x:Key="SelectedItemTemplateForInt" DataType="{x:Type system:Int32}"> 
     <!-- ... --> 
    </DataTemplate> 

    <DataTemplate x:Key="SelectedItemTemplateForDouble" DataType="{x:Type system:Double}"> 
     <!-- ... --> 
    </DataTemplate> 

    <DataTemplate x:Key="DropDownItemTemplateForInt" DataType="{x:Type system:Int32}"> 
     <!-- ... --> 
    </DataTemplate> 

    <DataTemplate x:Key="DropDownItemTemplateForDouble" DataType="{x:Type system:Double}"> 
     <!-- ... --> 
    </DataTemplate> 
</UserControl.Resources> 

<ComboBox> 
    <ComboBox.ItemTemplateSelector> 
     <local:ComboBoxItemTemplateSelector> 
      <local:ComboBoxItemTemplateSelector.SelectedItemTemplates> 
       <StaticResource ResourceKey="SelectedItemTemplateForInt" /> 
       <StaticResource ResourceKey="SelectedItemTemplateForDouble" /> 
      </local:ComboBoxItemTemplateSelector.SelectedItemTemplates> 

      <local:ComboBoxItemTemplateSelector.DropDownItemTemplates> 
       <StaticResource ResourceKey="DropDownItemTemplateForInt" /> 
       <StaticResource ResourceKey="DropDownItemTemplateForDouble" /> 
      </local:ComboBoxItemTemplateSelector.DropDownItemTemplates> 
     </local:ComboBoxItemTemplateSelector> 
    </ComboBox.ItemTemplateSelector> 
</ComboBox>