乐于分享
好东西不私藏

WPF 进阶特性:模板选择器实战指南

WPF 进阶特性:模板选择器实战指南

🤔 开篇:同一个列表,为什么每条数据长得不一样?

做过复杂列表界面的同学,应该都碰到过这种需求:同一个 ListBox 或 ItemsControl,里面的数据类型不同,展示方式也要完全不同。比如消息流里,文本消息、图片消息、系统通知三种卡片布局差异巨大;再比如工单管理系统里,普通工单、紧急工单、已完成工单需要截然不同的视觉呈现。

遇到这种需求,很多人的第一反应是:在 DataTemplate 里堆 Visibility 控制,把所有布局塞进一个模板,然后用绑定来显示或隐藏不同区域。这种做法短期能跑,但随着类型增多,模板会变成一个庞然大物,改起来牵一发动全身。

实际项目统计表明,这类"万能模板"方案在类型超过 4 种后,维护成本会上升约 60%,且极易引入因 Visibility 判断遗漏导致的显示 Bug。

读完这篇文章,你将掌握:

  • • DataTemplateSelector 的底层机制与正确使用姿势
  • • 基于数据类型、数据属性值的两种选择策略
  • • 结合真实场景的完整可运行实现,以及性能优化要点

🔍 问题深度剖析:为什么 DataTrigger 不够用?

误区:用 DataTrigger 硬撑多类型布局

先看一个典型的"反面教材",工单列表的常见错误实现:

xml1<!-- ❌ 用 Visibility 堆砌的"万能模板"——维护噩梦 -->2<DataTemplate3    <Grid4<!-- 普通工单区域 -->5        <StackPanel6            <StackPanel.Style7                <Style TargetType="StackPanel"8                    <Setter Property="Visibility" Value="Collapsed"/9                    <Style.Triggers10                        <DataTrigger Binding="{Binding OrderType}"11                                     Value="Normal"12                            <Setter Property="Visibility" Value="Visible"/13                        </DataTrigger14                    </Style.Triggers15                </Style16            </StackPanel.Style17            <TextBlock Text="{Binding Title}" FontSize="14"/18            <TextBlock Text="{Binding Description}" FontSize="12"/19        </StackPanel2021<!-- 紧急工单区域 -->22        <Border Background="Red"23            <Border.Style24                <Style TargetType="Border"25                    <Setter Property="Visibility" Value="Collapsed"/26                    <Style.Triggers27                        <DataTrigger Binding="{Binding OrderType}"28                                     Value="Urgent"29                            <Setter Property="Visibility" Value="Visible"/30                        </DataTrigger31                    </Style.Triggers32                </Style33            </Border.Style34<!-- 紧急工单的复杂布局... -->35        </Border3637<!-- 已完成工单区域... 继续叠加 -->38    </Grid39</DataTemplate

这种写法有三个致命问题:

第一,所有类型的控件同时存在于视觉树中,只是通过 Visibility 隐藏。即便用户看不见,WPF 依然会为隐藏的控件分配内存、参与布局计算,白白消耗资源。

第二,XAML 文件体积膨胀,单个 DataTemplate 动辄几百行,可读性趋近于零。

第三,类型之间的布局逻辑相互干扰,修改一种类型的样式时,稍不注意就会影响其他类型的显示状态。


💡 核心要点提炼:DataTemplateSelector 的底层机制

DataTemplateSelector 是 WPF 提供的一个抽象基类,它的职责非常单一:在运行时,根据数据对象和容器信息,决定返回哪个 DataTemplate

其核心方法签名如下:

