You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中RowDetailsTemplate自定义展开折叠图标(XAML替代±按钮)

我来帮你搞定这个WPF自定义RowDetails展开/折叠图标的需求,全程用XAML实现,不用写后台事件代码~你参考的Silverlight方案核心思路是替换行模板,我们把它适配成WPF的实现方式,逻辑一致但语法更贴合WPF的控件模板体系。

实现WPF DataGrid自定义RowDetails展开/折叠图标(纯XAML)

核心思路

我们需要重写DataGridRow的默认模板,替换掉自带的±按钮,用DataTrigger绑定DataGridRow的DetailsVisibility属性来切换展开/折叠图片,全程不需要后台事件处理。

完整可运行XAML示例

你可以直接把这段代码复制到项目里测试,记得替换自己的图片路径:

<Window x:Class="WpfDataGridCustomRowDetails.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfDataGridCustomRowDetails"
        Title="Custom RowDetails Icon" Height="450" Width="800">
    <Window.Resources>
        <!-- Visibility和Bool值的转换器,用于绑定ToggleButton的IsChecked -->
        <local:VisibilityToBoolConverter x:Key="VisibilityToBoolConverter"/>
    </Window.Resources>
    <Grid>
        <DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False" RowDetailsVisibilityMode="Collapsed">
            <!-- 自定义列 -->
            <DataGrid.Columns>
                <DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="150"/>
                <DataGridTextColumn Header="描述" Binding="{Binding Description}" Width="*"/>
            </DataGrid.Columns>

            <!-- RowDetails模板,这里是你自己的详情内容 -->
            <DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <Border Margin="10" Padding="10" Background="#F0F0F0" CornerRadius="5">
                        <TextBlock Text="{Binding Details}" FontStyle="Italic" Foreground="#333"/>
                    </Border>
                </DataTemplate>
            </DataGrid.RowDetailsTemplate>

            <!-- 重写DataGridRow的模板,替换默认展开按钮 -->
            <DataGrid.RowStyle>
                <Style TargetType="{x:Type DataGridRow}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type DataGridRow}">
                                <Border x:Name="DGR_Border" 
                                        BorderBrush="{TemplateBinding BorderBrush}" 
                                        BorderThickness="{TemplateBinding BorderThickness}" 
                                        Background="{TemplateBinding Background}" 
                                        SnapsToDevicePixels="True">
                                    <SelectiveScrollingGrid>
                                        <SelectiveScrollingGrid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="*"/>
                                        </SelectiveScrollingGrid.ColumnDefinitions>
                                        <SelectiveScrollingGrid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                            <RowDefinition Height="*"/>
                                        </SelectiveScrollingGrid.RowDefinitions>
                                        
                                        <!-- 自定义展开/折叠按钮 -->
                                        <ToggleButton x:Name="ExpanderButton" 
                                                      Margin="4,2" Width="20" Height="20"
                                                      IsChecked="{Binding Path=DetailsVisibility, 
                                                                           RelativeSource={RelativeSource TemplatedParent}, 
                                                                           Converter={StaticResource VisibilityToBoolConverter}}">
                                            <ToggleButton.Style>
                                                <Style TargetType="{x:Type ToggleButton}">
                                                    <Setter Property="Template">
                                                        <Setter.Value>
                                                            <ControlTemplate TargetType="{x:Type ToggleButton}">
                                                                <Grid>
                                                                    <!-- 折叠状态显示的图片 -->
                                                                    <Image x:Name="CollapsedImg" 
                                                                           Source="/Images/expand_icon.png" 
                                                                           Stretch="Uniform"/>
                                                                    <!-- 展开状态显示的图片 -->
                                                                    <Image x:Name="ExpandedImg" 
                                                                           Source="/Images/collapse_icon.png" 
                                                                           Stretch="Uniform" 
                                                                           Visibility="Collapsed"/>
                                                                </Grid>
                                                                <!-- 根据IsChecked状态切换图片显示 -->
                                                                <ControlTemplate.Triggers>
                                                                    <Trigger Property="IsChecked" Value="True">
                                                                        <Setter TargetName="CollapsedImg" Property="Visibility" Value="Collapsed"/>
                                                                        <Setter TargetName="ExpandedImg" Property="Visibility" Value="Visible"/>
                                                                    </Trigger>
                                                                </ControlTemplate.Triggers>
                                                            </ControlTemplate>
                                                        </Setter.Value>
                                                    </Setter>
                                                </Style>
                                            </ToggleButton.Style>
                                        </ToggleButton>

                                        <!-- 行内容区域 -->
                                        <DataGridCellsPresenter Grid.Column="1" 
                                                                ItemsPanel="{TemplateBinding ItemsPanel}" 
                                                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                        <!-- RowDetails详情区域 -->
                                        <DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" 
                                                                  SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, 
                                                                                                                               ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, 
                                                                                                                               Converter={x:Static DataGrid.RowDetailsScrollingConverter}, 
                                                                                                                               RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" 
                                                                  Visibility="{TemplateBinding DetailsVisibility}"/>
                                    </SelectiveScrollingGrid>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </Grid>
</Window>

关键细节说明

1. 必加的Visibility转换器

因为ToggleButton的IsChecked是布尔值,而DataGridRow的DetailsVisibility是Visibility枚举,所以需要一个简单的转换器来做类型转换:

namespace WpfDataGridCustomRowDetails
{
    public class VisibilityToBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((Visibility)value) == Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Visibility.Visible : Visibility.Collapsed;
        }
    }
}

这个转换器只是做类型映射,不属于事件处理,完全符合你“尽量不用后台代码”的需求。

2. 图片路径设置

把你的展开/折叠图片添加到项目中,右键图片文件→属性→设置生成操作为Resource,然后修改XAML里的Source路径,比如你的项目名为MyWpfApp,图片在Images文件夹下,路径就是/MyWpfApp;component/Images/expand.png。

3. 额外优化:点击整行展开/折叠

如果想要点击整行也能触发展开/折叠,可以在DataGridRow的Style里添加一个事件触发器:

<Style TargetType="{x:Type DataGridRow}">
    <!-- 原有的Setter内容 -->
    <Style.Triggers>
        <EventTrigger RoutedEvent="MouseLeftButtonUp">
            <BeginStoryboard>
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="DetailsVisibility">
                        <DiscreteObjectKeyFrame KeyTime="0" 
                                                Value="{Binding DetailsVisibility, 
                                                            RelativeSource={RelativeSource Self}, 
                                                            Converter={StaticResource InverseVisibilityConverter}}"/>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
</Style>

这时候需要再添加一个反向Visibility转换器,用来切换可见性状态:

public class InverseVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((Visibility)value) == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((Visibility)value) == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
    }
}

这样就完全实现了用自定义图片作为展开/折叠图标,而且全程用XAML控制,不需要后台事件来修改按钮外观,完美适配你的需求~

内容的提问来源于stack exchange,提问作者Bigeyes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:31:52