Ändern Sie das WPF DataTemplate für ListBox-Element, falls ausgewählt

89

Ich muss die DataTemplate für Elemente in einer ListBox ändern, je nachdem, ob das Element ausgewählt ist oder nicht (bei Auswahl anderer / weiterer Informationen).

Ich erhalte kein GotFocus / LostFocus-Ereignis für das oberste Element in der DataTemplate (ein StackPanel), wenn ich auf das betreffende ListBox-Element klicke (nur durch Tabulieren), und ich habe keine Ideen mehr.

Daniel Beck
quelle

Antworten:

181

Der einfachste Weg, dies zu tun, besteht darin, eine Vorlage für die Eigenschaft "ItemContainerStyle" und NICHT für die Eigenschaft "ItemTemplate" bereitzustellen. Im folgenden Code erstelle ich zwei Datenvorlagen: eine für den "nicht ausgewählten" und eine für den "ausgewählten" Status. Ich erstelle dann eine Vorlage für den "ItemContainerStyle", der das eigentliche "ListBoxItem" ist, das den Artikel enthält. Ich habe die Standardeinstellung "ContentTemplate" auf den Status "Nicht ausgewählt" gesetzt und dann einen Auslöser angegeben, der die Vorlage austauscht, wenn die Eigenschaft "IsSelected" wahr ist. (Hinweis: Der Einfachheit halber setze ich die Eigenschaft "ItemsSource" im Code dahinter auf eine Liste von Zeichenfolgen.)

<Window.Resources>

<DataTemplate x:Key="ItemTemplate">
    <TextBlock Text="{Binding}" Foreground="Red" />
</DataTemplate>

<DataTemplate x:Key="SelectedTemplate">
    <TextBlock Text="{Binding}" Foreground="White" />
</DataTemplate>

<Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
    <Setter Property="ContentTemplate" Value="{StaticResource ItemTemplate}" />
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}" />
        </Trigger>
    </Style.Triggers>
</Style>

</Window.Resources>
<ListBox x:Name="lstItems" ItemContainerStyle="{StaticResource ContainerStyle}" />
Micah
quelle
Vielen Dank, bitte fügen Sie die <ListBox ItemContainerStyle = ”{StaticResource ContainerStyle}” ItemsSource = ”{Binding MyData}” /> in Ihren Beitrag ein, damit die Leute nicht in Ihrem Blog suchen müssen.
Shimmy Weitzhandler
1
Ein Problem beim Festlegen des ContainerStyle der ListBox ist, dass es zu Inkompatibilitäten mit Themen führt. Ich habe Ihren Ansatz verwendet, aber als ich das a-Thema aus dem WPF-Futures-Set angewendet habe, hatten die ListBoxItems das Standard-Styling anstelle des Theme-Stylings. In meinem Fall schwarzer Text auf schwarzem Hintergrund und allgemeine Hässlichkeit. Ich suche immer noch nach einem anderen Ansatz, möglicherweise mithilfe von DataTemplate-Triggern.
Benny Jobigan
Wenn Sie möchten, dass Ihr neuer ItemContainerStyle mit Themen kompatibel ist, müssen Sie ihn auf dem des Themas basieren. Verwenden Sie dazu BasedOn="{StaticResource {x:Type ListBoxItem}}"ListBox. Dies gilt auch für andere Steuerelemente wie TreeView.
Benny Jobigan
5
Dabei musste ich die DataTemplates über dem Style im Abschnitt Resources deklarieren, um keine arkanen XAML-Fehler zu erhalten. Nur ein Heads-up dazu.
Rob Perkins
8

Um den Stil festzulegen, wenn das Element ausgewählt ist oder nicht, müssen Sie nur das ListBoxItemübergeordnete Element in Ihrem Element abrufen <DataTemplate>und Stiländerungen auslösen, wenn es sich IsSelectedändert. Zum Beispiel wird der Code unten ein erstellen TextBlockmit ForegroundStandardfarbe grün . Wenn nun das Element ausgewählt wird, wird die Schrift rot und wenn sich die Maus über dem Element befindet, wird sie gelb . Auf diese Weise müssen Sie nicht für jeden Status, den Sie geringfügig ändern möchten, separate Datenvorlagen angeben, wie in anderen Antworten vorgeschlagen.

<DataTemplate x:Key="SimpleDataTemplate">
    <TextBlock Text="{Binding}">
        <TextBlock.Style>
            <Style>
                <Setter Property="TextBlock.Foreground" Value="Green"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={
                        RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem }}}"
                                 Value="True">
                        <Setter Property="TextBlock.Foreground" Value="Red"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={
                        RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem }}}"
                                 Value="True">
                        <Setter Property="TextBlock.Foreground" Value="Yellow"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</DataTemplate>
Darien Pardinas
quelle
1
Wie ich in der Frage geschrieben habe, zeige ich bei Auswahl tatsächlich mehr Informationen an (" Anzeige anderer / mehr Informationen bei Auswahl "). Wenn dies jedoch dazu beitragen könnte, die Sichtbarkeit einiger Elemente umzuschalten (einschließlich der Frage, ob sie Größe annehmen), wäre dies eine praktikable Lösung. Ich habe schon eine Weile nicht mehr mit WPF gearbeitet.
Daniel Beck
6

Es sollte auch beachtet werden, dass das Stackpanel nicht fokussierbar ist, so dass es niemals fokussiert wird (setzen Sie Focusable = True, wenn Sie / wirklich / wollen, dass es fokussiert wird). Um jedoch die Schlüssel in Szenarien zu erinnern , wie das ist , dass der Stackpanel ist Kind des TreeViewItem, die die ItemContainer in diesem Fall sind. Wie Micah vorschlägt, ist es ein guter Ansatz, den Itemcontainerstyle zu optimieren.

Sie könnten dies wahrscheinlich mit DataTemplates und Dingen wie Datatriggern tun, die die RelativeSouce-Markup-Erweiterung verwenden würden, um nach dem Listenansichtselement zu suchen

Dominic Hopton
quelle