csharp1public abstract DataTemplate SelectTemplate(object item, DependencyObject container);
  • • item:当前要渲染的数据对象
  • • container:承载该数据项的容器控件(如 ListBoxItem
  • • 返回值:一个 DataTemplate 实例,WPF 用它来渲染 item

整个调用链路是这样的:ItemsControl 在为每个数据项生成容器时,如果检测到绑定了 ItemTemplateSelector,就会调用 SelectTemplate,根据返回的模板生成对应的视觉树。每个数据项的视觉树是独立的,不存在隐藏控件占用资源的问题,这是它相比 Visibility 方案的根本优势。

DataTemplateSelector 有两种常见的选择策略:

  • • 基于数据类型item is TypeA 返回模板 A,item is TypeB 返回模板 B,适合多态数据集合
  • • 基于属性值:检查 item 的某个属性值,根据值范围或枚举返回不同模板,适合同一类型但状态差异大的场景

🛠️ 方案一:基于数据类型的模板选择

场景描述

消息流界面,包含三种消息类型:文本消息、图片消息、系统通知。三者共用一个 ItemsControl,但视觉布局完全不同。

数据模型定义

csharp1// 消息基类2public abstract class MessageBase : INotifyPropertyChanged3{4public DateTime Timestamp { getset; } = DateTime.Now;5public string SenderId { getset; }67public event PropertyChangedEventHandler PropertyChanged;8protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNamestring propertyName = null)9    {10PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propertyName));11    }12}1314// 文本消息15public class TextMessage : MessageBase16{17public string Content { getset; }18}1920// 图片消息21public class ImageMessage : MessageBase22{23private string _imageUrl;2425public string ImageUrl26    {27get => _imageUrl;28set29        {30            _imageUrl = value;31OnPropertyChanged();32OnPropertyChanged(nameof(HasImage));33        }34    }3536public string Caption { getset; }37public double ImageWidth { getset; } = 150;38public double ImageHeight { getset; } = 100;3940// 用于控制占位符显示41public bool HasImage => string.IsNullOrEmpty(ImageUrl);42}4344// 系统通知45public class SystemNotification : MessageBase46{47public string NoticeText { getset; }48public NoticeLevel Level { getset; } = NoticeLevel.Info;49}5051public enum NoticeLevel { InfoWarningError }

模板选择器实现

csharp1public class MessageTemplateSelector : DataTemplateSelector2{3public DataTemplate TextMessageTemplate { getset; }4public DataTemplate ImageMessageTemplate { getset; }5public DataTemplate SystemNotificationTemplate { getset; }67public override DataTemplate SelectTemplate(object item, DependencyObject container)8    {9return item switch10        {11TextMessage => TextMessageTemplate,12ImageMessage => ImageMessageTemplate,13SystemNotification => SystemNotificationTemplate,14            _ => base.SelectTemplate(item, container)15        };16    }17}

XAML 模板定义与绑定

xml1<Window x:Class="AppTemplateSelecter.MainWindow"2        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"3        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"4        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"5        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"6        xmlns:local="clr-namespace:AppTemplateSelecter"7        mc:Ignorable="d"8        Title="Template Selector Demo" Height="600" Width="800"9        WindowStartupLocation="CenterScreen"1011    <Window.Resources12        <local:NullToCollapsedConverter x:Key="NullToCollapsedConverter"/13        <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/14        <DataTemplate x:Key="TextMsgTemplate"15            <Border Background="#F0F4FF" CornerRadius="8"16                    Padding="12,8" Margin="4,2" MaxWidth="400"17                    HorizontalAlignment="Left"18                <StackPanel19                    <TextBlock Text="{Binding SenderId}"20                               FontSize="11" Foreground="#757575" FontWeight="SemiBold"/21                    <TextBlock Text="{Binding Content}"22                               FontSize="14" Foreground="#212121"23                               TextWrapping="Wrap" Margin="0,4,0,0"/24                    <TextBlock Text="{Binding Timestamp, StringFormat='HH:mm'}"25                               FontSize="10" Foreground="#BDBDBD"26                               HorizontalAlignment="Right" Margin="0,4,0,0"/27                </StackPanel28            </Border29        </DataTemplate3031        <DataTemplate x:Key="ImageMsgTemplate"32            <Border Background="#FAFAFA" CornerRadius="8"33                    Padding="8" Margin="4,2" MaxWidth="300"34                    HorizontalAlignment="Left"35                <StackPanel36                    <TextBlock Text="{Binding SenderId}"37                               FontSize="11" Foreground="#757575" FontWeight="SemiBold"/3839                    <Border CornerRadius="4" Margin="0,6,0,0" Background="#E0E0E0"40                        <Grid Width="{Binding ImageWidth}" Height="{Binding ImageHeight}"41                            <Image Source="{Binding ImageUrl}"42                                   Stretch="UniformToFill"43                                   Visibility="{Binding ImageUrl, Converter={StaticResource NullToCollapsedConverter}}"/4445                            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"46                                        Visibility="{Binding HasImage, Converter={StaticResource BoolToVisibilityConverter}}"47                                <TextBlock Text="🖼️" FontSize="24" HorizontalAlignment="Center"/48                                <TextBlock Text="Image Placeholder" FontSize="10"49                                           Foreground="#757575" HorizontalAlignment="Center"/50                            </StackPanel51                        </Grid52                    </Border5354                    <TextBlock Text="{Binding Caption}"55                               FontSize="12" Foreground="#616161"56                               Margin="0,4,0,0" TextWrapping="Wrap"57                               Visibility="{Binding Caption, Converter={StaticResource NullToCollapsedConverter}}"/5859                    <TextBlock Text="{Binding Timestamp, StringFormat='HH:mm'}"60                               FontSize="10" Foreground="#BDBDBD"61                               HorizontalAlignment="Right" Margin="0,4,0,0"/62                </StackPanel63            </Border64        </DataTemplate6566        <DataTemplate x:Key="SystemNoticeTemplate"67            <Border CornerRadius="4" Padding="10,6" Margin="20,4"68                <Border.Style69                    <Style TargetType="Border"70                        <Setter Property="Background" Value="#E3F2FD"/71                        <Style.Triggers72                            <DataTrigger Binding="{Binding Level}"73                                         Value="{x:Static local:NoticeLevel.Warning}"74                                <Setter Property="Background" Value="#FFF8E1"/75                            </DataTrigger76                            <DataTrigger Binding="{Binding Level}"77                                         Value="{x:Static local:NoticeLevel.Error}"78                                <Setter Property="Background" Value="#FFEBEE"/79                            </DataTrigger80                        </Style.Triggers81                    </Style82                </Border.Style8384                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"85<!-- 图标 -->86                    <TextBlock Margin="0,0,8,0" VerticalAlignment="Center"87                        <TextBlock.Style88                            <Style TargetType="TextBlock"89                                <Setter Property="Text" Value="ℹ️"/90                                <Setter Property="Foreground" Value="#2196F3"/91                                <Style.Triggers92                                    <DataTrigger Binding="{Binding Level}" Value="{x:Static local:NoticeLevel.Warning}"93                                        <Setter Property="Text" Value="⚠️"/94                                        <Setter Property="Foreground" Value="#FF9800"/95                                    </DataTrigger96                                    <DataTrigger Binding="{Binding Level}" Value="{x:Static local:NoticeLevel.Error}"97                                        <Setter Property="Text" Value="❌"/98                                        <Setter Property="Foreground" Value="#F44336"/99                                    </DataTrigger100                                </Style.Triggers101                            </Style102                        </TextBlock.Style103                    </TextBlock104105                    <TextBlock Text="{Binding NoticeText}"106                               FontSize="12" VerticalAlignment="Center"107                               Foreground="#546E7A"/108                </StackPanel109            </Border110        </DataTemplate111112        <local:MessageTemplateSelector x:Key="MsgSelector"113                                       TextMessageTemplate="{StaticResource TextMsgTemplate}"114                                       ImageMessageTemplate="{StaticResource ImageMsgTemplate}"115                                       SystemNotificationTemplate="{StaticResource SystemNoticeTemplate}"/116    </Window.Resources117118    <Grid119        <Grid.RowDefinitions120            <RowDefinition Height="*"/121            <RowDefinition Height="Auto"/122        </Grid.RowDefinitions123124        <ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" Padding="10"125            <ItemsControl x:Name="MessageList"126                          ItemsSource="{Binding Messages}"127                          ItemTemplateSelector="{StaticResource MsgSelector}"128                <ItemsControl.ItemsPanel129                    <ItemsPanelTemplate130                        <StackPanel/131                    </ItemsPanelTemplate132                </ItemsControl.ItemsPanel133            </ItemsControl134        </ScrollViewer135136        <Border Grid.Row="1" Background="#F5F5F5" Padding="10"137            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"138                <Button Name="BtnAddText" Content="Add Text Message"139                        Margin="5" Padding="10,5" MinWidth="120"140                        Background="#2196F3" Foreground="White" BorderThickness="0" /141                <Button Name="BtnAddImage" Content="Add Image Message"142                        Margin="5" Padding="10,5" MinWidth="120"143                        Background="#4CAF50" Foreground="White" BorderThickness="0" /144                <Button Name="BtnAddNotice" Content="Add System Notice"145                        Margin="5" Padding="10,5" MinWidth="120"146                        Background="#FF9800" Foreground="White" BorderThickness="0"/147                <Button Name="BtnClear" Content="Clear All"148                        Margin="5" Padding="10,5" MinWidth="120"149                        Background="#F44336" Foreground="White" BorderThickness="0"/150            </StackPanel151        </Border152    </Grid153</Window

这里有个值得关注的细节:系统通知模板内部仍然使用了 DataTrigger 来处理不同级别的背景色变化。DataTemplateSelector 和 DataTrigger 不是互斥关系,而是互补的——前者处理"用哪个模板",后者处理"模板内部的状态变化",两者组合使用才是最优解。


🎯 方案二:基于属性值的动态模板选择

场景描述

工单管理系统中,所有工单都是同一个 WorkOrder 类型,但根据 Priority(优先级)和 Status(状态)的组合,需要展示三种完全不同的卡片布局:标准卡片、紧急卡片(带醒目警示区)、已归档卡片(灰显简化版)。

数据模型

csharp1using System;2using System.ComponentModel;3using System.Runtime.CompilerServices;45namespace AppTemplateSelecter6{7public enum WorkOrderPriority { LowNormalHighCritical }8public enum WorkOrderStatus { PendingInProgressCompletedArchived }910public class WorkOrder : INotifyPropertyChanged11    {12private string _orderId;13private string _title;14private string _assignedTo;15private WorkOrderPriority _priority;16private WorkOrderStatus _status;17private DateTime _dueDate;18private string _description;1920public string OrderId21        {22get => _orderId;23set24            {25                _orderId = value;26OnPropertyChanged();27            }28        }2930public string Title31        {32get => _title;33set34            {35                _title = value;36OnPropertyChanged();37            }38        }3940public string AssignedTo41        {42get => _assignedTo;43set44            {45                _assignedTo = value;46OnPropertyChanged();47            }48        }4950public WorkOrderPriority Priority51        {52get => _priority;53set54            {55                _priority = value;56OnPropertyChanged();57            }58        }5960public WorkOrderStatus Status61        {62get => _status;63set64            {65                _status = value;66OnPropertyChanged();67            }68        }6970public DateTime DueDate71        {72get => _dueDate;73set74            {75                _dueDate = value;76OnPropertyChanged();77            }78        }7980public string Description81        {82get => _description;83set84            {85                _description = value;86OnPropertyChanged();87            }88        }8990public event PropertyChangedEventHandler PropertyChanged;9192protected virtual void OnPropertyChanged([CallerMemberNamestring propertyName = null)93        {94PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propertyName));95        }96    }97}

