Laden...

ComboBox - nicht alles aus DropDown übernehmen

Erstellt von Fr3dd1 vor 12 Jahren Letzter Beitrag vor 12 Jahren 3.738 Views
F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren
ComboBox - nicht alles aus DropDown übernehmen

Hallo zusammen,

ich habe mal wieder eine Frage zur ComboBox aus WPF. Und zwar will ich im DropDown Menü der ComboBox zwei Informationen anzeigen, bei einer Selektion soll aber nur eine Information übernommen werden. Wie kann ich sowas umsetzen? Habe es bisher so versucht, die beiden Informationen in einen String zu packen und die hintere Information bei der Selektion einfach abzuschneiden (sind immer 4 Zeichen). Funktioniert soweit auch, nur wenn man ein zweites Mal in die ComboBox klickt, wird wieder alles ausgewält.

Gruß Fr3dd1

821 Beiträge seit 2009
vor 12 Jahren

Was verstehst du unter "soll aber nur eine Information übernommen werden"?
Meinst du damit im GUI Angezeigt werden oder in der Logik ausgewertet werden?

Gruß
Christoph

F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren

Die Text-Property soll nur eine Information beinhalten, visuell und logisch.

Z
403 Beiträge seit 2007
vor 12 Jahren

Hallo Fr3dd1,

was du meinst ist mir auch nicht klar,
warum nicht eine ItemsSource an die ComboBox binden ?

T
146 Beiträge seit 2004
vor 12 Jahren

Das geht über nen Templateselektor.

Du musst für aufgeklappt und für zugeklappt verschiedene Templates erstellen, und diese dann zuweisen. Hab da mal nen Artikel auf Codeproject gelesen glaub ich. Kann selbigen aber gerade leider nicht finden.

P
660 Beiträge seit 2008
vor 12 Jahren

Wäre ein Converter nicht eine Lösung?

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

U
1.578 Beiträge seit 2009
vor 12 Jahren

Ein DataTemplateSelector ist die einzigste saubere Lösung, alles andere ist Gefummel und Trixerei. Genau dafür ist diese funktionalität vorhancen.

if item.IsSelected then
    return ShortTemplate
else
    return NormalTemplate
end if
F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren

Habe mich mal ein bischen in den TamplateSelector eingelesen aber habe noch ein Problem.

Die Templates kann ich als Resource anlegen und auch an den Selector übergeben. Ich bekomme nur die Abfrage im Selector nicht hin, wann das eine und wann das andere ausgewählt werden soll.

Momentan habe ich das so:

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if ((item as ComboBoxItem).IsSelected)
                return ClosedTemplate;
            else
                return OpenedTemplate;
        }

Mittlerweile weis ich, das "Item" eine Zeile meines Typs ist, und kein ComboBoxItem. Wie kann ich denn jetzt abfragen ob die ComboBox geöffnet oder geschloßen ist?

F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren

Ich konnte den Selector jetzt so umschreiben, dass es zumindest keine Exception mehr gibt. Ich glaube auch das es wie folgt funktioniert:

public class SuggestTemplateSelector : DataTemplateSelector
    {
        public DataTemplate OpenedTemplate { get; set; }
        public DataTemplate ClosedTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if ((container as ContentPresenter).TemplatedParent is ComboBox)
                return ClosedTemplate;
            else
                return OpenedTemplate;
        }
    }

Das einzige Problem ist nur, dass die ComboBox nicht den richtigen Wert übernimmt, sondern den Klassennamen anzeigt. Weiß jemand wie ich das noch Lösen kann?

F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren

Konnte mir auch die letzte Frage selber beantworten, die ToString() Methode der Klasse war nicht überschrieben...

Allerdings wird das Template für den geschloßenen Zustand gar nicht verwendet, kann jemand sagen warum?

U
1.578 Beiträge seit 2009
vor 12 Jahren

Hast du OpenedTemplate und ClosedTemplate auch gesetzt?

Ich mach das immer so:

<Window.Resources>
    <Controls:DetailsTemplateSelector x:Key="DetailsTemplateSelector" />
</Window.Resources>

<ComboBox ItemsSource="{Binding Items}"
                   ItemTemplateSelector="{StaticResource DetailsTemplateSelector}">
    <ComboBox.Resources>
        <DataTemplate x:Key="Opened">
            <StackPanel>
                <TextBlock Text="{Binding First}" />
                <TextBlock Text="{Binding Second}" />
            </StackPanel>
        </DataTemplate>
        <DataTemplate x:Key="Closed">
            <TextBlock Text="{Binding First}" />
        </DataTemplate>
    </ComboBox.Resources>
</ComboBox>
public class DetailsTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var parent = ((FrameworkElement)container).TemplatedParent;
        if (parent is ComboBox)
            return ((ComboBox)parent).FindResource("Closed") as DataTemplate;
        else if (parent is ComboBoxItem)
            return ((ComboBoxItem)parent).FindResource("Opened") as DataTemplate;
        return null;
    }
}

Das tut auch, grad ma probiert.

F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren

jo, habe ich auch gemacht. Er nimmt jedoch nicht das Template sondern gibt mir einfach nur die .toString() ausgabe meines Objects zurück. Die habe ich jetzt dementsprechend angepasst.

U
1.578 Beiträge seit 2009
vor 12 Jahren

Wie sehn deine Templates aus?

F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren

Im geschloßenem Zustand:


            DataTemplate dataTemplate = new DataTemplate();
            dataTemplate.DataType = typeof(SuggestedAttributeValueInfo);
            Binding binding = new Binding();
            binding.Path = new PropertyPath("Unit");

            FrameworkElementFactory textElement = new FrameworkElementFactory(typeof(TextBlock));
            textElement.SetBinding(TextBlock.TextProperty, binding);

            dataTemplate.VisualTree = textElement;
            return dataTemplate;

Im geöffnetem Zustand:


            DataTemplate dataTemplate = new DataTemplate();
            dataTemplate.DataType = typeof(SuggestedAttributeValueInfo);
            Binding binding1 = new Binding();
            binding1.Path = new PropertyPath("Unit");

            Binding binding2 = new Binding();
            binding2.Path = new PropertyPath("Count");

            MultiBinding mb = new MultiBinding();
            mb.StringFormat = "{0} [{1}]";
            mb.Bindings.Add(binding1);
            mb.Bindings.Add(binding2);

            FrameworkElementFactory textElement = new FrameworkElementFactory(typeof(TextBlock));
            textElement.SetBinding(TextBlock.TextProperty, mb);

            dataTemplate.VisualTree = textElement;
            return dataTemplate;
U
1.578 Beiträge seit 2009
vor 12 Jahren

Warum zum Geier machst du die Templates im Code? Sowas les ich prinzipiell nicht durch 😁

F
Fr3dd1 Themenstarter:in
106 Beiträge seit 2010
vor 12 Jahren

Das Ganze soll an mehreren Stellen verfügbar sein und einfach zu implementieren. Da hab ich mir die Templates einmal im Code gemacht und werden auch direkt angewandt.

U
1.578 Beiträge seit 2009
vor 12 Jahren

Dann packs in einem Globalen "Styles" ResourceDictionary.
Einfacher als XAML geht nicht, Template im C# Code ist um Welten schlechter zu Maintainen.