เปลี่ยน WPF DataTemplate สำหรับรายการ ListBox หากเลือก


91

ฉันจำเป็นต้องเปลี่ยน DataTemplate สำหรับรายการใน ListBox ขึ้นอยู่กับว่ารายการนั้นถูกเลือกหรือไม่ (แสดงข้อมูลอื่น / เพิ่มเติมเมื่อเลือก)

ฉันไม่ได้รับเหตุการณ์ GotFocus / LostFocus ในองค์ประกอบด้านบนสุดใน DataTemplate (StackPanel) เมื่อคลิกรายการกล่องรายการที่เป็นปัญหา (ผ่านการแท็บเท่านั้น) และฉันไม่มีความคิด

คำตอบ:


185

วิธีที่ง่ายที่สุดคือจัดหาเทมเพลตสำหรับ "ItemContainerStyle" ไม่ใช่คุณสมบัติ "ItemTemplate" ในโค้ดด้านล่างฉันสร้างเทมเพลตข้อมูล 2 เทมเพลต: เทมเพลตหนึ่งสำหรับ "ไม่ได้เลือก" และอีกแบบสำหรับสถานะ "ที่เลือก" จากนั้นฉันจะสร้างเทมเพลตสำหรับ "ItemContainerStyle" ซึ่งเป็น "ListBoxItem" จริงที่มีรายการนั้น ฉันตั้งค่าเริ่มต้น "ContentTemplate" เป็นสถานะ "Unselected" จากนั้นจัดหาทริกเกอร์ที่เปลี่ยนเทมเพลตเมื่อคุณสมบัติ "IsSelected" เป็นจริง (หมายเหตุ: ฉันกำลังตั้งค่าคุณสมบัติ "ItemsSource" ในโค้ดหลังรายการสตริงเพื่อความเรียบง่าย)

<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
ขอขอบคุณโปรดใส่ <ListBox ItemContainerStyle =” {StaticResource ContainerStyle}” ItemsSource =” {Binding MyData}” /> ในโพสต์ของคุณเพื่อให้คนอื่นไม่ต้องค้นหาในบล็อกของคุณ
Shimmy Weitzhandler

2
ปัญหาหนึ่งที่ฉันพบในการตั้งค่า ContainerStyle ของ ListBox คือทำให้ไม่เข้ากันกับธีม ฉันใช้แนวทางของคุณ แต่เมื่อฉันใช้ธีมจาก WPF Futures ตั้งค่า ListBoxItems มีสไตล์เริ่มต้นแทนที่จะเป็นสไตล์ธีม ในกรณีของฉันข้อความสีดำบนพื้นหลังสีดำและความน่าเกลียดทั่วไป ฉันยังคงค้นหาแนวทางอื่นโดยอาจใช้ทริกเกอร์ DataTemplate
Benny Jobigan

1
นอกจากนี้หากคุณต้องการให้ ItemContainerStyle ใหม่ของคุณเข้ากันได้กับธีมคุณต้องยึดตามธีมจากธีม ในการทำเช่นนี้ให้ใช้BasedOn="{StaticResource {x:Type ListBoxItem}}"กับ ListBox นอกจากนี้ยังใช้กับตัวควบคุมอื่น ๆ เช่น TreeView
Benny Jobigan

5
ในการใช้สิ่งนี้ฉันพบว่าฉันต้องประกาศ DataTemplates เหนือสไตล์ในส่วนทรัพยากรเพื่อที่จะไม่ได้รับข้อผิดพลาด XAML อาร์เคน เพียงแค่ทราบเกี่ยวกับเรื่องนั้น
Rob Perkins

8

ในการตั้งค่าสไตล์เมื่อมีการเลือกรายการหรือไม่สิ่งที่คุณต้องทำคือดึงข้อมูลListBoxItemหลักใน<DataTemplate>สไตล์ของคุณและทริกเกอร์เมื่อมีIsSelectedการเปลี่ยนแปลง ตัวอย่างโค้ดด้านล่างจะสร้างTextBlockด้วยเริ่มต้นForegroundสีเขียว ตอนนี้ถ้ารายการที่ได้รับการเลือกตัวอักษรจะเปลี่ยนเป็นสีแดงและเมื่อเมาส์อยู่เหนือรายการที่จะเปลี่ยนเป็นสีเหลือง ด้วยวิธีนี้คุณไม่จำเป็นต้องระบุเทมเพลตข้อมูลแยกกันตามที่แนะนำในคำตอบอื่น ๆ สำหรับทุกรัฐที่คุณต้องการเปลี่ยนแปลงเล็กน้อย

<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
ตามที่ฉันเขียนในคำถามฉันจะแสดงข้อมูลเพิ่มเติมหากเลือกไว้ (" แสดงข้อมูลอื่น / ข้อมูลเพิ่มเติมเมื่อเลือก ") ถึงกระนั้นหากสิ่งนี้สามารถทำให้ใช้งานได้กับการสลับการมองเห็นขององค์ประกอบบางอย่าง (รวมถึงว่ามันใช้ขนาดใหญ่ขึ้นหรือไม่) นี่จะเป็นทางออกที่ใช้ได้ ไม่ได้ทำงานกับ WPF มาระยะหนึ่งแล้ว
Daniel Beck

6

ควรสังเกตด้วยว่าสแต็กพาเนลไม่สามารถโฟกัสได้ดังนั้นจึงไม่ได้รับโฟกัส (ตั้งค่า Focusable = True ถ้าคุณ / ต้องการให้โฟกัสจริงๆ / ต้องการให้โฟกัส) อย่างไรก็ตามสิ่งสำคัญที่ต้องจำในสถานการณ์เช่นนี้คือ Stackpanel เป็นลูกของ TreeViewItem ซึ่งเป็น ItemContainer ในกรณีนี้ ตามที่มีคาแนะนำการปรับแต่งสไตล์คอนเทนเนอร์ของไอเทมเป็นแนวทางที่ดี

คุณอาจทำได้โดยใช้ DataTemplates และสิ่งต่างๆเช่น datatriggers ซึ่งจะใช้ส่วนขยายมาร์กอัป RelativeSouce เพื่อค้นหา listviewitem

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.