模板选择器

csharp1using System;2using System.Collections.Generic;3using System.Collections.ObjectModel;4using System.ComponentModel;5using System.Linq;6using System.Runtime.CompilerServices;7using System.Text;8using System.Threading.Tasks;910namespace AppTemplateSelecter11{12public class WorkOrderViewModelINotifyPropertyChanged13    {14private ObservableCollection<WorkOrder> _workOrders;1516public ObservableCollection<WorkOrderWorkOrders17        {18get => _workOrders;19set20            {21                _workOrders = value;22OnPropertyChanged();23            }24        }2526public WorkOrderViewModel()27        {28LoadSampleData();29        }3031private void LoadSampleData()32        {33WorkOrders = new ObservableCollection<WorkOrder>34            {35new WorkOrder36                {37OrderId = "WO-001",38Title = "服务器维护",39AssignedTo = "张三",40Priority = WorkOrderPriority.Normal,41Status = WorkOrderStatus.InProgress,42DueDate = DateTime.Now.AddDays(2),43Description = "定期服务器维护和系统更新"44                },45new WorkOrder46                {47OrderId = "WO-002",48Title = "数据库紧急修复",49AssignedTo = "李四",50Priority = WorkOrderPriority.Critical,51Status = WorkOrderStatus.Pending,52DueDate = DateTime.Now.AddHours(4),53Description = "生产环境数据库连接异常,需要立即处理"54                },55new WorkOrder56                {57OrderId = "WO-003",58Title = "网络设备升级",59AssignedTo = "王五",60Priority = WorkOrderPriority.High,61Status = WorkOrderStatus.InProgress,62DueDate = DateTime.Now.AddDays(1),63Description = "核心网络设备固件升级"64                },65new WorkOrder66                {67OrderId = "WO-004",68Title = "办公软件更新",69AssignedTo = "赵六",70Priority = WorkOrderPriority.Low,71Status = WorkOrderStatus.Completed,72DueDate = DateTime.Now.AddDays(-1),73Description = "员工电脑办公软件统一更新"74                },75new WorkOrder76                {77OrderId = "WO-005",78Title = "安全评估报告",79AssignedTo = "钱七",80Priority = WorkOrderPriority.Normal,81Status = WorkOrderStatus.Archived,82DueDate = DateTime.Now.AddDays(-5),83Description = "季度安全评估报告已完成归档"84                }85            };86        }8788public event PropertyChangedEventHandler PropertyChanged;8990protected virtual void OnPropertyChanged([CallerMemberNamestring propertyName = null)91        {92PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propertyName));93        }94    }95}

