Tiêu đề TreeViewItem sẽ không kéo dài?
Sự cố này xảy ra do mẫu mặc định của WPF cho TreeViewItem
được thiết lập dưới dạng 3 cột theo 2 hàng Grid
. Hàng đầu tiên dành cho "tiêu đề" (thực tế là Border
) và hàng thứ hai là dành cho số ItemsPresenter
. Hai hàng được hiển thị hoặc ẩn khi cần thiết, để hoàn thành việc mở rộng cây khi bạn nhấp vào hình tam giác nhỏ - chiếm không cột số Grid
.
Cả hai hàng thực sự chỉ cần một cột bổ sung. Ví dụ, trong hàng thứ hai, chúng ta không có gì ở col-0, row-1, bởi vì phần trống đó sẽ được thụt vào khi IsExpanded
là đúng. Nhưng bí ẩn bắt đầu khi chúng tôi lưu ý rằng ItemsPresenter
, có trụ sở tại col-1, hàng-1, chỉ định Grid.ColumnSpan=2
.
Thật không may ở hàng trên cùng, Border
giữ tiêu đề được đặt thành Grid.Column=1
... nhưng không có ColumnSpan. Vì col-2 của Grid
có Width=*
điều này có nghĩa là tiêu đề/đường viền sẽ không kéo theo chiều ngang.
Nói cách khác, tôi có vẻ như thiết kế lưới 3 cột không có mục đích ngoại trừ đặc biệt để ngăn tiêu đề kéo dài.Theo như tôi có thể nói, một sắp xếp 2x2 đơn giản sẽ linh hoạt hơn [chỉnh sửa: xem chú thích # 2] và hỗ trợ hoặc kéo dài toàn bộ tiêu đề không bị kéo dài, thông qua các cơ chế liên kết WPF
thông thường.
Lý tưởng nhất, chúng tôi muốn thay đổi Grid
chỉ có 2 cột thay vì 3. Kể từ đó không phải là dễ dàng như vậy, thay vì chúng tôi sẽ làm cho khoảng tiêu đề 2 cột, giống như ItemsPresenter
làm.
Ok, đây là một nhỏ, hoàn chỉnh, khép kín (XAML-only) chương trình mà chứng minh làm việc - và các bản sửa lỗi - các vấn đề:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/netfx/2007/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:r="clr-namespace:System.Reflection;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Width="800" SizeToContent="Manual">
<TreeView ItemsSource="{Binding Source={StaticResource data}}"
VirtualizingStackPanel.VirtualizationMode="Recycling"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Item">
<TreeView.Resources>
<ObjectDataProvider x:Key="data" ObjectInstance="{x:Static sys:AppDomain.CurrentDomain}" MethodName="GetAssemblies" />
<HierarchicalDataTemplate DataType="{x:Type r:Assembly}" ItemsSource="{Binding Path=DefinedTypes}" >
<TextBlock Text="{Binding Path=Location}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type sys:Type}" ItemsSource="{Binding Path=CustomAttributes}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type r:CustomAttributeData}" ItemsSource="{Binding Path=ConstructorArguments}">
<TextBlock Text="{Binding Path=AttributeType.Name}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- == == BEGIN HERE == == -->
<Style.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Grid.ColumnSpan" Value="2" />
</Style>
</Style.Resources>
<!-- == == == END == == == -->
<Setter Property="Background" Value="LightBlue" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Window>
Nếu bạn chạy chương trình này như thể hiện bạn sẽ thấy một cái gì đó như thế này. Đây là hành vi cố định, cho phép bạn lấy lại toàn quyền kiểm soát các hành vi kéo dài của TreeViewItem
tiêu đề:

Thông báo BEGIN/END phần với đường chấm trong nguồn XAML. Về cơ bản, tôi chỉ đặt Grid.ColumnSpan=2
trên vi phạm Border
, để nó sẽ lấp đầy chiều rộng kéo dài của Grid
. Phần tử đó được phát ra bởi mẫu TreeViewItem
, vì vậy tôi nhận thấy rằng một cách hiệu quả để thay đổi thuộc tính của nó là thông qua nhắm mục tiêu Style
trong từ điển tài nguyên của TreeViewItem
's Style
. Vâng, khó hiểu. Bạn có thể truy cập Style
qua TreeViewItem.ItemContainerStyle
.
Để xem (hiện có) hành vi bị hỏng, bạn có thể nhận xét ra phần giữa đường chấm:

Bạn cũng có thể thiết lập các phong cách trong một số từ điển tài nguyên, thay vì sử dụng ItemContainerStyle
bất động sản như tôi đã làm ở đây. Tôi đã làm theo cách này bởi vì nó giảm thiểu phạm vi sửa chữa, do đó các điều khiển Border
không liên quan sẽ không bị ảnh hưởng. Nếu bạn cần một cách phân biệt đối xử hơn để nhắm mục tiêu điều khiển này, bạn có thể tận dụng lợi thế của thực tế là nó có Name='Bd'
.
[sửa:] Giải pháp này không không phản ánh sử dụng! Đừng sợ hãi bởi dữ liệu demo vô nghĩa - nó không liên quan gì đến vấn đề này; nó chỉ là cách dễ nhất để lấy một số dữ liệu phân cấp cho mục đích trình diễn, trong khi vẫn giữ toàn bộ chương trình nhỏ.
[sửa # 2:] Tôi chỉ nhận ra rằng những gì các nhà thiết kế đã cố gắng để tránh với sự sắp xếp lưới 3x2 là hiệu ứng khó coi sau (phóng đại ở đây bằng một ảnh chụp màn hình thu nhỏ).Vì vậy, nếu bạn áp dụng một trong những giải pháp từ trang này, được cảnh báo trước rằng bạn có thể không muốn điều này:

Vậy đó! Cảm ơn bạn rất nhiều cho tất cả các bài viết của bạn! – alex2k8
Câu trả lời hay. +1 Cảm ơn rất nhiều. – Amenti
Tuyệt vời! Tuy nhiên tôi đã nhận thấy một vấn đề mà độ sâu được tính toán không chính xác nếu chế độ xem dạng cây được tạo bằng cách sử dụng các mẫu phân cấp trong đó thuộc tính 'Parent' không được đặt trên' TreeViewItem'. Tôi đã chỉnh sửa câu trả lời để thay vì sử dụng cây trực quan để làm việc ra cha mẹ mà sửa chữa vấn đề (ít nhất là cho tôi), cảm thấy tự do để cuộn nó trở lại nếu bạn có bất kỳ phản đối mặc dù. – Justin