惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
宝玉的分享
宝玉的分享
月光博客
月光博客
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
小众软件
小众软件
量子位
MongoDB | Blog
MongoDB | Blog
Blog — PlanetScale
Blog — PlanetScale
The Cloudflare Blog
Stack Overflow Blog
Stack Overflow Blog
U
Unit 42
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

博客园 - Hey,Coder!

微信小程序 web方案实现调音器功能 systemctl slice配置docker最大占用cpu 内存 pipenv环境变量配置 .net8验证码 数据库差异对比工具 docker部署prometheus grafana pgexporter Alertmanager ubuntu24 换源 ssh配置 ubuntu24 Harbor部署 ubuntu24 kvm部署 cockpit web管理界面 .net api代理 Ubuntu 24.04 DMAR IOMMU 报错修复 uniapp iOS App 上架 vs文件软链接 Docker 网络别名 .net8通用中间件处理公共返回值结构 .net环境下OpenTelemetry Body 读取注意事项 jaeger界面显示异常 .net opentelemetry collector jaeger c# opentelemetry 自定义export c# opentelemetry 自定义export c# 生成对象的初始化代码 Elasticsearch ILM 与 Data Stream 概念及实例说明文档 portainer httphelper封装 Ocelot + Consul + SignalR 粘性会话 正交软件架构 docker postgresql17 主从复制 rabbitmq总结与c#示例 docker rabbitmq quartz dashboard
WPF 重写Expander
Hey,Coder! · 2026-02-12 · via 博客园 - Hey,Coder!

效果图
image

<UserControl x:Class="BlackBoard.UserControls.ColorExpander"
             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:BlackBoard.UserControls"
             mc:Ignorable="d"              x:Name="rootControl"
             xmlns:usercontrols="clr-namespace:BlackBoard.UserControls"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <!-- 定义统一的背景色变量 -->
        <SolidColorBrush x:Key="HeaderBackgroundBrush" Color="#D4F7EA"/>

        <Style x:Key="ExpanderStyle" TargetType="{x:Type Expander}">
            <Setter Property="IsExpanded" Value="False"></Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Expander}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="auto"></RowDefinition>
                                <RowDefinition Height="auto"></RowDefinition>
                            </Grid.RowDefinitions>

                            <Border BorderThickness="0" Background="{DynamicResource HeaderBackgroundBrush}" >
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="auto"/>
                                        <ColumnDefinition/>
                                    </Grid.ColumnDefinitions>
                                    <!-- 将ToggleButton放在第一行,覆盖整个Header区域 -->
                                    <ToggleButton x:Name="HeaderSite" Grid.ColumnSpan="2" Background="Transparent" Margin="0" Padding="0"
                                      IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"                                  
                                      Style="{DynamicResource ExpanderToggleButtonStyle}" >
                                        <ToggleButton.Content>
                                            <!-- 在ToggleButton内部放置Header内容 -->
                                            <DockPanel HorizontalAlignment="Stretch" Background="{DynamicResource HeaderBackgroundBrush}">
                                                <!-- 小三角图标容器,设置与Header相同的背景色 -->
                                                <Border Width="20" Background="{DynamicResource HeaderBackgroundBrush}" DockPanel.Dock="Left">
                                                    <Canvas Width="12" Height="12" VerticalAlignment="Center" HorizontalAlignment="Center">
                                                        <!-- 使用RenderTransform实现旋转效果 -->
                                                        <Path x:Name="expanderArrow"
                                                          Data="M0,0 L8,4 L0,8 Z" 
                                                          Stroke="Black" 
                                                          StrokeThickness="2"
                                                          Fill="Black"
                                                          Canvas.Left="2"
                                                          Canvas.Top="2"
                                                          RenderTransformOrigin="0.5,0.5">
                                                            <Path.RenderTransform>
                                                                <RotateTransform Angle="0"/>
                                                            </Path.RenderTransform>
                                                        </Path>
                                                    </Canvas>
                                                </Border>

                                                <!-- 实际Header内容 -->
                                                <ContentPresenter 
                                                ContentTemplate="{TemplateBinding HeaderTemplate}" 
                                                Content="{TemplateBinding Header}" 
                                                VerticalAlignment="Center"
                                                Margin="0,0,0,0"/>
                                            </DockPanel>
                                        </ToggleButton.Content>
                                    </ToggleButton>
                                </Grid>
                            </Border>
                            <ContentPresenter x:Name="ExpandSite" Grid.Row="1" Margin="0"
                                          ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" 
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="True">
                                <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
                                <!-- 当展开时,旋转小三角90度 -->
                                <Setter TargetName="expanderArrow" Property="RenderTransform">
                                    <Setter.Value>
                                        <RotateTransform Angle="90"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsExpanded" Value="False">
                                <!-- 当收起时,恢复原始角度 -->
                                <Setter TargetName="expanderArrow" Property="RenderTransform">
                                    <Setter.Value>
                                        <RotateTransform Angle="0"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style x:Key="ExpanderToggleButtonStyle" TargetType="{x:Type ToggleButton}">
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="Foreground" Value="Gainsboro"/>
            <Setter Property="FontSize" Value="15" />
            <Setter Property="FontFamily" Value="宋体" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Grid Background="Transparent">
                            <ContentPresenter 
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                            Margin="{TemplateBinding Padding}" 
                            RecognizesAccessKey="True"                       
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>

                        <ControlTemplate.Triggers>
                            <Trigger Property="IsPressed" Value="true">
                                <!-- 鼠标按下时,可以添加轻微的透明度变化来表示交互 -->
                                <Setter Property="Opacity" Value="0.9"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="true">
                                <!-- 这里通过动画或样式更改来显示展开状态 -->
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="Gray"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </UserControl.Resources>
    <Grid>
        <Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Padding="0" Margin="0" 
      Style="{StaticResource ExpanderStyle}">
            <Expander.Header>
                <DockPanel HorizontalAlignment="Stretch" Background="{DynamicResource HeaderBackgroundBrush}" Margin="0" Height="30" >
                    <StackPanel Orientation="Horizontal" DockPanel.Dock="Left" HorizontalAlignment="Stretch" VerticalAlignment="Center">
                        <TextBlock Name="lblTitle" Text="" Margin="5,0" FontSize="12" FontWeight="Bold"/>
                    </StackPanel>
                </DockPanel>
            </Expander.Header>
            <ContentPresenter Name="content"/>
        </Expander>
    </Grid>