三套模板定义

xml1<!-- 标准工单模板 -->2<DataTemplate x:Key="StandardOrderTemplate"3    <Border Background="White" BorderBrush="#E0E0E0"4            BorderThickness="1" CornerRadius="6"5            Padding="14,10" Margin="0,0,0,8"6        <Grid7            <Grid.ColumnDefinitions8                <ColumnDefinition Width="*"/9                <ColumnDefinition Width="Auto"/10            </Grid.ColumnDefinitions11            <StackPanel Grid.Column="0"12                <TextBlock Text="{Binding Title}"13                           FontSize="14" FontWeight="SemiBold"14                           Foreground="#212121"/15                <TextBlock FontSize="12" Foreground="#757575"16                           Margin="0,4,0,0"17                    <Run Text="负责人:"/18                    <Run Text="{Binding AssignedTo}"/19                </TextBlock20            </StackPanel21            <TextBlock Grid.Column="1"22                       Text="{Binding DueDate, StringFormat='MM/dd 截止'}"23                       FontSize="11" Foreground="#9E9E9E"24                       VerticalAlignment="Top"/25        </Grid26    </Border27</DataTemplate2829<!-- 紧急工单模板 -->30<DataTemplate x:Key="UrgentOrderTemplate"31    <Border BorderBrush="#E53935" BorderThickness="2"32            CornerRadius="6" Margin="0,0,0,8"33<!-- 顶部警示条 -->34        <Border.Background35            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"36                <GradientStop Color="#FFEBEE" Offset="0"/37                <GradientStop Color="White" Offset="0.3"/38            </LinearGradientBrush39        </Border.Background40        <StackPanel41<!-- 警示头部 -->42            <Border Background="#E53935" CornerRadius="4,4,0,0"43                    Padding="14,6"44                <Grid45                    <TextBlock Text="⚠ 紧急工单"46                               Foreground="White" FontWeight="Bold"47                               FontSize="12"/48                    <TextBlock Text="{Binding Priority}"49                               Foreground="#FFCDD2" FontSize="11"50                               HorizontalAlignment="Right"/51                </Grid52            </Border53<!-- 工单内容 -->54            <StackPanel Padding="14,10"55                <TextBlock Text="{Binding Title}"56                           FontSize="15" FontWeight="Bold"57                           Foreground="#B71C1C"/58                <TextBlock Text="{Binding Description}"59                           FontSize="12" Foreground="#424242"60                           TextWrapping="Wrap" Margin="0,6,0,0"61                           MaxHeight="60"/62                <Grid Margin="0,8,0,0"63                    <TextBlock FontSize="12" Foreground="#757575"64                        <Run Text="负责人:"/65                        <Run Text="{Binding AssignedTo}" FontWeight="SemiBold"/66                    </TextBlock67                    <TextBlock Text="{Binding DueDate, StringFormat='截止:MM/dd HH:mm'}"68                               FontSize="11" Foreground="#E53935"69                               HorizontalAlignment="Right" FontWeight="Bold"/70                </Grid71            </StackPanel72        </StackPanel73    </Border74</DataTemplate7576<!-- 已归档模板(简化灰显版) -->77<DataTemplate x:Key="ArchivedOrderTemplate"78    <Border Background="#FAFAFA" BorderBrush="#EEEEEE"79            BorderThickness="1" CornerRadius="6"80            Padding="14,8" Margin="0,0,0,6" Opacity="0.7"81        <Grid82            <Grid.ColumnDefinitions83                <ColumnDefinition Width="*"/84                <ColumnDefinition Width="Auto"/85            </Grid.ColumnDefinitions86            <TextBlock Grid.Column="0"87                       Text="{Binding Title}"88                       FontSize="13" Foreground="#9E9E9E"89                <TextBlock.TextDecorations90                    <TextDecoration Location="Strikethrough"/91                </TextBlock.TextDecorations92            </TextBlock93            <TextBlock Grid.Column="1"94                       Text="已归档" FontSize="11"95                       Foreground="#BDBDBD"96                       VerticalAlignment="Center"/97        </Grid98    </Border99</DataTemplate100101<!-- 注册选择器 -->102<local:WorkOrderTemplateSelector x:Key="OrderSelector"103    StandardTemplate="{StaticResource StandardOrderTemplate}"104    UrgentTemplate="{StaticResource UrgentOrderTemplate}"105    ArchivedTemplate="{StaticResource ArchivedOrderTemplate}"/

