ListView调整列的性能问题(分组)

Dom*_*Dom 16 c# wpf performance xaml listview

ListView每当我实施分组时,我都会遇到重大的性能问题.我在StackOverflow上发现了一些类似的问题,但似乎都没有帮助!


这是我目前的情况(我简化了我的项目,因此噪音更小):

我有ContentControl一个ListView为孩子.所述ListView绑定到ObservableCollection,其最初是空的.随着时间的推移,对象被添加到集合中(在此示例中,使用a每10秒添加500个项目DispatcherTimer).它的大小ObservableCollection会有所不同,但收藏可能最终超过25,000件.

ObservableCollection小于2000(不精确的数字)时,列大小调整如下所示:

在此输入图像描述

但是,随着更多对象的添加ObservableCollection,性能会明显下降(您需要向下滚动才能实现).

这最终将导致Application锁定.

我认为问题可以使用解决Virtualization,所以我尝试使用以下内容:

<ListView x:Name="ListView1"
                  Style="{DynamicResource lvStyle}"
                  VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.IsContainerVirtualizable="True"
                  ScrollViewer.IsDeferredScrollingEnabled="True">
Run Code Online (Sandbox Code Playgroud)

但是,似乎没有任何作用!

更不用说,VirtualizingPanel.IsVirtualizingWhenGrouping="True"导致ListView完全锁定.

我也研究过Paul McClean出色的数据虚拟化,但它并没有处理分组.


问题: 在a中对项目进行分组时ListView,是否有办法调整列的大小而不会显着影响应用程序的性能?

理想情况下,我想减少内存开销,所以我全都是为了实现某种异步解决方案.


码:

XAML:

<ContentControl x:Class="ListViewDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:ListViewDemo"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
        xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic" 
        mc:Ignorable="d" 
        d:DesignHeight="400" d:DesignWidth="300">
    <ContentControl.Resources>
    <Style x:Key="lvStyle" TargetType="{x:Type ListView}">
        <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
        <Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
        <Setter Property="ListView.ItemsSource" Value="{Binding}"/>
        <Setter Property="ListView.View">
            <Setter.Value>
                <GridView>
                    <GridViewColumn Header="Name">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Date">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Date}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Desc">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Desc}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </Setter.Value>
        </Setter>
        </Style>
    </ContentControl.Resources>

    <Grid>
        <ListView x:Name="ListView1"
                      Style="{DynamicResource lvStyle}"
                      VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                      VirtualizingPanel.IsVirtualizing="True"
                      VirtualizingPanel.IsContainerVirtualizable="True"
                      ScrollViewer.IsDeferredScrollingEnabled="True">
            <ListView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <DockPanel>
                                            <Border DockPanel.Dock="Top">
                                                <TextBlock x:Name="groupItem"
                                                            Text="{Binding ItemCount, StringFormat={}({0} Results)}"></TextBlock>
                                            </Border>
                                            <ItemsPresenter DockPanel.Dock="Bottom"></ItemsPresenter>
                                        </DockPanel>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ListView.GroupStyle>
        </ListView>
    </Grid>
</ContentControl>
Run Code Online (Sandbox Code Playgroud)

后台代码:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace ListViewDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : ContentControl
    {
        private ObservableCollection<Event> eventCollection = new ObservableCollection<Event>();

        public MainWindow()
        {
            InitializeComponent();

            DispatcherTimer dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 10);
            dispatcherTimer.Start();

            ListView1.ItemsSource = eventCollection;
            ListView1.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Descending));
            ListView1.Items.SortDescriptions.Add(new SortDescription("Date", ListSortDirection.Descending));
            ListView1.Items.GroupDescriptions.Add(new PropertyGroupDescription("Seconds"));
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            for(var i = 0; i < 500; i++){
                eventCollection.Add(new Event
                {
                    Name = string.Format("Name_{0}", eventCollection.Count),
                    Date = DateTime.Now.ToString("MM.dd.yy HH:mm"),
                    Seconds = Convert.ToInt32(DateTime.Now.ToString("ss")),
                    Desc = "Description"
                });
            }
        }

        public class Event
        {
            public string Name { get; set; }
            public string Date { get; set; }
            public int Seconds { get; set; }
            public string Desc { get; set; }
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

Sis*_*phe 11

Your performance issue is due to not using IsVirtualizingWhenGrouping

You mentionned that using IsVirtualizingWhenGrouping was locking your application, and this is a known WPF issue (see : http://connect.microsoft.com/VisualStudio/feedback/details/780146/freeze-when-using-virtualizingpanel-isvirtualizingwhengrouping for more information on this bug happening when having a custom GroupStyle and IsVirtualizingWhenGrouping set to true)

Here is a quick workaroung to solve your issue : You just have to add an expander in the GroupStyle ControlTemplate. You'll then be able to use IsVirtualizingWhenGrouping and then have good performances when scrolling/Resizing columns.

Here is the code that works on my machine : (I put everything directly in MainWindow to simplify a bit)

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>

        <Style x:Key="lvStyle" TargetType="{x:Type ListView}" >

            <Setter Property="ListView.ItemsSource" Value="{Binding}"/>
            <Setter Property="ListView.View">
                <Setter.Value>
                    <GridView>
                        <GridViewColumn Header="Name">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding Name}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Date">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding Date}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Desc">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding Desc}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                    </GridView>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid>
        <ListView x:Name="ListView1"
                  Style="{DynamicResource lvStyle}"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.IsVirtualizingWhenGrouping="True">
            <ListView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <Expander IsExpanded="True">
                                            <DockPanel>
                                                <Border DockPanel.Dock="Top">
                                                    <TextBlock x:Name="groupItem"
                                                                Text="{Binding ItemCount, StringFormat={}({0} Results)}"></TextBlock>
                                                </Border>
                                                <ItemsPresenter x:Name="groupItemPresenter" DockPanel.Dock="Bottom"></ItemsPresenter>
                                            </DockPanel>
                                        </Expander>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ListView.GroupStyle>
        </ListView>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

