WPF 重写Expander
效果图

<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>
留待后查,同时方便他人
联系我:ivesbao@163.com
联系我:ivesbao@163.com

浙公网安备 33010602011771号