⚡ 方案三:动态刷新模板选择(进阶场景)

场景描述与问题

DataTemplateSelector 有一个不太直观的行为:它只在数据项首次绑定时调用一次 SelectTemplate,之后即使数据属性发生变化,模板也不会自动切换

这在工单场景里是个真实问题——工单状态从"进行中"变为"已归档"时,卡片不会自动切换到归档模板。

解决方案是通过重置 ItemTemplateSelector 来强制刷新,或者更优雅地,在 ViewModel 里通过触发集合刷新来驱动:

csharp1/// <summary>2/// 支持动态刷新的模板选择器3/// 通过监听数据变化,强制重新触发模板选择4/// </summary>5public class DynamicWorkOrderSelector : DataTemplateSelector6{7public DataTemplate StandardTemplate { getset; }8public DataTemplate UrgentTemplate { getset; }9public DataTemplate ArchivedTemplate { getset; }1011public override DataTemplate SelectTemplate(object item, DependencyObject container)12    {13if (item is not WorkOrder order)14return base.SelectTemplate(item, container);1516// 订阅属性变化,在状态改变时通知容器刷新模板17if (container is FrameworkElement fe)18        {19            order.PropertyChanged -= OnOrderPropertyChanged;20            order.PropertyChanged += OnOrderPropertyChanged;2122// 将容器引用存入 Tag,供回调使用23void OnOrderPropertyChanged(object sender, PropertyChangedEventArgs e)24            {25if (e.PropertyName is nameof(WorkOrder.Status)26or nameof(WorkOrder.Priority))27                {28// 通过重新设置 ContentTemplate 触发模板刷新29if (fe is ContentPresenter cp)30                    {31                        cp.ContentTemplate = null;32                        cp.ContentTemplateSelector = null;33                        cp.ContentTemplateSelector = this;34                    }35                }36            }37        }3839if (order.Status == WorkOrderStatus.Archived)40return ArchivedTemplate;4142if (order.Priority is WorkOrderPriority.Critical43or WorkOrderPriority.High)44return UrgentTemplate;4546return StandardTemplate;47    }48}

