ListBox öğesi için WPF DataTemplate seçiliyse değiştirin


91

Bir ListBox içindeki öğeler için DataTemplate öğenin seçilip seçilmediğine bağlı olarak değiştirmem gerekiyor (seçildiğinde farklı / daha fazla bilgi görüntüleniyor).

Söz konusu ListBox öğesine tıkladığımda (yalnızca sekme yoluyla) DataTemplate'teki (bir StackPanel) en üstteki öğede bir GotFocus / LostFocus olayı görmüyorum ve fikirlerim tükendi.

Yanıtlar:


184

Bunu yapmanın en kolay yolu, "ItemContainerStyle" için bir şablon sağlamaktır, "ItemTemplate" özelliği DEĞİLDİR. Aşağıdaki kodda 2 veri şablonu oluşturuyorum: biri "seçilmemiş" ve diğeri "seçili" durumlar için. Ardından, öğeyi içeren gerçek "ListBoxItem" olan "ItemContainerStyle" için bir şablon oluşturuyorum. Varsayılan "ContentTemplate" öğesini "Unselected" durumuna ayarladım ve ardından "IsSelected" özelliği doğru olduğunda şablonu değiştiren bir tetikleyici sağladım. (Not: Basit olması için, kodun arkasındaki "ItemsSource" özelliğini bir dizeler listesine ayarlıyorum)

<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}" />

1
Teşekkürler, lütfen gönderinize <ListBox ItemContainerStyle = ”{StaticResource ContainerStyle}” ItemsSource = ”{Binding MyData}” /> ekleyin, böylece insanlar blogunuzda arama yapmak zorunda kalmazlar.
Shimmy Weitzhandler

2
ListBox'ın ContainerStyle'ını ayarlarken karşılaştığım bir sorun, temalarla uyumsuzluğa neden olmasıdır. Yaklaşımınızı kullandım, ancak WPF Futures'tan bir temayı uyguladığımda ListBoxItems tema stili yerine varsayılan stillere sahipti. Benim durumumda, siyah zemin üzerine siyah metin ve genel çirkinlik. Hala başka bir yaklaşım arıyorum, belki de DataTemplate tetikleyicileri kullanarak.
Benny Jobigan

1
Ayrıca, yeni ItemContainerStyle'ınızın temalarla uyumlu olmasını istiyorsanız, bunu temadaki olanı temel almalısınız. Bunu yapmak BasedOn="{StaticResource {x:Type ListBoxItem}}"için ListBox ile kullanın. Bu aynı zamanda TreeView gibi diğer kontroller için de geçerlidir.
Benny Jobigan

5
Bunu kullanırken, gizli XAML hatalarını almamak için DataTemplates'i Kaynaklar bölümündeki Stilin üzerinde beyan etmem gerektiğini fark ettim. Bununla ilgili bir uyarı.
Rob Perkins

8

Öğe seçildiğinde veya değilken stili ayarlamak için yapmanız gereken tek şey, ListBoxItemüst öğenizdeki üst öğeyi almak <DataTemplate>ve değiştiğinde stil değişikliklerini tetiklemektir IsSelected. Örneğin aşağıdaki kod bir yaratacak TextBlockvarsayılan ile Foregroundrenk yeşil . Şimdi öğe seçilirse yazı tipi kırmızıya dönecek ve fare üzerindeyken öğe sarıya dönecektir . Bu şekilde, biraz değiştirmek istediğiniz her durum için diğer yanıtlarda önerildiği gibi ayrı veri şablonları belirtmenize gerek kalmaz.

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

1
Soruya yazdığım gibi, seçildiyse aslında daha fazla bilgi gösteriyorum ("seçildiğinde farklı / daha fazla bilgi gösteriliyor "). Yine de, bu, bazı öğelerin görünürlüğünün değiştirilmesiyle (boyut alıp almadıkları dahil) işe yarayacaksa, bu uygulanabilir bir çözüm olacaktır. Yine de bir süredir WPF ile çalışmadım.
Daniel Beck

6

Ayrıca, yığın panelinin odaklanabilir olmadığı, bu nedenle asla odaklanmayacağı da belirtilmelidir (Odaklanabilir = Doğru olarak ayarlayın, eğer / gerçekten / odaklanmak istiyorsanız). Bununla birlikte, bunun gibi senaryolarda hatırlanması gereken anahtar , Stackpanel'in bu durumda ItemContainer olan TreeViewItem'in alt öğesi olmasıdır . Micah'ın önerdiği gibi, itemcontainer tarzını değiştirmek iyi bir yaklaşımdır.

Muhtemelen bunu DataTemplates kullanarak ve listviewitem'i aramak için RelativeSouce biçimlendirme uzantısını kullanan veri tetikleyiciler gibi şeyler kullanarak yapabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.