</UserControl>

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace BlackBoard.UserControls
{
    /// <summary>
    /// ColorExpander.xaml 的交互逻辑
    /// </summary>
    public partial class ColorExpander : UserControl
    {
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Title.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register(nameof(Title), typeof(string), typeof(ColorExpander), new PropertyMetadata(string.Empty, OnTitleChange));

        private static void OnTitleChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ColorExpander)d;
            if (e.NewValue is string value)
            {
                control.Dispatcher.Invoke(() =>
                {
                    control.lblTitle.Text = value;
                });
            }
        }

        public string BGColor
        {
            get { return (string)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Color.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register(nameof(BGColor), typeof(string), typeof(ColorExpander), new PropertyMetadata(string.Empty, OnColorChange));

        private static void OnColorChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ColorExpander)d;
            if (e.NewValue is string value)
            {
                control.Dispatcher.Invoke(() =>
                {
                    if (!string.IsNullOrEmpty(value))
                    {
                        // 获取当前的SolidColorBrush
                        var brush = (SolidColorBrush)control.FindResource("HeaderBackgroundBrush");
                        if (brush != null)
                        {
                            brush.Color = (Color)ColorConverter.ConvertFromString(value);
                        }
                    }
                });
            }
        }



        public object Body
        {
            get { return (object)GetValue(BodyProperty); }
            set { SetValue(BodyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Body.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BodyProperty =
            DependencyProperty.Register(nameof(Body), typeof(object), typeof(ColorExpander), new PropertyMetadata(null, OnBodyChange));

        private static void OnBodyChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ColorExpander)d;
            if (e.NewValue is object value)
            {
                control.Dispatcher.Invoke(() =>
                {
                    control.content.Content = value;
                });
            }
        }

        public ColorExpander()
        {
            InitializeComponent();
        }
    }
}

使用

<usercontrols:ColorExpander BGColor="#FF9F3A" Title="A  [ 3人 / 占 12.5% ]">
    <usercontrols:ColorExpander.Body>
        <ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="200">
            <StackPanel Orientation="Horizontal" Margin="0 10">
                <Border Background="#F5F5F5" CornerRadius="3" Padding="8" Margin="0,0,8,5">
                    <TextBlock Text="张三张三" Foreground="#333"/>
                </Border>
                <Border Background="#F5F5F5" CornerRadius="3" Padding="8" Margin="0,0,8,5">
                    <TextBlock Text="李四" Foreground="#333"/>
                </Border>
                <Border Background="#F5F5F5" CornerRadius="3" Padding="8" Margin="0,0,8,5">
                    <TextBlock Text="王五" Foreground="#333"/>
                </Border>
            </StackPanel>
        </ScrollViewer>
    </usercontrols:ColorExpander.Body>
</usercontrols:ColorExpander>