2025-07-12 23:31:32 +08:00
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
|
using WindowSize = System.Windows.Size;
|
|
|
|
|
|
using ContentControlBase = System.Windows.Controls.ContentControl;
|
|
|
|
|
|
|
2025-07-31 20:12:24 +08:00
|
|
|
|
namespace AntDesignWPF.Controls;
|
2025-07-12 23:31:32 +08:00
|
|
|
|
|
|
|
|
|
|
[TemplatePart(Name = PART_BadgeContainer, Type = typeof(FrameworkElement))]
|
|
|
|
|
|
[TemplatePart(Name = PART_Count, Type = typeof(ContentPresenter))]
|
|
|
|
|
|
public class Badge : ContentControlBase
|
2025-07-11 09:20:23 +08:00
|
|
|
|
{
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#region Fields
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
private const string PART_BadgeContainer = "PART_BadgeContainer";
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
private const string PART_Count = "PART_Count";
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
private FrameworkElement badgeContainer;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
private ContentPresenter count;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#endregion
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#region Properties
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty CountProperty =
|
|
|
|
|
|
DependencyProperty.Register("Count", typeof(object), typeof(Badge), new PropertyMetadata(null, OnCountChanged));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets/sets number to show in badge
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public object Count
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (object)GetValue(CountProperty); }
|
|
|
|
|
|
set { SetValue(CountProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
private static void OnCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
(d as Badge).ApplyCount();
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
private void ApplyCount()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (count == null) return;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
var content = Count;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
if (Count is string)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
2025-07-11 09:20:23 +08:00
|
|
|
|
{
|
2025-07-12 23:31:32 +08:00
|
|
|
|
var d = int.Parse(Count as string);
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
if (d > OverflowCount)
|
|
|
|
|
|
{
|
|
|
|
|
|
content = OverflowCount + "+";
|
2025-07-11 09:20:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-12 23:31:32 +08:00
|
|
|
|
catch { } // Swallow the error, it may be normal
|
2025-07-11 09:20:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
count.Content = content;
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty DotProperty =
|
|
|
|
|
|
DependencyProperty.Register("Dot", typeof(bool), typeof(Badge), new PropertyMetadata(false));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets/sets whether to display a red dot instead of count
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool Dot
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (bool)GetValue(DotProperty); }
|
|
|
|
|
|
set { SetValue(DotProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty OffsetProperty =
|
|
|
|
|
|
DependencyProperty.Register("Offset", typeof(Point?), typeof(Badge), new PropertyMetadata(null));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public Point? Offset
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (Point?)GetValue(OffsetProperty); }
|
|
|
|
|
|
set { SetValue(OffsetProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty OverflowCountProperty =
|
|
|
|
|
|
DependencyProperty.Register("OverflowCount", typeof(int), typeof(Badge), new PropertyMetadata(99, OnCountChanged));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets/sets max count to show
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int OverflowCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (int)GetValue(OverflowCountProperty); }
|
|
|
|
|
|
set { SetValue(OverflowCountProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty ShowZeroProperty =
|
|
|
|
|
|
DependencyProperty.Register("ShowZero", typeof(bool), typeof(Badge), new PropertyMetadata(false));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets/sets whether to show badge when count is zero
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool ShowZero
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (bool)GetValue(ShowZeroProperty); }
|
|
|
|
|
|
set { SetValue(ShowZeroProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty StatusProperty =
|
|
|
|
|
|
DependencyProperty.Register("Status", typeof(BadgeStatus?), typeof(Badge), new PropertyMetadata(null));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets/sets badge as a status dot
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public BadgeStatus? Status
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (BadgeStatus?)GetValue(StatusProperty); }
|
|
|
|
|
|
set { SetValue(StatusProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty TextProperty =
|
|
|
|
|
|
DependencyProperty.Register("Text", typeof(string), typeof(Badge), new PropertyMetadata(string.Empty));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets/sets the text of the status dot. valid with StatusProperty set
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string Text
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (string)GetValue(TextProperty); }
|
|
|
|
|
|
set { SetValue(TextProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty BadgeHeightProperty =
|
|
|
|
|
|
DependencyProperty.Register("BadgeHeight", typeof(double), typeof(Badge), new PropertyMetadata(default(double)));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public double BadgeHeight
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (double)GetValue(BadgeHeightProperty); }
|
|
|
|
|
|
set { SetValue(BadgeHeightProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty BadgeForegroundProperty =
|
|
|
|
|
|
DependencyProperty.Register("BadgeForeground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush)));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public Brush BadgeForeground
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (Brush)GetValue(BadgeForegroundProperty); }
|
|
|
|
|
|
set { SetValue(BadgeForegroundProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public static readonly DependencyProperty BadgeBackgroundProperty =
|
|
|
|
|
|
DependencyProperty.Register("BadgeBackground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush)));
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public Brush BadgeBackground
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (Brush)GetValue(BadgeBackgroundProperty); }
|
|
|
|
|
|
set { SetValue(BadgeBackgroundProperty, value); }
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#endregion
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#region Constructors
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
static Badge()
|
|
|
|
|
|
{
|
|
|
|
|
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(Badge), new FrameworkPropertyMetadata(typeof(Badge)));
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#endregion
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#region Overrides
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
public override void OnApplyTemplate()
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnApplyTemplate();
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
badgeContainer = GetTemplateChild(PART_BadgeContainer) as FrameworkElement;
|
|
|
|
|
|
count = GetTemplateChild(PART_Count) as ContentPresenter;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
ApplyCount();
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
protected override WindowSize ArrangeOverride(WindowSize arrangeBounds)
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = base.ArrangeOverride(arrangeBounds);
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
if (badgeContainer == null) return result;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
var desiredSize = badgeContainer.DesiredSize;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
// System.Console.WriteLine(desiredSize);
|
|
|
|
|
|
// if ((desiredSize.Width <= 0.0 || desiredSize.Height <= 0.0))
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
//var containerDesiredSize = _badgeContainer.DesiredSize;
|
|
|
|
|
|
//if ((containerDesiredSize.Width <= 0.0 || containerDesiredSize.Height <= 0.0)
|
|
|
|
|
|
// && !double.IsNaN(_badgeContainer.ActualWidth) && !double.IsInfinity(_badgeContainer.ActualWidth)
|
|
|
|
|
|
// && !double.IsNaN(_badgeContainer.ActualHeight) && !double.IsInfinity(_badgeContainer.ActualHeight))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// containerDesiredSize = new Size(_badgeContainer.ActualWidth, _badgeContainer.ActualHeight);
|
|
|
|
|
|
//}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
var h = 0 - desiredSize.Width / 2;
|
|
|
|
|
|
var v = 0 - desiredSize.Height / 2;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
// badgeContainer.Margin = new Thickness(0);
|
|
|
|
|
|
// badgeContainer.Margin = new Thickness(h, v, h, v);
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
return result;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-12 23:31:32 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public enum BadgeStatus : byte
|
|
|
|
|
|
{
|
|
|
|
|
|
Success, Processing, Default, Error, Warning
|
2025-07-11 09:20:23 +08:00
|
|
|
|
}
|