编辑:这是一个"隐藏"扩展器的ControlTemplate.这是我删除不必要部分的原始内容:

<ControlTemplate x:Key="CustomExpanderControlTemplate" TargetType="{x:Type Expander}">
        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="True">
            <DockPanel>
                <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
                    <ToggleButton.FocusVisualStyle>
                        <Style>
                            <Setter Property="Control.Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <Border>
                                            <Rectangle Margin="0" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToggleButton.FocusVisualStyle>
                    <ToggleButton.Style>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="*"/>
                                                </Grid.ColumnDefinitions>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                                            </Grid>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToggleButton.Style>
                </ToggleButton>
                <ContentPresenter x:Name="ExpandSite" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" DockPanel.Dock="Bottom" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </DockPanel>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="IsExpanded" Value="True">
                <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
            </Trigger>
            <Trigger Property="ExpandDirection" Value="Right">
                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
                <Setter Property="Style" TargetName="HeaderSite">
                    <Setter.Value>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="19"/>
                                                    <RowDefinition Height="*"/>
                                                </Grid.RowDefinitions>
                                                <Grid>
                                                    <Grid.LayoutTransform>
                                                        <TransformGroup>
                                                            <RotateTransform Angle="-90"/>
                                                        </TransformGroup>
                                                    </Grid.LayoutTransform>
                                                    <Ellipse x:Name="circle" Fill="Transparent" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                                    <Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF666666" StrokeThickness="2" VerticalAlignment="Center"/>
                                                </Grid>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                                            </Grid>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
                                            </Trigger>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF222222"/>
                                            </Trigger>
                                            <Trigger Property="IsPressed" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Stroke" TargetName="circle" Value="DarkGray"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF666666"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="ExpandDirection" Value="Up">
                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
                <Setter Property="Style" TargetName="HeaderSite">
                    <Setter.Value>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="19"/>
                                                    <ColumnDefinition Width="*"/>
                                                </Grid.ColumnDefinitions>
                                                <Grid>
                                                    <Grid.LayoutTransform>
                                                        <TransformGroup>
                                                            <RotateTransform Angle="180"/>
                                                        </TransformGroup>
                                                    </Grid.LayoutTransform>
                                                    <Ellipse x:Name="circle" Fill="Transparent" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                                    <Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF666666" StrokeThickness="2" VerticalAlignment="Center"/>
                                                </Grid>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="1" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                                            </Grid>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
                                            </Trigger>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF222222"/>
                                            </Trigger>
                                            <Trigger Property="IsPressed" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Stroke" TargetName="circle" Value="DarkGray"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF666666"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="ExpandDirection" Value="Left">
                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
                <Setter Property="Style" TargetName="HeaderSite">
                    <Setter.Value>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="19"/>
                                                    <RowDefinition Height="*"/>
                                                </Grid.RowDefinitions>
                                                <Grid>
                                                    <Grid.LayoutTransform>
                                                        <TransformGroup>
                                                            <RotateTransform Angle="90"/>
                                                        </TransformGroup>
                                                    </Grid.LayoutTransform>
                                                    <Ellipse x:Name="circle" Fill="Transparent" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                                    <Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF666666" StrokeThickness="2" VerticalAlignment="Center"/>
                                                </Grid>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                                            </Grid>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
                                            </Trigger>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF222222"/>
                                            </Trigger>
                                            <Trigger Property="IsPressed" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Stroke" TargetName="circle" Value="DarkGray"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF666666"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
Run Code Online (Sandbox Code Playgroud)

您可以通过在组样式中设置它来使用它:

<Expander IsExpanded="True" Template="{DynamicResource CustomExpanderControlTemplate}">
Run Code Online (Sandbox Code Playgroud)