月更
This commit is contained in:
256
AntDesignWPF/Controls/Avatar/Avatar.cs
Normal file
256
AntDesignWPF/Controls/Avatar/Avatar.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
namespace AntDesignWPF.Controls;
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
|
||||
/// <summary>
|
||||
/// Avatars can be used to represent people or objects. It supports images, Icons, or letters.
|
||||
/// </summary>
|
||||
[ContentProperty("Text")]
|
||||
[TemplatePart(Name = "PART_Content", Type = typeof(ContentPresenter))]
|
||||
public class Avatar : Control
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string PART_Content = "PART_Content";
|
||||
|
||||
private ContentPresenter contentPresenter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty IconProperty =
|
||||
DependencyProperty.Register("Icon", typeof(string), typeof(Avatar), new PropertyMetadata(null, OnContentChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the icon type for an icon avatar.
|
||||
/// </summary>
|
||||
public string Icon
|
||||
{
|
||||
get { return (string)GetValue(IconProperty); }
|
||||
set { SetValue(IconProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Avatar).SetContent(true);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShapeProperty =
|
||||
DependencyProperty.Register("Shape", typeof(Shapes), typeof(Avatar), new PropertyMetadata(Shapes.Circle));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the shape of avatar.
|
||||
/// </summary>
|
||||
public Shapes Shape
|
||||
{
|
||||
get { return (Shapes)GetValue(ShapeProperty); }
|
||||
set { SetValue(ShapeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register("Size", typeof(Sizes?), typeof(Avatar), new PropertyMetadata(null, OnSizeChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the size of the avatar.
|
||||
/// </summary>
|
||||
public Sizes? Size
|
||||
{
|
||||
get { return (Sizes?)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var avatar = d as Avatar;
|
||||
var newValue = (Sizes?)e.NewValue;
|
||||
var oldValue = (Sizes?)e.OldValue;
|
||||
|
||||
if (newValue.HasValue && newValue.Value >= 0)
|
||||
{
|
||||
var size = (double)newValue.Value;
|
||||
avatar.SetValue(WidthProperty, size);
|
||||
avatar.SetValue(HeightProperty, size);
|
||||
avatar.SetValue(FontSizeProperty, size / 2);
|
||||
}
|
||||
else if (oldValue.HasValue && oldValue.Value >= 0)
|
||||
{
|
||||
avatar.ClearValue(WidthProperty);
|
||||
avatar.ClearValue(HeightProperty);
|
||||
avatar.ClearValue(FontSizeProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register("Source", typeof(ImageSource), typeof(Avatar), new PropertyMetadata(null, OnContentChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ImageSource for an image avatar.
|
||||
/// </summary>
|
||||
public ImageSource Source
|
||||
{
|
||||
get { return (ImageSource)GetValue(SourceProperty); }
|
||||
set { SetValue(SourceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(Avatar), new PropertyMetadata(string.Empty, OnContentChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the text for an text avatar.
|
||||
/// </summary>
|
||||
public string Text
|
||||
{
|
||||
get { return (string)GetValue(TextProperty); }
|
||||
set { SetValue(TextProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AlternativeProperty =
|
||||
DependencyProperty.Register("Alternative", typeof(string), typeof(Avatar), new PropertyMetadata(string.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the alternative text describing the image.
|
||||
/// </summary>
|
||||
public string Alternative
|
||||
{
|
||||
get { return (string)GetValue(AlternativeProperty); }
|
||||
set { SetValue(AlternativeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsImageProperty =
|
||||
DependencyProperty.Register("IsImage", typeof(bool), typeof(Avatar), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current avatar type as an image.
|
||||
/// </summary>
|
||||
public bool IsImage
|
||||
{
|
||||
get { return (bool)GetValue(IsImageProperty); }
|
||||
private set { SetValue(IsImageProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Avatar()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Avatar), new FrameworkPropertyMetadata(typeof(Avatar)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
contentPresenter = GetTemplateChild(PART_Content) as ContentPresenter;
|
||||
SetContent(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void SetContent(bool imageExist)
|
||||
{
|
||||
if (contentPresenter == null) return;
|
||||
|
||||
var content = contentPresenter.Content;
|
||||
|
||||
// Clear Event
|
||||
if (content is Image img)
|
||||
{
|
||||
ClearValue(IsImageProperty);
|
||||
img.ImageFailed -= OnImageFailed;
|
||||
}
|
||||
else if (content is TextBlock block)
|
||||
{
|
||||
SizeChanged -= OnTextSizeChanged;
|
||||
block.SizeChanged -= OnTextSizeChanged;
|
||||
}
|
||||
|
||||
if (Source != null && imageExist)
|
||||
{
|
||||
if (content is not Image)
|
||||
{
|
||||
content = new Image();
|
||||
}
|
||||
|
||||
SetCurrentValue(IsImageProperty, true);
|
||||
|
||||
var image = (Image)content;
|
||||
image.Source = Source;
|
||||
|
||||
image.ImageFailed += OnImageFailed;
|
||||
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
|
||||
|
||||
}
|
||||
else if (Icon != null)
|
||||
{
|
||||
if (content is not Controls.Icon icon)
|
||||
{
|
||||
content = new Icon();
|
||||
}
|
||||
|
||||
((Icon)content).Type = Icon;
|
||||
}
|
||||
else
|
||||
{
|
||||
var text = string.IsNullOrEmpty(Text) ? (imageExist ? string.Empty : Alternative) : Text;
|
||||
|
||||
if (content is not TextBlock)
|
||||
{
|
||||
content = new TextBlock();
|
||||
}
|
||||
|
||||
var textblock = (TextBlock)content;
|
||||
|
||||
SizeChanged += OnTextSizeChanged;
|
||||
textblock.SizeChanged += OnTextSizeChanged;
|
||||
|
||||
textblock.Text = text;
|
||||
textblock.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||
}
|
||||
|
||||
// 引用传递对 Null 无效
|
||||
contentPresenter.Content = content;
|
||||
}
|
||||
|
||||
private void OnImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
SetContent(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Autoset Font Size
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnTextSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (contentPresenter != null && contentPresenter.Content is TextBlock textBlock)
|
||||
{
|
||||
var childrenWidth = textBlock.ActualWidth;
|
||||
var width = ActualWidth - 8;
|
||||
var scale = 1d;
|
||||
var left = 0d;
|
||||
|
||||
if (width < childrenWidth)
|
||||
{
|
||||
scale = width / childrenWidth;
|
||||
left = ActualWidth / 2 - childrenWidth / 2;
|
||||
}
|
||||
|
||||
textBlock.Margin = new Thickness(left, 0d, left, 0d);
|
||||
textBlock.RenderTransform = new ScaleTransform(scale, scale);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
67
AntDesignWPF/Controls/Avatar/Avatar.xaml
Normal file
67
AntDesignWPF/Controls/Avatar/Avatar.xaml
Normal file
@@ -0,0 +1,67 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:controls="clr-namespace:AntDesignWPF.Controls"
|
||||
xmlns:helpers="clr-namespace:AntDesignWPF.Helpers"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Themes/Converters.xaml" />
|
||||
<!--<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Resources/BaseBrushes/Cyan.xaml" />-->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style TargetType="{x:Type controls:Avatar}">
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="TextBlock.LineHeight" Value="NaN" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="Width" Value="{DynamicResource AvatarSizeBase}" />
|
||||
<Setter Property="FontFamily" Value="{DynamicResource FontFamily}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource AvatarFontSizeBase}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource AntDesign.Brush.TextOnPrimary}" />
|
||||
<Setter Property="Background" Value="{DynamicResource AntDesign.Brush.TextQuaternary}" />
|
||||
<Setter Property="Height" Value="{Binding Width, Mode=OneWay, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="helpers:AntControl.CornerRadius" Value="{Binding Width, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource DoubleToCornerRadiusConverter}, ConverterParameter=2}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:Avatar}">
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding helpers:AntControl.CornerRadius}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
|
||||
<ContentPresenter
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
x:Name="PART_Content" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Shape" Value="Square">
|
||||
<Setter Property="helpers:AntControl.CornerRadius" Value="{DynamicResource AvatarBorderRadius}" />
|
||||
</Trigger>
|
||||
<!-- Sizes -->
|
||||
<Trigger Property="Size" Value="Small">
|
||||
<Setter Property="Width" Value="{DynamicResource AvatarSizeSmall}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource AvatarFontSizeSmall}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Size" Value="Large">
|
||||
<Setter Property="Width" Value="{DynamicResource AvatarSizeLarge}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource AvatarFontSizeLarge}" />
|
||||
</Trigger>
|
||||
<!-- without icon -->
|
||||
<Trigger Property="Icon" Value="{x:Null}">
|
||||
<Setter Property="FontSize" Value="{DynamicResource FontSizeBase}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsImage" Value="True">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
Reference in New Issue
Block a user