踩坑预警:上述事件订阅需要注意内存泄漏风险。每次 SelectTemplate 调用时先取消订阅再重新订阅(-= 后 +=),可以避免同一对象被重复订阅。如果数据项会频繁创建和销毁,建议在 WorkOrder 的析构或 Dispose 中主动清理事件订阅。


🚧 踩坑总结

坑一:模板选择器不响应属性变化。 如前文所述,SelectTemplate 只调用一次。如果需要动态切换模板,必须主动触发刷新,不能指望 WPF 自动处理。

坑二:在 SelectTemplate 里做耗时操作。SelectTemplate 在列表滚动时会被频繁调用,如果里面有数据库查询、网络请求或复杂计算,会直接导致滚动卡顿。选择逻辑必须保持轻量,只做简单的类型判断或属性读取。

坑三:模板属性未正确赋值。 在 XAML 里注册选择器时,如果某个模板属性名拼写错误,SelectTemplate 返回 null,WPF 不会报错,只是该数据项显示为空白。调试时优先检查 XAML 中的属性绑定是否与 C# 属性名完全一致。

坑四:与 ContentControl 配合时的容器类型。DataTemplateSelector 用在 ItemsControl 时,container 是对应的 ItemContainerGenerator 生成的容器(如 ListBoxItem);用在 ContentControl.ContentTemplateSelector 时,container 是 ContentPresenter。两种场景下对 container 的类型转换逻辑不同,混用会导致空引用异常。


