Thay đổi WPF DataTemplate cho mục ListBox nếu được chọn


89

Tôi cần thay đổi DataTemplate cho các mục trong ListBox tùy thuộc vào việc mục đó có được chọn hay không (hiển thị các thông tin khác nhau / nhiều hơn khi được chọn).

Tôi không nhận được sự kiện GotFocus / LostFocus trên phần tử cao nhất trong DataTemplate (một StackPanel) khi nhấp vào mục ListBox được đề cập (chỉ thông qua tab) và tôi không có ý tưởng.

Câu trả lời:


182

Cách dễ nhất để làm điều này là cung cấp một mẫu cho thuộc tính "ItemContainerStyle" chứ KHÔNG phải thuộc tính "ItemTemplate". Trong đoạn mã dưới đây, tôi tạo 2 mẫu dữ liệu: một cho trạng thái "không được chọn" và một cho trạng thái "đã chọn". Sau đó, tôi tạo một mẫu cho "ItemContainerStyle" là "ListBoxItem" thực tế có chứa mục. Tôi đặt "ContentTemplate" mặc định thành trạng thái "Không được chọn", sau đó cung cấp trình kích hoạt hoán đổi mẫu khi thuộc tính "IsSelected" là true. (Lưu ý: Tôi đang đặt thuộc tính "ItemsSource" trong mã phía sau thành danh sách các chuỗi để đơn giản hóa)

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

Cảm ơn bạn, vui lòng bao gồm <ListBox ItemContainerStyle = ”{StaticResource ContainerStyle}” ItemsSource = ”{Binding MyData}” /> trong bài đăng của bạn, để mọi người không phải tìm kiếm trong blog của bạn.
Shimmy Weitzhandler 09/09/09

2
Một vấn đề tôi gặp phải khi đặt ContainerStyle của ListBox là nó gây ra sự không tương thích với các chủ đề. Tôi đã sử dụng cách tiếp cận của bạn, nhưng khi tôi áp dụng một chủ đề từ bộ WPF Futures, ListBoxItems có kiểu mặc định thay vì kiểu chủ đề. Trong trường hợp của tôi, văn bản màu đen trên nền đen và sự xấu xí nói chung. Tôi vẫn đang tìm kiếm một cách tiếp cận khác, có lẽ là sử dụng trình kích hoạt DataTemplate.
Benny Jobigan

1
Ngoài ra, nếu bạn muốn ItemContainerStyle mới của mình tương thích với các chủ đề, bạn phải căn cứ vào nó từ chủ đề. Để làm điều này, hãy sử dụng BasedOn="{StaticResource {x:Type ListBoxItem}}"với ListBox. Điều này cũng áp dụng cho các điều khiển khác như TreeView.
Benny Jobigan

5
Khi sử dụng cái này, tôi thấy rằng tôi phải khai báo DataTemplates phía trên Style trong phần Resources để không mắc lỗi XAML phức tạp. Chỉ cần lưu ý về điều đó.
Rob Perkins

8

Để đặt kiểu khi mục được chọn hoặc không, tất cả những gì bạn cần làm là truy xuất mục ListBoxItemgốc trong của bạn <DataTemplate>và kích hoạt các thay đổi kiểu khi mục đó IsSelectedthay đổi. Ví dụ, đoạn mã dưới đây sẽ tạo ra một TextBlockvới Foregroundmàu mặc định là xanh lục . Bây giờ nếu mục được chọn, phông chữ sẽ chuyển sang màu đỏ và khi chuột qua mục đó sẽ chuyển sang màu vàng . Bằng cách đó, bạn không cần chỉ định các mẫu dữ liệu riêng biệt như được đề xuất trong các câu trả lời khác cho mọi trạng thái mà bạn muốn thay đổi một chút.

<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
Như tôi đã viết trong câu hỏi, tôi thực sự hiển thị nhiều thông tin hơn nếu được chọn (" hiển thị các thông tin khác / nhiều hơn khi được chọn "). Tuy nhiên, nếu điều này có thể được thực hiện để làm việc với khả năng hiển thị chuyển đổi của một số yếu tố (bao gồm cả việc chúng có chiếm kích thước hay không), thì đây sẽ là một giải pháp khả thi. Tuy nhiên, đã không làm việc với WPF trong một thời gian.
Daniel Beck

6

Cũng cần lưu ý rằng bảng điều khiển ngăn xếp không thể tạo được, vì vậy nó sẽ không bao giờ lấy được tiêu điểm (đặt Focusable = True nếu bạn / thực sự / muốn nó tập trung). Tuy nhiên, điều quan trọng cần nhớ trong các trường hợp như thế này là Stackpanel là con của TreeViewItem, là ItemContainer trong trường hợp này. Như Micah gợi ý, điều chỉnh phong cách vật phẩm là một cách tiếp cận tốt.

Bạn có thể làm điều đó bằng cách sử dụng DataTemplates và những thứ như bộ đo dữ liệu sẽ sử dụng tiện ích mở rộng đánh dấu RelativeSouce để tìm kiếm listviewitem

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.