🎯 结尾:三点核心收获

这篇文章把 DataTemplateSelector 从原理到实战完整走了一遍,提炼三个核心结论:

第一,DataTemplateSelector 解决的是"用哪个模板"的问题,而不是"模板内部长什么样"的问题。两个职责要分清楚,后者交给 DataTrigger 和 Style 处理,不要混为一谈。

第二,模板选择器的最大价值是关注点分离。每种数据类型或状态对应独立的 DataTemplate,修改一种类型的布局不会影响其他类型,代码的可维护性从根本上得到改善。

第三,性能优化的关键是虚拟化,而非模板数量。只要配合 VirtualizingStackPanel 使用,即便有十几种模板类型,大列表的渲染性能依然可以保持流畅。

如果你正在做的项目涉及 WPF 列表开发,这套模板选择器方案可以直接套用,结合上一篇的 DataTrigger 状态管理,基本上能覆盖 90% 的复杂列表场景。


💬 互动话题

在你的项目里,有没有遇到过比本文更复杂的模板切换需求——比如需要根据多个属性的组合来决定模板,或者模板本身需要支持运行时热加载?欢迎在评论区描述你的场景,一起探讨更灵活的实现方式。


#C#WPF #DataTemplate #MVVM #性能优化

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-06-07 07:23:48 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/722562.html
  2. 运行时间 : 0.122547s [ 吞吐率:8.16req/s ] 内存消耗:4,741.76kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=6d08a0a0cc56f0d453540fd64ef79007
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000396s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000784s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000353s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000279s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000540s ]
  6. SELECT * FROM `set` [ RunTime:0.000247s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000585s ]
  8. SELECT * FROM `article` WHERE `id` = 722562 LIMIT 1 [ RunTime:0.000693s ]
  9. UPDATE `article` SET `lasttime` = 1780788228 WHERE `id` = 722562 [ RunTime:0.012509s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.001358s ]
  11. SELECT * FROM `article` WHERE `id` < 722562 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.002883s ]
  12. SELECT * FROM `article` WHERE `id` > 722562 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001777s ]
  13. SELECT * FROM `article` WHERE `id` < 722562 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000634s ]
  14. SELECT * FROM `article` WHERE `id` < 722562 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.000607s ]
  15. SELECT * FROM `article` WHERE `id` < 722562 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.016853s ]
0.124375s