From 6d96da6f906b6e2550d3bddb3e991cdd16cf5136 Mon Sep 17 00:00:00 2001 From: GG Z <903524121@qq.com> Date: Sat, 12 Jul 2025 23:31:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=91=BD=E5=90=8D=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AntdWpf/AntdWpf.csproj | 1 + AntdWpf/Controls/Alert.cs | 15 +- AntdWpf/Controls/AntButton.cs | 339 +++++++ AntdWpf/Controls/AntIcon.cs | 3 + AntdWpf/Controls/AntdBorder.cs | 749 ++++++++++++++ ...ontentControl.cs => AntdContentControl.cs} | 11 +- AntdWpf/Controls/{Window.cs => AntdWindow.cs} | 88 +- AntdWpf/Controls/Avatar.cs | 500 +++++----- AntdWpf/Controls/Badge.cs | 409 ++++---- AntdWpf/Controls/Border.cs | 750 -------------- AntdWpf/Controls/Button.cs | 340 ------- AntdWpf/Controls/CodeBox.cs | 2 +- AntdWpf/Controls/ISpinable.cs | 10 - AntdWpf/Controls/Icon.cs | 930 +++++++++--------- AntdWpf/Controls/MaterialWindow.cs | 180 ++++ AntdWpf/Controls/TabControl.cs | 3 +- AntdWpf/Controls/ThumbContentControl.cs | 2 +- AntdWpf/Controls/WindowButtons.cs | 4 +- AntdWpf/Controls/WindowCommands.cs | 6 +- .../CornerRadiusToDoubleConverter.cs | 2 +- .../DoubleToCornerRadiusConverter.cs | 2 +- .../Converters/GenericConverterExtension.cs | 36 + .../Converters/ThicknessToDoubleConverter.cs | 2 +- .../Helpers/{Control.cs => AntdControl.cs} | 26 +- .../Standard/Verify.cs | 15 +- .../Microsoft.Windows.Shell/SystemCommands.cs | 4 +- AntdWpf/Styles/Alert.xaml | 14 +- .../Styles/{Window.xaml => AntWindow.xaml} | 20 +- AntdWpf/Styles/Avatar.xaml | 6 +- AntdWpf/Styles/Button.xaml | 24 +- AntdWpf/Styles/CheckBox.xaml | 4 +- AntdWpf/Styles/CheckableTag.xaml | 10 +- AntdWpf/Styles/CodeBox.xaml | 4 +- AntdWpf/Styles/ComboBox.xaml | 12 +- AntdWpf/Styles/ContentControl.xaml | 4 +- AntdWpf/Styles/Hyperlink.xaml | 8 +- AntdWpf/Styles/Input.xaml | 8 +- AntdWpf/Styles/MaterialWindow.xaml | 455 +++++++++ AntdWpf/Styles/PasswordBox.xaml | 20 +- AntdWpf/Styles/ProgressBar.xaml | 2 + AntdWpf/Styles/Switch.xaml | 4 +- AntdWpf/Styles/Tag.xaml | 14 +- AntdWpf/Styles/TextBox.xaml | 10 +- AntdWpf/Styles/ToolTip.xaml | 4 +- AntdWpf/Styles/WindowButton.xaml | 10 +- AntdWpf/Styles/WindowButtons.xaml | 12 +- AntdWpf/Styles/WindowCommands.xaml | 4 +- AntdWpf/Themes/AntIcons.xaml | 9 + AntdWpf/Themes/Generic.xaml | 7 +- AntdWpf/Themes/{Theme.xaml => Light.xaml} | 0 AntdWpf/Utils/CornerRadiusUtil.cs | 4 +- AntdWpf/Utils/Spinner.cs | 14 +- AntdWpfDemo/AntdWpfDemo.csproj | 3 + AntdWpfDemo/App.xaml | 6 +- AntdWpfDemo/Resources/Images/ImageTest.png | Bin 32425 -> 0 bytes AntdWpfDemo/Resources/Images/SyminUI.png | Bin 93206 -> 0 bytes AntdWpfDemo/Resources/SyminUI.ico | Bin 260894 -> 0 bytes AntdWpfDemo/Views/AvatarView.xaml | 2 +- AntdWpfDemo/Views/ButtonView.xaml | 74 +- AntdWpfDemo/Views/CheckBoxView.xaml | 4 +- AntdWpfDemo/Views/InputView.xaml | 20 +- AntdWpfDemo/Views/ProgressView.xaml | 42 +- AntdWpfDemo/Views/RadioButtonView.xaml | 2 +- AntdWpfDemo/Views/ShellView.xaml | 4 +- AntdWpfDemo/Views/SwitchView.xaml | 2 +- AntdWpfDemo/Views/TagView.xaml | 2 +- AntdWpfDemo/Views/ToolTipView.xaml | 30 +- .../Controls/MaterialWindow.cs | 23 - .../Controls/MaterialWindow.xaml | 103 +- ShrlAlgo.Toolkit.Wpf/Resources/Colors.xaml | 4 - .../Resources/InternalIcons.xaml | 47 - ShrlAlgo.Toolkit.Wpf/Themes/Controls.xaml | 122 --- .../Extensions/RoomExtensions.cs | 2 +- .../RvFamily/ExplodeDwgCmd.cs | 14 +- .../RvFamily/RenameFamilyView.xaml | 222 ++--- .../RvFamily/RenameTypeView.xaml | 8 +- ShrlAlgoToolkit.sln | 1 - WPFDark.Gallery/MainWindow.xaml | 799 +++++++++++++-- WPFDark.Gallery/MainWindow.xaml.cs | 11 + WPFDark.Gallery/WPFDark.Gallery.csproj | 4 + WPFDark/Constants.cs | 13 + WPFDark/Controls/BiaWindow.xaml.cs | 10 +- WPFDark/ControlsDictionary.cs | 2 +- WPFDark/Properties/AssemblyInfo.cs | 1 + WPFDark/ThemeManager.cs | 2 +- WebUITest/ShrlAlgoWindow.xaml | 17 - WebUITest/ShrlAlgoWindow.xaml.cs | 27 - WebUITest/WebUITest.csproj | 3 - 88 files changed, 3975 insertions(+), 2763 deletions(-) create mode 100644 AntdWpf/Controls/AntButton.cs create mode 100644 AntdWpf/Controls/AntdBorder.cs rename AntdWpf/Controls/{ContentControl.cs => AntdContentControl.cs} (76%) rename AntdWpf/Controls/{Window.cs => AntdWindow.cs} (89%) delete mode 100644 AntdWpf/Controls/Border.cs delete mode 100644 AntdWpf/Controls/Button.cs delete mode 100644 AntdWpf/Controls/ISpinable.cs create mode 100644 AntdWpf/Controls/MaterialWindow.cs create mode 100644 AntdWpf/Converters/GenericConverterExtension.cs rename AntdWpf/Helpers/{Control.cs => AntdControl.cs} (96%) rename AntdWpf/Styles/{Window.xaml => AntWindow.xaml} (94%) create mode 100644 AntdWpf/Styles/MaterialWindow.xaml rename AntdWpf/Themes/{Theme.xaml => Light.xaml} (100%) delete mode 100644 AntdWpfDemo/Resources/Images/ImageTest.png delete mode 100644 AntdWpfDemo/Resources/Images/SyminUI.png delete mode 100644 AntdWpfDemo/Resources/SyminUI.ico delete mode 100644 ShrlAlgo.Toolkit.Wpf/Resources/Colors.xaml delete mode 100644 WebUITest/ShrlAlgoWindow.xaml delete mode 100644 WebUITest/ShrlAlgoWindow.xaml.cs diff --git a/AntdWpf/AntdWpf.csproj b/AntdWpf/AntdWpf.csproj index 0777f59..77fe687 100644 --- a/AntdWpf/AntdWpf.csproj +++ b/AntdWpf/AntdWpf.csproj @@ -3,6 +3,7 @@ net462 Library true + 13.0 true False diff --git a/AntdWpf/Controls/Alert.cs b/AntdWpf/Controls/Alert.cs index d8de09d..ac514d1 100644 --- a/AntdWpf/Controls/Alert.cs +++ b/AntdWpf/Controls/Alert.cs @@ -1,17 +1,16 @@ -namespace AntdWpf.Controls +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Markup; +using System.Windows.Media; +namespace AntdWpf.Controls { - using System.Windows; - using System.Windows.Controls.Primitives; - using System.Windows.Markup; - using System.Windows.Media; - using ControlBase = System.Windows.Controls.Control; - /// /// Alert component for feedback. /// [ContentProperty("Message")] [TemplatePart(Name = PART_Close, Type = typeof(ButtonBase))] - public class Alert : ControlBase + public class Alert : Control { #region Fields diff --git a/AntdWpf/Controls/AntButton.cs b/AntdWpf/Controls/AntButton.cs new file mode 100644 index 0000000..c8635cd --- /dev/null +++ b/AntdWpf/Controls/AntButton.cs @@ -0,0 +1,339 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; + +namespace AntdWpf.Controls; + +/// +/// To trigger an operation. +/// +[TemplatePart(Name = PART_Border, Type = typeof(FrameworkElement))] +[TemplateVisualState(Name = "Loaded", GroupName = "LoadStates")] +[TemplateVisualState(Name = "Unloaded", GroupName = "LoadStates")] +public class AntButton : Button +{ + #region Fields + + private const string PART_Border = "PART_Border"; + + private FrameworkElement border; + + private VisualState mouseOverState; + + private VisualState pressedState; + + private VisualState focusedState; + + #endregion + + #region Properties + + public static readonly DependencyProperty GhostProperty = + DependencyProperty.Register("Ghost", typeof(bool), typeof(AntButton), new PropertyMetadata(false, OnEffectBrushChanged)); + + /// + /// Gets/sets whether to make the background transparent and invert text and border colors. + /// + public bool Ghost + { + get { return (bool)GetValue(GhostProperty); } + set { SetValue(GhostProperty, value); } + } + + public static readonly DependencyProperty IconProperty = + DependencyProperty.Register("Icon", typeof(string), typeof(AntButton), new PropertyMetadata(null)); + + /// + /// Gets/sets the icon type of the button. + /// + public string Icon + { + get { return (string)GetValue(IconProperty); } + set { SetValue(IconProperty, value); } + } + + public static readonly DependencyProperty LoadingProperty = + DependencyProperty.Register("Loading", typeof(bool), typeof(AntButton), new PropertyMetadata(false, OnLoadingChanged)); + + /// + /// Gets/sets the loading state of the button. + /// + public bool Loading + { + get { return (bool)GetValue(LoadingProperty); } + set { SetValue(LoadingProperty, value); } + } + + private static void OnLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as AntButton).SetLoadVisualState(); + } + + private void SetLoadVisualState() + { + VisualStateManager.GoToState(this, (Loading ? "Loaded" : "Unloaded"), true); + } + + + public static readonly DependencyProperty ShapeProperty = + DependencyProperty.Register("Shape", typeof(Shapes), typeof(AntButton), new PropertyMetadata(Shapes.Square)); + + /// + /// Gets/sets the shape of button. + /// + public Shapes Shape + { + get { return (Shapes)GetValue(ShapeProperty); } + set { SetValue(ShapeProperty, value); } + } + + public static readonly DependencyProperty SizeProperty = + DependencyProperty.Register("Size", typeof(Sizes?), typeof(AntButton), new PropertyMetadata(null)); + + /// + /// Gets/sets the size of the button. + /// + public Sizes? Size + { + get { return (Sizes?)GetValue(SizeProperty); } + set { SetValue(SizeProperty, value); } + } + + public static readonly DependencyProperty TypeProperty = + DependencyProperty.Register("Type", typeof(ButtonType?), typeof(AntButton), new PropertyMetadata(null)); + + /// + /// Gets/sets the type of the button. + /// + public ButtonType? Type + { + get { return (ButtonType?)GetValue(TypeProperty); } + set { SetValue(TypeProperty, value); } + } + + public static readonly DependencyProperty EffectBrushProperty = DependencyProperty.Register( + "EffectBrush", + typeof(Brush), + typeof(AntButton), + new FrameworkPropertyMetadata( + Brushes.Transparent, + FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits, + OnEffectBrushChanged)); + + /// + /// Gets/sets the border effect brush of the button. + /// + public Brush EffectBrush + { + get { return (Brush)GetValue(EffectBrushProperty); } + set { SetValue(EffectBrushProperty, value); } + } + + private static void OnEffectBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as AntButton).SetVisualStateAnimation(); + } + + /// + /// Force background transparent in Ghost state. + /// + private static object OnBackgroundCoerceValue(DependencyObject d, object baseValue) + { + var button = d as AntButton; + + if (button.Ghost) + { + return Brushes.Transparent; + } + + return baseValue; + } + + #endregion + + #region Constructors + + static AntButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(AntButton), new FrameworkPropertyMetadata(typeof(AntButton))); + BackgroundProperty.OverrideMetadata(typeof(AntButton), new FrameworkPropertyMetadata { CoerceValueCallback = OnBackgroundCoerceValue }); + } + + #endregion + + #region Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + border = GetTemplateChild(PART_Border) as FrameworkElement; + mouseOverState = GetTemplateChild("MouseOver") as VisualState; + + focusedState = GetTemplateChild("Focused") as VisualState; + pressedState = GetTemplateChild("Pressed") as VisualState; + + SetVisualStateAnimation(); + SetLoadVisualState(); + } + + #endregion + + #region Private Methods + + private void SetVisualStateAnimation() + { + // No initialization or no need for me to handle. + if (border == null || mouseOverState == null && focusedState == null && pressedState == null) return; + + // Unable to extract color. + if (EffectBrush is SolidColorBrush brush) + { + var isShape = border is Shape; + Func func; + + if (!Type.HasValue || Type.Value == ButtonType.Dashed) + { + func = CreateDefaultStoryboard; + } + else if (Type.Value == ButtonType.Primary) + { + func = CreatePrimaryStoryboard; + } + else + { + // Danger + func = CreateDangerStoryboard; + } + + if (mouseOverState != null) + { + mouseOverState.Storyboard = func(this, brush.Color, 5, isShape, false, null); + } + + if (focusedState != null) + { + focusedState.Storyboard = func(this, brush.Color, 5, isShape, true, null); + } + + if (pressedState != null) + { + pressedState.Storyboard = func(this, brush.Color, 7, isShape, false, TimeSpan.FromSeconds(0)); + } + } + } + + private static Storyboard CreateDefaultStoryboard(AntButton button, Color color, int index, bool IsShape, bool focused, Duration? duration = null) + { + var storyboard = new Storyboard(); + var children = storyboard.Children; + + color = ColorPalette.Toning(color, index); + children.Add(CreateForegroundAnimation(button, color, duration)); + children.Add(CreateBorderAnimation(PART_Border, color, IsShape, duration)); + + return storyboard; + } + + private static Storyboard CreatePrimaryStoryboard(AntButton button, Color color, int index, bool IsShape, bool focused, Duration? duration = null) + { + var storyboard = new Storyboard(); + var children = storyboard.Children; + + color = ColorPalette.Toning(color, index); + + if (button.Ghost) + { + children.Add(CreateForegroundAnimation(button, color, duration)); + } else + { + children.Add(CreateBackgroundAnimation(PART_Border, color, IsShape, duration)); + } + + children.Add(CreateBorderAnimation(PART_Border, color, IsShape, duration)); + + return storyboard; + } + + private static Storyboard CreateDangerStoryboard(AntButton button, Color color, int index, bool IsShape, bool focused, Duration? duration = null) + { + var storyboard = new Storyboard(); + var children = storyboard.Children; + + Color foreground; + color = ColorPalette.Toning(color, index); + + if (button.Ghost) + { + foreground = color; + } else + { + Color background; + + if (focused) + { + foreground = color; + background = Colors.White; + } + else + { + foreground = Colors.White; + background = color; + } + + children.Add(CreateBackgroundAnimation(PART_Border, background, IsShape, duration)); + } + + children.Add(CreateForegroundAnimation(button, foreground, duration)); + children.Add(CreateBorderAnimation(PART_Border, color, IsShape, duration)); + + return storyboard; + } + + private static Timeline CreateForegroundAnimation(DependencyObject target, Color color, Duration? duration = null) + { + return CreateColorAnimation(target, "(Control.Foreground).(SolidColorBrush.Color)", color, duration); + } + + private static Timeline CreateBackgroundAnimation(string target, Color color, bool IsShape, Duration? duration = null) + { + return CreateColorAnimation(target, (IsShape ? "Fill" : "Background") + ".Color", color, duration); + } + + private static Timeline CreateBorderAnimation(string target, Color color, bool IsShape, Duration? duration = null) + { + return CreateColorAnimation(target, (IsShape ? "Stroke" : "BorderBrush") + ".Color", color, duration); + } + + private static Timeline CreateColorAnimation(object target, string path, Color color, Duration? duration) + { + var animation = new ColorAnimation() { To = color }; + + if (duration.HasValue) + { + animation.Duration = duration.Value; + } + + if (target is DependencyObject) + { + Storyboard.SetTarget(animation, (DependencyObject)target); + } else + { + Storyboard.SetTargetName(animation, (string)target); + } + + Storyboard.SetTargetProperty(animation, new PropertyPath(path)); + + return animation; + } + + #endregion +} + +public enum ButtonType : byte +{ + Primary, Dashed, Danger +} diff --git a/AntdWpf/Controls/AntIcon.cs b/AntdWpf/Controls/AntIcon.cs index 5045076..f7380ea 100644 --- a/AntdWpf/Controls/AntIcon.cs +++ b/AntdWpf/Controls/AntIcon.cs @@ -7,6 +7,9 @@ using System.Windows.Media; namespace AntdWpf.Controls { + /// + /// 图标控件 + /// public class AntIcon : System.Windows.Controls.Control { private static readonly Lazy> _dataList diff --git a/AntdWpf/Controls/AntdBorder.cs b/AntdWpf/Controls/AntdBorder.cs new file mode 100644 index 0000000..a6f33e7 --- /dev/null +++ b/AntdWpf/Controls/AntdBorder.cs @@ -0,0 +1,749 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +using AntdWpf.Utils; + +namespace AntdWpf.Controls; + +/// +/// Draws a border, background, or both around another element. +/// +public class AntdBorder : Decorator +{ + #region Fields + + private StreamGeometry backgroundGeometryCache; + + private StreamGeometry upperLeftCache; + + private StreamGeometry upperRightCache; + + private StreamGeometry lowerRightCache; + + private StreamGeometry lowerLeftCache; + + private bool useComplexRender; + + private Pen leftPenCache; + + private Pen topPenCache; + + private Pen rightPenCache; + + private Pen bottomPenCache; + + #endregion + + #region Properties + + public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register( + "Background", + typeof(Brush), + typeof(AntdBorder), + new FrameworkPropertyMetadata( + null, + FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender + )); + + /// + /// Gets or sets the brush that fills the area between the bounds of a Border. + /// + public Brush Background + { + get { return (Brush)GetValue(BackgroundProperty); } + set { SetValue(BackgroundProperty, value); } + } + + public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register( + "BorderBrush", + typeof(Brush), + typeof(AntdBorder), + new FrameworkPropertyMetadata( + null, + FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, + OnClearPenCache + )); + + /// + /// Gets or sets the brush that draws the outer border color. + /// + public Brush BorderBrush + { + get { return (Brush)GetValue(BorderBrushProperty); } + set { SetValue(BorderBrushProperty, value); } + } + + public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register( + "BorderThickness", + typeof(Thickness), + typeof(AntdBorder), + new FrameworkPropertyMetadata( + new Thickness(), + FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, + OnClearPenCache + ), + IsThicknessValid); + + /// + /// Gets or sets the relative thickness of a border. + /// + public Thickness BorderThickness + { + get { return (Thickness)GetValue(BorderThicknessProperty); } + set { SetValue(BorderThicknessProperty, value); } + } + + private static void OnClearPenCache(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var border = (AntdBorder)d; + border.leftPenCache = border.topPenCache = border.rightPenCache = border.bottomPenCache = null; + } + + private static bool IsThicknessValid(object value) + { + return ThicknessUtil.IsValid((Thickness)value, false, false, false, false); + } + + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( + "CornerRadius", + typeof(CornerRadius), + typeof(AntdBorder), + new FrameworkPropertyMetadata( + new CornerRadius(), + FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender + ), + IsCornerRadiusValid); + + /// + /// Gets or sets a value that represents the degree to which the corners of a Border are rounded. + /// + public CornerRadius CornerRadius + { + get { return (CornerRadius)GetValue(CornerRadiusProperty); } + set { SetValue(CornerRadiusProperty, value); } + } + + private static bool IsCornerRadiusValid(object value) + { + return CornerRadiusUtil.IsValid((CornerRadius)value, false, false, false, false); + } + + public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register( + "Padding", + typeof(Thickness), + typeof(AntdBorder), + new FrameworkPropertyMetadata( + new Thickness(), + FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender + ), + IsThicknessValid); + + /// + /// Gets or sets a thickness value that describes the amount of space between a border and its child element. + /// + public Thickness Padding + { + get { return (Thickness)GetValue(PaddingProperty); } + set { SetValue(PaddingProperty, value); } + } + + public static readonly DependencyProperty BorderStyleProperty = DependencyProperty.Register( + "BorderStyle", + typeof(BorderStyle), + typeof(AntdBorder), + new FrameworkPropertyMetadata( + BorderStyle.Solid, + FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, + OnClearPenCache + )); + + /// + /// Gets or sets the border style. + /// + public BorderStyle BorderStyle + { + get { return (BorderStyle)GetValue(BorderStyleProperty); } + set { SetValue(BorderStyleProperty, value); } + } + + #endregion + + #region Overrides + + /// + /// Updates DesiredSize of the Border. Called by parent UIElement. This is the first pass of layout. + /// + /// + /// Border determines its desired size it needs from the specified border the child: its sizing + /// properties, margin, and requested size. + /// + /// Constraint size is an "upper limit" that the return value should not exceed. + /// The Decorator's desired size. + protected override Size MeasureOverride(Size constraint) + { + var child = Child; + var desiredSize = new Size(); + var borders = BorderThickness; + + if (UseLayoutRounding) + { + var dpi = DpiUtil.GetDpi(this); + borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY), + UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); + } + + // Compute the total size required + var borderSize = ThicknessUtil.CollapseThickness(borders); + var paddingSize = ThicknessUtil.CollapseThickness(Padding); + + // If we have a child + if (child != null) + { + // Combine into total decorating size + var combined = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height); + + // Remove size of border only from child's reference size. + var childConstraint = new Size(Math.Max(0.0, constraint.Width - combined.Width), + Math.Max(0.0, constraint.Height - combined.Height)); + + + child.Measure(childConstraint); + var childSize = child.DesiredSize; + + // Now use the returned size to drive our size, by adding back the margins, etc. + desiredSize.Width = childSize.Width + combined.Width; + desiredSize.Height = childSize.Height + combined.Height; + } + else + { + // Combine into total decorating size + desiredSize = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height); + } + + return desiredSize; + } + + /// + /// Border computes the position of its single child and applies its child's alignments to the child. + /// + /// The size reserved for this element by the parent + /// The actual ink area of the element, typically the same as finalSize + protected override Size ArrangeOverride(Size finalSize) + { + var borders = BorderThickness; + + if (UseLayoutRounding) + { + var dpi = DpiUtil.GetDpi(this); + borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY), + UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); + } + + var boundRect = new Rect(finalSize); + var innerRect = RectUtil.Deflate(boundRect, borders); + + // arrange child + var child = Child; + if (child != null) + { + Rect childRect = RectUtil.Deflate(innerRect, Padding); + child.Arrange(childRect); + } + + var radius = CornerRadius; + + useComplexRender = !CornerRadiusUtil.IsUniform(radius) || !ThicknessUtil.IsUniform(borders); + backgroundGeometryCache = upperLeftCache = upperRightCache = lowerRightCache = lowerLeftCache = null; + + if (useComplexRender) + { + // calculate border / background rendering geometry + if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height)) + { + var outerRadii = new Radii(boundRect, radius, borders, true); + + // Upper-right corner + var radiusX = boundRect.TopRight.X - outerRadii.TopRight.X; + var radiusY = outerRadii.RightTop.Y - boundRect.TopRight.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + upperRightCache = GenerateRoundedGeometry(outerRadii.TopRight, outerRadii.RightTop, new Size(radiusX, radiusY)); + } + + // Lower-right corner + radiusX = boundRect.BottomRight.X - outerRadii.BottomRight.X; + radiusY = boundRect.BottomRight.Y - outerRadii.RightBottom.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + lowerRightCache = GenerateRoundedGeometry(outerRadii.RightBottom, outerRadii.BottomRight, new Size(radiusX, radiusY)); + } + + // Lower-left corner + radiusX = outerRadii.BottomLeft.X - boundRect.BottomLeft.X; + radiusY = boundRect.BottomLeft.Y - outerRadii.LeftBottom.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + lowerLeftCache = GenerateRoundedGeometry(outerRadii.BottomLeft, outerRadii.LeftBottom, new Size(radiusX, radiusY)); + } + + // Upper-left corner + radiusX = outerRadii.TopLeft.X - boundRect.TopLeft.X; + radiusY = outerRadii.LeftTop.Y - boundRect.TopLeft.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + upperLeftCache = GenerateRoundedGeometry(outerRadii.LeftTop, outerRadii.TopLeft, new Size(radiusX, radiusY)); + } + } + + if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height)) + { + var innerRadii = new Radii(innerRect, radius, borders, false); + var backgroundGeometry = new StreamGeometry(); + + using (StreamGeometryContext sc = backgroundGeometry.Open()) + { + // create the border geometry + sc.BeginFigure(innerRadii.TopLeft, true /* is filled */, true /* is closed */); + + // Top line + sc.LineTo(innerRadii.TopRight, true /* is stroked */, false /* is smooth join */); + + // Upper-right corners + var radiusX = innerRect.TopRight.X - innerRadii.TopRight.X; + var radiusY = innerRadii.RightTop.Y - innerRect.TopRight.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + sc.ArcTo(innerRadii.RightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); + } + + // Right line + sc.LineTo(innerRadii.RightBottom, true /* is stroked */, false /* is smooth join */); + + // Lower-right corners + radiusX = innerRect.BottomRight.X - innerRadii.BottomRight.X; + radiusY = innerRect.BottomRight.Y - innerRadii.RightBottom.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + sc.ArcTo(innerRadii.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); + } + + // Bottom line + sc.LineTo(innerRadii.BottomLeft, true /* is stroked */, false /* is smooth join */); + + // Lower-left corners + radiusX = innerRadii.BottomLeft.X - innerRect.BottomLeft.X; + radiusY = innerRect.BottomLeft.Y - innerRadii.LeftBottom.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + sc.ArcTo(innerRadii.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); + } + + // Left line + sc.LineTo(innerRadii.LeftTop, true /* is stroked */, false /* is smooth join */); + + // Upper-left corners + radiusX = innerRadii.TopLeft.X - innerRect.TopLeft.X; + radiusY = innerRadii.LeftTop.Y - innerRect.TopLeft.Y; + if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) + { + sc.ArcTo(innerRadii.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); + } + } + + backgroundGeometry.Freeze(); + backgroundGeometryCache = backgroundGeometry; + } + } + + return finalSize; + } + + protected override void OnRender(DrawingContext dc) + { + if (useComplexRender) + { + ComplexRender(dc); + } else + { + SimpleRender(dc); + } + } + + #endregion + + #region Private Methods + + private void SimpleRender(DrawingContext dc) + { + var useLayoutRounding = UseLayoutRounding; + var dpi = DpiUtil.GetDpi(this); + + Brush brush; + var borderStyle = BorderStyle; + + var borders = BorderThickness; + var cornerRadius = CornerRadius; + + var outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radius + var roundedCorners = !DoubleUtil.IsZero(outerCornerRadius); + + var width = RenderSize.Width; + var height = RenderSize.Height; + + // Draw border + if (!ThicknessUtil.IsZero(borders) && (brush = BorderBrush) != null) + { + var pen = GetPen(brush, borderStyle, borders.Left, dpi.DpiScaleX, useLayoutRounding); + var penThickness = pen.Thickness; + + double x = penThickness * 0.5; + var rect = new Rect(x, x, width - penThickness, height - penThickness); + + if (roundedCorners) + { + dc.DrawRoundedRectangle(null, pen, rect, outerCornerRadius, outerCornerRadius); + } + else + { + dc.DrawRectangle(null, pen, rect); + } + } + + // Draw background in rectangle inside border. + if ((brush = Background) != null) + { + // Intialize background + Point ptTL, ptBR; + + if (useLayoutRounding) + { + ptTL = new Point(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), + UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY)); + ptBR = new Point(width - UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), + height - UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); + } + else + { + ptTL = new Point(borders.Left, borders.Top); + ptBR = new Point(width - borders.Right, height - borders.Bottom); + } + + // Do not draw background if the borders are so large that they overlap. + if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y) + { + if (roundedCorners) + { + // Determine the inner edge radius + var innerCornerRadius = Math.Max(0.0, outerCornerRadius - borders.Top * 0.5); + dc.DrawRoundedRectangle(brush, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius); + } + else + { + dc.DrawRectangle(brush, null, new Rect(ptTL, ptBR)); + } + } + } + } + + private void ComplexRender(DrawingContext dc) + { + Brush brush; + var width = RenderSize.Width; + var height = RenderSize.Height; + + //Draw border + if (!DoubleUtil.IsZero(width) && !DoubleUtil.IsZero(height) && (brush = BorderBrush) != null) + { + var useLayoutRounding = UseLayoutRounding; + var dpi = DpiUtil.GetDpi(this); + + var borders = BorderThickness; + var borderStyle = BorderStyle; + var radius = CornerRadius; + double x, y; + + // Left Line + if (!DoubleUtil.IsZero(borders.Left)) + { + if (leftPenCache == null) + { + leftPenCache = GetPen(brush, borderStyle, borders.Left, dpi.DpiScaleX, useLayoutRounding); + } + + x = leftPenCache.Thickness * 0.5; + dc.DrawLine(leftPenCache, new Point(x, radius.TopLeft), new Point(x, height - radius.BottomLeft)); + } + + // Top Line + if (!DoubleUtil.IsZero(borders.Top)) + { + if (topPenCache == null) + { + topPenCache = GetPen(brush, borderStyle, borders.Top, dpi.DpiScaleY, useLayoutRounding); + } + + y = topPenCache.Thickness * 0.5; + dc.DrawLine(topPenCache, new Point(radius.TopLeft, y), new Point(width - radius.TopRight, y)); + } + + // Right Line + if (!DoubleUtil.IsZero(borders.Right)) + { + if (rightPenCache == null) + { + rightPenCache = GetPen(brush, borderStyle, borders.Right, dpi.DpiScaleX, useLayoutRounding); + } + + x = width - rightPenCache.Thickness * 0.5; + dc.DrawLine(rightPenCache, new Point(x, radius.TopRight), new Point(x, height - radius.BottomRight)); + } + + // Bottom Line + if (!DoubleUtil.IsZero(borders.Bottom)) + { + if (bottomPenCache == null) + { + bottomPenCache = GetPen(brush, borderStyle, borders.Bottom, dpi.DpiScaleY, useLayoutRounding); + } + + y = height - bottomPenCache.Thickness * 0.5; + dc.DrawLine(bottomPenCache, new Point(radius.BottomLeft, y), new Point(width - radius.BottomRight, y)); + } + + // Draw Rounded + Pen pen; + + if (upperLeftCache != null && (pen = GetMaxPen(leftPenCache, topPenCache)) != null) + { + dc.DrawGeometry(null, pen, upperLeftCache); + } + + if (upperRightCache != null && (pen = GetMaxPen(topPenCache, rightPenCache)) != null) + { + dc.DrawGeometry(null, pen, upperRightCache); + } + + if (lowerRightCache != null && (pen = GetMaxPen(rightPenCache, bottomPenCache)) != null) + { + dc.DrawGeometry(null, pen, lowerRightCache); + } + + if (lowerLeftCache != null && (pen = GetMaxPen(bottomPenCache, leftPenCache)) != null) + { + dc.DrawGeometry(null, pen, lowerLeftCache); + } + } + + // Draw background in rectangle inside border. + if (backgroundGeometryCache != null && (brush = Background) != null) + { + dc.DrawGeometry(brush, null, backgroundGeometryCache); + } + } + + private Pen GetMaxPen(Pen pen1, Pen pen2) + { + if (pen2 == null || (pen1 != null && pen2.Thickness < pen1.Thickness)) + { + return pen1; + } + + return pen2; + } + + private static StreamGeometry GenerateRoundedGeometry(Point startPoint, Point endPoint, Size size) + { + var streamGeometry = new StreamGeometry(); + + using (StreamGeometryContext sc = streamGeometry.Open()) + { + sc.BeginFigure(startPoint, true, false); + sc.ArcTo(endPoint, size, 0, false, SweepDirection.Clockwise, true, false); + } + + streamGeometry.Freeze(); + return streamGeometry; + } + + private static Pen GetPen(Brush brush, BorderStyle borderStyle, double thickness, double dpi, bool useLayoutRounding) + { + var pen = new Pen + { + Brush = brush, + DashCap = PenLineCap.Flat, + Thickness = useLayoutRounding ? UIElementUtil.RoundLayoutValue(thickness, dpi) : thickness, + }; + + switch (borderStyle) + { + case BorderStyle.Dotted: + pen.DashStyle = new DashStyle(new double[] { 1 }, 0d); + break; + case BorderStyle.Dashed: + pen.DashStyle = new DashStyle(new double[] { 4, 2 }, 0d); + break; + default: + break; + } + + if (brush.IsFrozen) + { + pen.Freeze(); + } + + return pen; + } + + #endregion + + #region Private Structures Classes + + private struct Radii + { + #region Fields + + internal readonly Point LeftTop; + + internal readonly Point LeftBottom; + + internal readonly Point TopLeft; + + internal readonly Point TopRight; + + internal readonly Point RightTop; + + internal readonly Point RightBottom; + + internal readonly Point BottomRight; + + internal readonly Point BottomLeft; + + #endregion + + internal Radii(Rect rect, CornerRadius radius, Thickness borders, bool outer) + { + var left = borders.Left * 0.5; + var top = borders.Top * 0.5; + var right = borders.Right * 0.5; + var bottom = borders.Bottom * 0.5; + + LeftTop = new Point(0d, 0d); + LeftBottom = new Point(0d, rect.Height); + + TopLeft = new Point(0d, 0d); + TopRight = new Point(rect.Width, 0d); + + RightTop = new Point(rect.Width, 0d); + RightBottom = new Point(rect.Width, rect.Height); + + BottomRight = new Point(rect.Width, rect.Height); + BottomLeft = new Point(0d, rect.Height); + + if (outer) + { + LeftTop.X = left; + LeftBottom.X = left; + + TopLeft.Y = top; + TopRight.Y = top; + + RightTop.X -= right; + RightBottom.X -= right; + + BottomLeft.Y -= bottom; + BottomRight.Y -= bottom; + + if (!DoubleUtil.IsZero(radius.TopLeft)) + { + TopLeft.X = radius.TopLeft; // + left; + LeftTop.Y = radius.TopLeft;// + top; + } + + if (!DoubleUtil.IsZero(radius.TopRight)) + { + RightTop.Y = radius.TopRight;// + top; + TopRight.X -= radius.TopRight;// + right; + } + + if (!DoubleUtil.IsZero(radius.BottomRight)) + { + BottomRight.X -= radius.BottomRight;// + right; + RightBottom.Y -= radius.BottomRight;// + bottom; ; + } + + if (!DoubleUtil.IsZero(radius.BottomLeft)) + { + LeftBottom.Y -= radius.BottomLeft; // + bottom; + BottomLeft.X = radius.BottomLeft;// + left; + } + } else + { + TopLeft.X = Math.Max(0.0, radius.TopLeft - left); + LeftTop.Y = Math.Max(0.0, radius.TopLeft - top); + + RightTop.Y = Math.Max(0.0, radius.TopRight - top); + TopRight.X -= Math.Max(0.0, radius.TopRight - right); + + BottomRight.X -= Math.Max(0.0, radius.BottomRight - right); + RightBottom.Y -= Math.Max(0.0, radius.BottomRight - bottom); + + LeftBottom.Y -= Math.Max(0.0, radius.BottomLeft - bottom); + BottomLeft.X = Math.Max(0.0, radius.BottomLeft - left); + } + + // check keypoints for overlap and resolve by partitioning corners according to + // the percentage of each one. + + // top edge + if (TopLeft.X > TopRight.X) + { + var v = TopLeft.X / (TopLeft.X + rect.Width - TopRight.X) * rect.Width; + TopLeft.X = v; + TopRight.X = v; + } + + // right edge + if (RightTop.Y > RightBottom.Y) + { + var v = RightTop.Y / (RightTop.Y + rect.Height - RightBottom.Y) * rect.Height; + RightTop.Y = v; + RightBottom.Y = v; + } + + // bottom edge + if (BottomRight.X < BottomLeft.X) + { + var v = BottomLeft.X / (BottomLeft.X + rect.Width - BottomRight.X) * rect.Width; + BottomRight.X = v; + BottomLeft.X = v; + } + + // left edge + if (LeftBottom.Y < LeftTop.Y) + { + var v = LeftTop.Y / (LeftTop.Y + rect.Height - LeftBottom.Y) * rect.Height; + LeftBottom.Y = v; + LeftTop.Y = v; + } + + // Apply offset + var offset = new Vector(rect.TopLeft.X, rect.TopLeft.Y); + + LeftTop += offset; + LeftBottom += offset; + + TopRight += offset; + TopLeft += offset; + + RightTop += offset; + RightBottom += offset; + + BottomRight += offset; + BottomLeft += offset; + } + } + + #endregion Private Structures Classes +} diff --git a/AntdWpf/Controls/ContentControl.cs b/AntdWpf/Controls/AntdContentControl.cs similarity index 76% rename from AntdWpf/Controls/ContentControl.cs rename to AntdWpf/Controls/AntdContentControl.cs index d6ad90c..01b4b94 100644 --- a/AntdWpf/Controls/ContentControl.cs +++ b/AntdWpf/Controls/AntdContentControl.cs @@ -2,12 +2,11 @@ { using System.Windows; using System.Windows.Controls; - using ContentControlBase = System.Windows.Controls.ContentControl; - public class ContentControl : ContentControlBase + public class AntdContentControl : ContentControl { public static readonly DependencyProperty ContentCharacterCasingProperty = - DependencyProperty.Register("ContentCharacterCasing", typeof(CharacterCasing), typeof(ContentControl), + DependencyProperty.Register("ContentCharacterCasing", typeof(CharacterCasing), typeof(AntdContentControl), new FrameworkPropertyMetadata(CharacterCasing.Normal, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure), value => CharacterCasing.Normal <= (CharacterCasing)value && (CharacterCasing)value <= CharacterCasing.Upper); @@ -21,7 +20,7 @@ } public static readonly DependencyProperty RecognizesAccessKeyProperty = - DependencyProperty.Register("RecognizesAccessKey", typeof(bool), typeof(ContentControl), new FrameworkPropertyMetadata(false)); + DependencyProperty.Register("RecognizesAccessKey", typeof(bool), typeof(AntdContentControl), new FrameworkPropertyMetadata(false)); /// /// Determine if the inner ContentPresenter should use AccessText in its style @@ -32,9 +31,9 @@ set { SetValue(RecognizesAccessKeyProperty, value); } } - static ContentControl() + static AntdContentControl() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(ContentControl), new FrameworkPropertyMetadata(typeof(ContentControl))); + DefaultStyleKeyProperty.OverrideMetadata(typeof(AntdContentControl), new FrameworkPropertyMetadata(typeof(AntdContentControl))); } } } diff --git a/AntdWpf/Controls/Window.cs b/AntdWpf/Controls/AntdWindow.cs similarity index 89% rename from AntdWpf/Controls/Window.cs rename to AntdWpf/Controls/AntdWindow.cs index 086ed4b..e55428b 100644 --- a/AntdWpf/Controls/Window.cs +++ b/AntdWpf/Controls/AntdWindow.cs @@ -1,9 +1,6 @@ -using AntdWpf.Controls; - -using AntdWpf.Contracts; +using AntdWpf.Contracts; using AntdWpf.Microsoft.Windows.Shell; using AntdWpf.Win32; -using Microsoft.Windows.Shell; using System; using System.Collections; using System.Reflection; @@ -14,22 +11,19 @@ using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; using Standard; -using SystemCommands = AntdWpf.Microsoft.Windows.Shell.SystemCommands; -using ThumbBase = System.Windows.Controls.Primitives.Thumb; -using WindowBase = System.Windows.Window; namespace AntdWpf.Controls { - [TemplatePart(Name = PART_TitleBarThumb, Type = typeof(ThumbBase))] + [TemplatePart(Name = PART_TitleBarThumb, Type = typeof(Thumb))] [TemplatePart(Name = PART_TitleBar, Type = typeof(UIElement))] [TemplatePart(Name = PART_Icon, Type = typeof(FrameworkElement))] [TemplatePart(Name = PART_LeftWindowCommands, Type = typeof(WindowCommands))] [TemplatePart(Name = PART_Title, Type = typeof(UIElement))] [TemplatePart(Name = PART_RightWindowCommands, Type = typeof(WindowCommands))] [TemplatePart(Name = PART_WindowButtons, Type = typeof(WindowButtons))] - public class Window : WindowBase + public class AntdWindow : Window { #region Fields @@ -47,7 +41,7 @@ namespace AntdWpf.Controls private const string PART_WindowButtons = "PART_WindowButtons"; - private ThumbBase titleBarThumb; + private Thumb titleBarThumb; private UIElement titleBar; @@ -66,7 +60,7 @@ namespace AntdWpf.Controls #region Properties public static readonly DependencyProperty IgnoreTaskbarProperty = - DependencyProperty.Register("IgnoreTaskbar", typeof(bool), typeof(Window), new PropertyMetadata(false)); + DependencyProperty.Register("IgnoreTaskbar", typeof(bool), typeof(AntdWindow), new PropertyMetadata(false)); /// /// Gets/sets whether the window will ignore (and overlap) the taskbar when maximized. @@ -78,7 +72,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty ShowSystemMenuProperty = - DependencyProperty.Register("ShowSystemMenu", typeof(bool), typeof(Window), new PropertyMetadata(false)); + DependencyProperty.Register("ShowSystemMenu", typeof(bool), typeof(AntdWindow), new PropertyMetadata(false)); /// /// Gets/sets if the the system menu should popup on right click. @@ -90,7 +84,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty IsDraggableProperty = - DependencyProperty.Register("IsDraggable", typeof(bool), typeof(Window), new PropertyMetadata(true)); + DependencyProperty.Register("IsDraggable", typeof(bool), typeof(AntdWindow), new PropertyMetadata(true)); /// /// Gets/sets if the the allow drag window @@ -102,7 +96,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty UseNoneWindowStyleProperty = - DependencyProperty.Register("UseNoneWindowStyle", typeof(bool), typeof(Window), new PropertyMetadata(false, OnUseNoneWindowStyleChanged)); + DependencyProperty.Register("UseNoneWindowStyle", typeof(bool), typeof(AntdWindow), new PropertyMetadata(false, OnUseNoneWindowStyleChanged)); /// /// Gets/sets whether the WindowStyle is None or not. @@ -117,7 +111,7 @@ namespace AntdWpf.Controls { if (e.NewValue != e.OldValue) { - (d as Window).ToggleNoneWindowStyle((bool)e.NewValue); + (d as AntdWindow).ToggleNoneWindowStyle((bool)e.NewValue); } } @@ -130,13 +124,13 @@ namespace AntdWpf.Controls { get { - var value = typeof(WindowBase).GetProperty("CriticalHandle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this, new object[0]); + var value = typeof(Window).GetProperty("CriticalHandle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this, new object[0]); return (IntPtr)value; } } public static readonly DependencyProperty TitleBarHeightProperty = - DependencyProperty.Register("TitleBarHeight", typeof(double), typeof(Window), new PropertyMetadata(30d, OnTitleBarHeightChanged)); + DependencyProperty.Register("TitleBarHeight", typeof(double), typeof(AntdWindow), new PropertyMetadata(30d, OnTitleBarHeightChanged)); /// /// Gets/sets the TitleBar height. @@ -149,7 +143,7 @@ namespace AntdWpf.Controls private static void OnTitleBarHeightChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { - var window = (Window)dependencyObject; + var window = (AntdWindow)dependencyObject; if (e.NewValue != e.OldValue) { window.SetVisibiltyForTitleBarElements((int)e.NewValue > 0); @@ -157,7 +151,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty TitleBarForegroundProperty = - DependencyProperty.Register("TitleBarForeground", typeof(Brush), typeof(Window)); + DependencyProperty.Register("TitleBarForeground", typeof(Brush), typeof(AntdWindow)); /// /// Gets/sets the foreground brush of the title bar. @@ -169,7 +163,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty TitleBarBackgroundProperty = - DependencyProperty.Register("TitleBarBackground", typeof(Brush), typeof(Window), new PropertyMetadata(Brushes.Transparent)); + DependencyProperty.Register("TitleBarBackground", typeof(Brush), typeof(AntdWindow), new PropertyMetadata(Brushes.Transparent)); /// /// Gets/sets the background brush of the title bar. @@ -181,7 +175,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty ShowIconProperty = - DependencyProperty.Register("ShowIcon", typeof(bool), typeof(Window), new PropertyMetadata(true, OnShowIconChanged)); + DependencyProperty.Register("ShowIcon", typeof(bool), typeof(AntdWindow), new PropertyMetadata(true, OnShowIconChanged)); /// /// Gets/sets whether the titlebar icon is visible or not. @@ -196,12 +190,12 @@ namespace AntdWpf.Controls { if (e.NewValue != e.OldValue) { - (d as Window).SetVisibiltyForIcon(); + (d as AntdWindow).SetVisibiltyForIcon(); } } public static readonly DependencyProperty IconTemplateProperty = - DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(Window), new PropertyMetadata(null)); + DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(AntdWindow), new PropertyMetadata(null)); /// /// Gets/sets the icon content template to show a custom icon. @@ -213,7 +207,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty TitleCharacterCasingProperty = - DependencyProperty.Register("TitleCharacterCasing", typeof(CharacterCasing), typeof(Window), + DependencyProperty.Register("TitleCharacterCasing", typeof(CharacterCasing), typeof(AntdWindow), new FrameworkPropertyMetadata(CharacterCasing.Normal, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure), value => CharacterCasing.Normal <= (CharacterCasing)value && (CharacterCasing)value <= CharacterCasing.Upper); @@ -227,7 +221,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty TitleAlignmentProperty = - DependencyProperty.Register("TitleAlignment", typeof(HorizontalAlignment), typeof(Window), new PropertyMetadata(HorizontalAlignment.Stretch, OnTitleAlignmentChanged)); + DependencyProperty.Register("TitleAlignment", typeof(HorizontalAlignment), typeof(AntdWindow), new PropertyMetadata(HorizontalAlignment.Stretch, OnTitleAlignmentChanged)); public HorizontalAlignment TitleAlignment { @@ -237,7 +231,7 @@ namespace AntdWpf.Controls private static void OnTitleAlignmentChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { - if (dependencyObject is Window window) + if (dependencyObject is AntdWindow window) { window.SizeChanged -= window.OnSizeChanged; @@ -249,7 +243,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty TitleTemplateProperty = - DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(Window), new PropertyMetadata(null)); + DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(AntdWindow), new PropertyMetadata(null)); /// /// Gets/sets the title content template to show a custom title. @@ -261,7 +255,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty LeftWindowCommandsProperty = - DependencyProperty.Register("LeftWindowCommands", typeof(WindowCommands), typeof(Window), new PropertyMetadata(null, UpdateLogicalChilds)); + DependencyProperty.Register("LeftWindowCommands", typeof(WindowCommands), typeof(AntdWindow), new PropertyMetadata(null, UpdateLogicalChilds)); /// /// Gets/sets the left window commands that hosts the user commands. @@ -273,7 +267,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty RightWindowCommandsProperty = - DependencyProperty.Register("RightWindowCommands", typeof(WindowCommands), typeof(Window), new PropertyMetadata(null, UpdateLogicalChilds)); + DependencyProperty.Register("RightWindowCommands", typeof(WindowCommands), typeof(AntdWindow), new PropertyMetadata(null, UpdateLogicalChilds)); /// /// Gets/sets the right window commands that hosts the user commands. @@ -285,7 +279,7 @@ namespace AntdWpf.Controls } public static readonly DependencyProperty WindowButtonsProperty = - DependencyProperty.Register("WindowButtons", typeof(WindowButtons), typeof(Window), new PropertyMetadata(null, UpdateLogicalChilds)); + DependencyProperty.Register("WindowButtons", typeof(WindowButtons), typeof(AntdWindow), new PropertyMetadata(null, UpdateLogicalChilds)); /// /// Gets/sets the window button commands that hosts the min/max/close commands. @@ -298,7 +292,7 @@ namespace AntdWpf.Controls private static void UpdateLogicalChilds(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { - if (!(dependencyObject is Window window)) + if (!(dependencyObject is AntdWindow window)) { return; } @@ -332,14 +326,14 @@ namespace AntdWpf.Controls #region Constructors - static Window() + static AntdWindow() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata(typeof(Window))); + DefaultStyleKeyProperty.OverrideMetadata(typeof(AntdWindow), new FrameworkPropertyMetadata(typeof(AntdWindow))); } - public Window() + public AntdWindow() { - SetResourceReference(StyleProperty, typeof(Window)); + //SetResourceReference(StyleProperty, typeof(AntdWindow)); DataContextChanged += OnDataContextChanged; } @@ -381,7 +375,7 @@ namespace AntdWpf.Controls { base.OnApplyTemplate(); - titleBarThumb = GetTemplateChild(PART_TitleBarThumb) as ThumbBase; + titleBarThumb = GetTemplateChild(PART_TitleBarThumb) as Thumb; titleBar = GetTemplateChild(PART_TitleBar) as UIElement; icon = GetTemplateChild(PART_Icon) as FrameworkElement; title = GetTemplateChild(PART_Title) as UIElement; @@ -557,9 +551,7 @@ namespace AntdWpf.Controls Close(); } else { -#pragma warning disable 618 - SystemCommands.ShowSystemMenu(this, PointToScreen(new Point(0, TitleBarHeight))); -#pragma warning restore 618 + System.Windows.SystemCommands.ShowSystemMenu(this, PointToScreen(new Point(0, TitleBarHeight))); } } @@ -583,7 +575,7 @@ namespace AntdWpf.Controls DoThumbMouseRightButtonUp(this, e); } - internal static void DoThumbPreviewMouseLeftButtonUp(Window window, MouseButtonEventArgs e) + internal static void DoThumbPreviewMouseLeftButtonUp(AntdWindow window, MouseButtonEventArgs e) { if (e.Source == e.OriginalSource) { @@ -591,7 +583,7 @@ namespace AntdWpf.Controls } } - internal static void DoThumbDragDelta(IThumb thumb, Window window, DragDeltaEventArgs e) + internal static void DoThumbDragDelta(IThumb thumb, AntdWindow window, DragDeltaEventArgs e) { if (thumb == null) { @@ -660,7 +652,7 @@ namespace AntdWpf.Controls /// /// /// - internal static void DoThumbMouseDoubleClick(Window window, MouseButtonEventArgs e) + internal static void DoThumbMouseDoubleClick(AntdWindow window, MouseButtonEventArgs e) { // restore/maximize only with left button if (e.ChangedButton == MouseButton.Left) @@ -671,16 +663,14 @@ namespace AntdWpf.Controls var isMouseOnTitlebar = mousePos.Y <= window.TitleBarHeight && window.TitleBarHeight > 0; if (canResize && isMouseOnTitlebar) { -#pragma warning disable 618 if (window.WindowState == WindowState.Normal) { - SystemCommands.MaximizeWindow(window); + System.Windows.SystemCommands.MaximizeWindow(window); } else { - SystemCommands.RestoreWindow(window); + System.Windows.SystemCommands.RestoreWindow(window); } -#pragma warning restore 618 e.Handled = true; } } @@ -691,7 +681,7 @@ namespace AntdWpf.Controls /// /// /// - internal static void DoThumbMouseRightButtonUp(Window window, MouseButtonEventArgs e) + internal static void DoThumbMouseRightButtonUp(AntdWindow window, MouseButtonEventArgs e) { if (window.ShowSystemMenu) { @@ -699,9 +689,7 @@ namespace AntdWpf.Controls var mousePos = e.GetPosition(window); if ((mousePos.Y <= window.TitleBarHeight && window.TitleBarHeight > 0) || (window.UseNoneWindowStyle && window.TitleBarHeight <= 0)) { -#pragma warning disable 618 - SystemCommands.ShowSystemMenu(window, window.PointToScreen(mousePos)); -#pragma warning restore 618 + System.Windows.SystemCommands.ShowSystemMenu(window, window.PointToScreen(mousePos)); } } } diff --git a/AntdWpf/Controls/Avatar.cs b/AntdWpf/Controls/Avatar.cs index ebc774c..e21be2e 100644 --- a/AntdWpf/Controls/Avatar.cs +++ b/AntdWpf/Controls/Avatar.cs @@ -1,258 +1,256 @@ -namespace AntdWpf.Controls +namespace AntdWpf.Controls; + +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; +using System.Windows.Media; + +/// +/// Avatars can be used to represent people or objects. It supports images, Icons, or letters. +/// +[ContentProperty("Text")] +[TemplatePart(Name = "PART_Content", Type = typeof(ContentPresenter))] +public class Avatar : Control { - using System.Windows; - using System.Windows.Controls; - using System.Windows.Markup; - using System.Windows.Media; - using ControlBase = System.Windows.Controls.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)); /// - /// Avatars can be used to represent people or objects. It supports images, Icons, or letters. + /// Gets/sets the icon type for an icon avatar. /// - [ContentProperty("Text")] - [TemplatePart(Name = "PART_Content", Type = typeof(ContentPresenter))] - public class Avatar : ControlBase + public string Icon { - #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)); - - /// - /// Gets/sets the icon type for an icon avatar. - /// - 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)); - - /// - /// Gets/sets the shape of avatar. - /// - 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)); - - /// - /// Gets/sets the size of the avatar. - /// - 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)); - - /// - /// Gets/sets the ImageSource for an image avatar. - /// - 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)); - - /// - /// Gets/sets the text for an text avatar. - /// - 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)); - - /// - /// Gets/sets the alternative text describing the image. - /// - 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)); - - /// - /// Gets the current avatar type as an image. - /// - 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) - { - ClearValue(IsImageProperty); - ((Image)content).ImageFailed -= OnImageFailed; - } - else if (content is TextBlock) - { - SizeChanged -= OnTextSizeChanged; - ((TextBlock)content).SizeChanged -= OnTextSizeChanged; - } - - if (Source != null && imageExist) - { - if (!(content is 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 Icon)) - { - content = new Icon(); - } - - ((Icon)content).Type = Icon; - } - else - { - var text = string.IsNullOrEmpty(Text) ? (imageExist ? string.Empty : Alternative) : Text; - - if (!(content is 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); - } - - /// - /// Autoset Font Size - /// - /// - /// - 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 + 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)); + + /// + /// Gets/sets the shape of avatar. + /// + 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)); + + /// + /// Gets/sets the size of the avatar. + /// + 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)); + + /// + /// Gets/sets the ImageSource for an image avatar. + /// + 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)); + + /// + /// Gets/sets the text for an text avatar. + /// + 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)); + + /// + /// Gets/sets the alternative text describing the image. + /// + 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)); + + /// + /// Gets the current avatar type as an image. + /// + 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); + } + + /// + /// Autoset Font Size + /// + /// + /// + 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 } diff --git a/AntdWpf/Controls/Badge.cs b/AntdWpf/Controls/Badge.cs index 05a6b5a..54d989e 100644 --- a/AntdWpf/Controls/Badge.cs +++ b/AntdWpf/Controls/Badge.cs @@ -1,224 +1,223 @@ -namespace AntdWpf.Controls +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using WindowSize = System.Windows.Size; +using ContentControlBase = System.Windows.Controls.ContentControl; + +namespace AntdWpf.Controls; + +[TemplatePart(Name = PART_BadgeContainer, Type = typeof(FrameworkElement))] +[TemplatePart(Name = PART_Count, Type = typeof(ContentPresenter))] +public class Badge : ContentControlBase { - using System.Windows; - using System.Windows.Controls; - using System.Windows.Media; - using WindowSize = System.Windows.Size; - using ContentControlBase = System.Windows.Controls.ContentControl; + #region Fields - [TemplatePart(Name = PART_BadgeContainer, Type = typeof(FrameworkElement))] - [TemplatePart(Name = PART_Count, Type = typeof(ContentPresenter))] - public class Badge : ContentControlBase + private const string PART_BadgeContainer = "PART_BadgeContainer"; + + private const string PART_Count = "PART_Count"; + + private FrameworkElement badgeContainer; + + private ContentPresenter count; + + #endregion + + #region Properties + + public static readonly DependencyProperty CountProperty = + DependencyProperty.Register("Count", typeof(object), typeof(Badge), new PropertyMetadata(null, OnCountChanged)); + + /// + /// Gets/sets number to show in badge + /// + public object Count { - #region Fields + get { return (object)GetValue(CountProperty); } + set { SetValue(CountProperty, value); } + } - private const string PART_BadgeContainer = "PART_BadgeContainer"; + private static void OnCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as Badge).ApplyCount(); + } - private const string PART_Count = "PART_Count"; + private void ApplyCount() + { + if (count == null) return; - private FrameworkElement badgeContainer; + var content = Count; - private ContentPresenter count; - - #endregion - - #region Properties - - public static readonly DependencyProperty CountProperty = - DependencyProperty.Register("Count", typeof(object), typeof(Badge), new PropertyMetadata(null, OnCountChanged)); - - /// - /// Gets/sets number to show in badge - /// - public object Count + if (Count is string) { - get { return (object)GetValue(CountProperty); } - set { SetValue(CountProperty, value); } - } - - private static void OnCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as Badge).ApplyCount(); - } - - private void ApplyCount() - { - if (count == null) return; - - var content = Count; - - if (Count is string) + try { - try + var d = int.Parse(Count as string); + + if (d > OverflowCount) { - var d = int.Parse(Count as string); - - if (d > OverflowCount) - { - content = OverflowCount + "+"; - } + content = OverflowCount + "+"; } - catch { } // Swallow the error, it may be normal } - - count.Content = content; + catch { } // Swallow the error, it may be normal } - public static readonly DependencyProperty DotProperty = - DependencyProperty.Register("Dot", typeof(bool), typeof(Badge), new PropertyMetadata(false)); - - /// - /// Gets/sets whether to display a red dot instead of count - /// - public bool Dot - { - get { return (bool)GetValue(DotProperty); } - set { SetValue(DotProperty, value); } - } - - public static readonly DependencyProperty OffsetProperty = - DependencyProperty.Register("Offset", typeof(Point?), typeof(Badge), new PropertyMetadata(null)); - - public Point? Offset - { - get { return (Point?)GetValue(OffsetProperty); } - set { SetValue(OffsetProperty, value); } - } - - public static readonly DependencyProperty OverflowCountProperty = - DependencyProperty.Register("OverflowCount", typeof(int), typeof(Badge), new PropertyMetadata(99, OnCountChanged)); - - /// - /// Gets/sets max count to show - /// - public int OverflowCount - { - get { return (int)GetValue(OverflowCountProperty); } - set { SetValue(OverflowCountProperty, value); } - } - - public static readonly DependencyProperty ShowZeroProperty = - DependencyProperty.Register("ShowZero", typeof(bool), typeof(Badge), new PropertyMetadata(false)); - - /// - /// Gets/sets whether to show badge when count is zero - /// - public bool ShowZero - { - get { return (bool)GetValue(ShowZeroProperty); } - set { SetValue(ShowZeroProperty, value); } - } - - public static readonly DependencyProperty StatusProperty = - DependencyProperty.Register("Status", typeof(BadgeStatus?), typeof(Badge), new PropertyMetadata(null)); - - /// - /// Gets/sets badge as a status dot - /// - public BadgeStatus? Status - { - get { return (BadgeStatus?)GetValue(StatusProperty); } - set { SetValue(StatusProperty, value); } - } - - public static readonly DependencyProperty TextProperty = - DependencyProperty.Register("Text", typeof(string), typeof(Badge), new PropertyMetadata(string.Empty)); - - /// - /// Gets/sets the text of the status dot. valid with StatusProperty set - /// - public string Text - { - get { return (string)GetValue(TextProperty); } - set { SetValue(TextProperty, value); } - } - - public static readonly DependencyProperty BadgeHeightProperty = - DependencyProperty.Register("BadgeHeight", typeof(double), typeof(Badge), new PropertyMetadata(default(double))); - - public double BadgeHeight - { - get { return (double)GetValue(BadgeHeightProperty); } - set { SetValue(BadgeHeightProperty, value); } - } - - public static readonly DependencyProperty BadgeForegroundProperty = - DependencyProperty.Register("BadgeForeground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush))); - - public Brush BadgeForeground - { - get { return (Brush)GetValue(BadgeForegroundProperty); } - set { SetValue(BadgeForegroundProperty, value); } - } - - - public static readonly DependencyProperty BadgeBackgroundProperty = - DependencyProperty.Register("BadgeBackground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush))); - - public Brush BadgeBackground - { - get { return (Brush)GetValue(BadgeBackgroundProperty); } - set { SetValue(BadgeBackgroundProperty, value); } - } - - - #endregion - - #region Constructors - - static Badge() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(Badge), new FrameworkPropertyMetadata(typeof(Badge))); - } - - #endregion - - #region Overrides - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - badgeContainer = GetTemplateChild(PART_BadgeContainer) as FrameworkElement; - count = GetTemplateChild(PART_Count) as ContentPresenter; - - ApplyCount(); - } - - protected override WindowSize ArrangeOverride(WindowSize arrangeBounds) - { - var result = base.ArrangeOverride(arrangeBounds); - - if (badgeContainer == null) return result; - - var desiredSize = badgeContainer.DesiredSize; - - // System.Console.WriteLine(desiredSize); - // if ((desiredSize.Width <= 0.0 || desiredSize.Height <= 0.0)) - - - //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); - //} - - var h = 0 - desiredSize.Width / 2; - var v = 0 - desiredSize.Height / 2; - - // badgeContainer.Margin = new Thickness(0); - // badgeContainer.Margin = new Thickness(h, v, h, v); - - return result; - } - - #endregion + count.Content = content; } - public enum BadgeStatus : byte + public static readonly DependencyProperty DotProperty = + DependencyProperty.Register("Dot", typeof(bool), typeof(Badge), new PropertyMetadata(false)); + + /// + /// Gets/sets whether to display a red dot instead of count + /// + public bool Dot { - Success, Processing, Default, Error, Warning + get { return (bool)GetValue(DotProperty); } + set { SetValue(DotProperty, value); } } + + public static readonly DependencyProperty OffsetProperty = + DependencyProperty.Register("Offset", typeof(Point?), typeof(Badge), new PropertyMetadata(null)); + + public Point? Offset + { + get { return (Point?)GetValue(OffsetProperty); } + set { SetValue(OffsetProperty, value); } + } + + public static readonly DependencyProperty OverflowCountProperty = + DependencyProperty.Register("OverflowCount", typeof(int), typeof(Badge), new PropertyMetadata(99, OnCountChanged)); + + /// + /// Gets/sets max count to show + /// + public int OverflowCount + { + get { return (int)GetValue(OverflowCountProperty); } + set { SetValue(OverflowCountProperty, value); } + } + + public static readonly DependencyProperty ShowZeroProperty = + DependencyProperty.Register("ShowZero", typeof(bool), typeof(Badge), new PropertyMetadata(false)); + + /// + /// Gets/sets whether to show badge when count is zero + /// + public bool ShowZero + { + get { return (bool)GetValue(ShowZeroProperty); } + set { SetValue(ShowZeroProperty, value); } + } + + public static readonly DependencyProperty StatusProperty = + DependencyProperty.Register("Status", typeof(BadgeStatus?), typeof(Badge), new PropertyMetadata(null)); + + /// + /// Gets/sets badge as a status dot + /// + public BadgeStatus? Status + { + get { return (BadgeStatus?)GetValue(StatusProperty); } + set { SetValue(StatusProperty, value); } + } + + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register("Text", typeof(string), typeof(Badge), new PropertyMetadata(string.Empty)); + + /// + /// Gets/sets the text of the status dot. valid with StatusProperty set + /// + public string Text + { + get { return (string)GetValue(TextProperty); } + set { SetValue(TextProperty, value); } + } + + public static readonly DependencyProperty BadgeHeightProperty = + DependencyProperty.Register("BadgeHeight", typeof(double), typeof(Badge), new PropertyMetadata(default(double))); + + public double BadgeHeight + { + get { return (double)GetValue(BadgeHeightProperty); } + set { SetValue(BadgeHeightProperty, value); } + } + + public static readonly DependencyProperty BadgeForegroundProperty = + DependencyProperty.Register("BadgeForeground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush))); + + public Brush BadgeForeground + { + get { return (Brush)GetValue(BadgeForegroundProperty); } + set { SetValue(BadgeForegroundProperty, value); } + } + + + public static readonly DependencyProperty BadgeBackgroundProperty = + DependencyProperty.Register("BadgeBackground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush))); + + public Brush BadgeBackground + { + get { return (Brush)GetValue(BadgeBackgroundProperty); } + set { SetValue(BadgeBackgroundProperty, value); } + } + + + #endregion + + #region Constructors + + static Badge() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(Badge), new FrameworkPropertyMetadata(typeof(Badge))); + } + + #endregion + + #region Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + badgeContainer = GetTemplateChild(PART_BadgeContainer) as FrameworkElement; + count = GetTemplateChild(PART_Count) as ContentPresenter; + + ApplyCount(); + } + + protected override WindowSize ArrangeOverride(WindowSize arrangeBounds) + { + var result = base.ArrangeOverride(arrangeBounds); + + if (badgeContainer == null) return result; + + var desiredSize = badgeContainer.DesiredSize; + + // System.Console.WriteLine(desiredSize); + // if ((desiredSize.Width <= 0.0 || desiredSize.Height <= 0.0)) + + + //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); + //} + + var h = 0 - desiredSize.Width / 2; + var v = 0 - desiredSize.Height / 2; + + // badgeContainer.Margin = new Thickness(0); + // badgeContainer.Margin = new Thickness(h, v, h, v); + + return result; + } + + #endregion +} + +public enum BadgeStatus : byte +{ + Success, Processing, Default, Error, Warning } diff --git a/AntdWpf/Controls/Border.cs b/AntdWpf/Controls/Border.cs deleted file mode 100644 index 0c564cb..0000000 --- a/AntdWpf/Controls/Border.cs +++ /dev/null @@ -1,750 +0,0 @@ -namespace AntdWpf.Controls -{ - using System; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Media; - - using AntdWpf.Utils; - - /// - /// Draws a border, background, or both around another element. - /// - public class Border : Decorator - { - #region Fields - - private StreamGeometry backgroundGeometryCache; - - private StreamGeometry upperLeftCache; - - private StreamGeometry upperRightCache; - - private StreamGeometry lowerRightCache; - - private StreamGeometry lowerLeftCache; - - private bool useComplexRender; - - private Pen leftPenCache; - - private Pen topPenCache; - - private Pen rightPenCache; - - private Pen bottomPenCache; - - #endregion - - #region Properties - - public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register( - "Background", - typeof(Brush), - typeof(Border), - new FrameworkPropertyMetadata( - null, - FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender - )); - - /// - /// Gets or sets the brush that fills the area between the bounds of a Border. - /// - public Brush Background - { - get { return (Brush)GetValue(BackgroundProperty); } - set { SetValue(BackgroundProperty, value); } - } - - public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register( - "BorderBrush", - typeof(Brush), - typeof(Border), - new FrameworkPropertyMetadata( - null, - FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, - OnClearPenCache - )); - - /// - /// Gets or sets the brush that draws the outer border color. - /// - public Brush BorderBrush - { - get { return (Brush)GetValue(BorderBrushProperty); } - set { SetValue(BorderBrushProperty, value); } - } - - public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register( - "BorderThickness", - typeof(Thickness), - typeof(Border), - new FrameworkPropertyMetadata( - new Thickness(), - FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, - OnClearPenCache - ), - IsThicknessValid); - - /// - /// Gets or sets the relative thickness of a border. - /// - public Thickness BorderThickness - { - get { return (Thickness)GetValue(BorderThicknessProperty); } - set { SetValue(BorderThicknessProperty, value); } - } - - private static void OnClearPenCache(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var border = (Border)d; - border.leftPenCache = border.topPenCache = border.rightPenCache = border.bottomPenCache = null; - } - - private static bool IsThicknessValid(object value) - { - return ThicknessUtil.IsValid((Thickness)value, false, false, false, false); - } - - public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( - "CornerRadius", - typeof(CornerRadius), - typeof(Border), - new FrameworkPropertyMetadata( - new CornerRadius(), - FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender - ), - IsCornerRadiusValid); - - /// - /// Gets or sets a value that represents the degree to which the corners of a Border are rounded. - /// - public CornerRadius CornerRadius - { - get { return (CornerRadius)GetValue(CornerRadiusProperty); } - set { SetValue(CornerRadiusProperty, value); } - } - - private static bool IsCornerRadiusValid(object value) - { - return CornerRadiusUtil.IsValid((CornerRadius)value, false, false, false, false); - } - - public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register( - "Padding", - typeof(Thickness), - typeof(Border), - new FrameworkPropertyMetadata( - new Thickness(), - FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender - ), - IsThicknessValid); - - /// - /// Gets or sets a thickness value that describes the amount of space between a border and its child element. - /// - public Thickness Padding - { - get { return (Thickness)GetValue(PaddingProperty); } - set { SetValue(PaddingProperty, value); } - } - - public static readonly DependencyProperty BorderStyleProperty = DependencyProperty.Register( - "BorderStyle", - typeof(BorderStyle), - typeof(Border), - new FrameworkPropertyMetadata( - BorderStyle.Solid, - FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, - OnClearPenCache - )); - - /// - /// Gets or sets the border style. - /// - public BorderStyle BorderStyle - { - get { return (BorderStyle)GetValue(BorderStyleProperty); } - set { SetValue(BorderStyleProperty, value); } - } - - #endregion - - #region Overrides - - /// - /// Updates DesiredSize of the Border. Called by parent UIElement. This is the first pass of layout. - /// - /// - /// Border determines its desired size it needs from the specified border the child: its sizing - /// properties, margin, and requested size. - /// - /// Constraint size is an "upper limit" that the return value should not exceed. - /// The Decorator's desired size. - protected override Size MeasureOverride(Size constraint) - { - var child = Child; - var desiredSize = new Size(); - var borders = BorderThickness; - - if (UseLayoutRounding) - { - var dpi = DpiUtil.GetDpi(this); - borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY), - UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); - } - - // Compute the total size required - var borderSize = ThicknessUtil.CollapseThickness(borders); - var paddingSize = ThicknessUtil.CollapseThickness(Padding); - - // If we have a child - if (child != null) - { - // Combine into total decorating size - var combined = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height); - - // Remove size of border only from child's reference size. - var childConstraint = new Size(Math.Max(0.0, constraint.Width - combined.Width), - Math.Max(0.0, constraint.Height - combined.Height)); - - - child.Measure(childConstraint); - var childSize = child.DesiredSize; - - // Now use the returned size to drive our size, by adding back the margins, etc. - desiredSize.Width = childSize.Width + combined.Width; - desiredSize.Height = childSize.Height + combined.Height; - } - else - { - // Combine into total decorating size - desiredSize = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height); - } - - return desiredSize; - } - - /// - /// Border computes the position of its single child and applies its child's alignments to the child. - /// - /// The size reserved for this element by the parent - /// The actual ink area of the element, typically the same as finalSize - protected override Size ArrangeOverride(Size finalSize) - { - var borders = BorderThickness; - - if (UseLayoutRounding) - { - var dpi = DpiUtil.GetDpi(this); - borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY), - UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); - } - - var boundRect = new Rect(finalSize); - var innerRect = RectUtil.Deflate(boundRect, borders); - - // arrange child - var child = Child; - if (child != null) - { - Rect childRect = RectUtil.Deflate(innerRect, Padding); - child.Arrange(childRect); - } - - var radius = CornerRadius; - - useComplexRender = !CornerRadiusUtil.IsUniform(radius) || !ThicknessUtil.IsUniform(borders); - backgroundGeometryCache = upperLeftCache = upperRightCache = lowerRightCache = lowerLeftCache = null; - - if (useComplexRender) - { - // calculate border / background rendering geometry - if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height)) - { - var outerRadii = new Radii(boundRect, radius, borders, true); - - // Upper-right corner - var radiusX = boundRect.TopRight.X - outerRadii.TopRight.X; - var radiusY = outerRadii.RightTop.Y - boundRect.TopRight.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - upperRightCache = GenerateRoundedGeometry(outerRadii.TopRight, outerRadii.RightTop, new Size(radiusX, radiusY)); - } - - // Lower-right corner - radiusX = boundRect.BottomRight.X - outerRadii.BottomRight.X; - radiusY = boundRect.BottomRight.Y - outerRadii.RightBottom.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - lowerRightCache = GenerateRoundedGeometry(outerRadii.RightBottom, outerRadii.BottomRight, new Size(radiusX, radiusY)); - } - - // Lower-left corner - radiusX = outerRadii.BottomLeft.X - boundRect.BottomLeft.X; - radiusY = boundRect.BottomLeft.Y - outerRadii.LeftBottom.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - lowerLeftCache = GenerateRoundedGeometry(outerRadii.BottomLeft, outerRadii.LeftBottom, new Size(radiusX, radiusY)); - } - - // Upper-left corner - radiusX = outerRadii.TopLeft.X - boundRect.TopLeft.X; - radiusY = outerRadii.LeftTop.Y - boundRect.TopLeft.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - upperLeftCache = GenerateRoundedGeometry(outerRadii.LeftTop, outerRadii.TopLeft, new Size(radiusX, radiusY)); - } - } - - if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height)) - { - var innerRadii = new Radii(innerRect, radius, borders, false); - var backgroundGeometry = new StreamGeometry(); - - using (StreamGeometryContext sc = backgroundGeometry.Open()) - { - // create the border geometry - sc.BeginFigure(innerRadii.TopLeft, true /* is filled */, true /* is closed */); - - // Top line - sc.LineTo(innerRadii.TopRight, true /* is stroked */, false /* is smooth join */); - - // Upper-right corners - var radiusX = innerRect.TopRight.X - innerRadii.TopRight.X; - var radiusY = innerRadii.RightTop.Y - innerRect.TopRight.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - sc.ArcTo(innerRadii.RightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); - } - - // Right line - sc.LineTo(innerRadii.RightBottom, true /* is stroked */, false /* is smooth join */); - - // Lower-right corners - radiusX = innerRect.BottomRight.X - innerRadii.BottomRight.X; - radiusY = innerRect.BottomRight.Y - innerRadii.RightBottom.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - sc.ArcTo(innerRadii.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); - } - - // Bottom line - sc.LineTo(innerRadii.BottomLeft, true /* is stroked */, false /* is smooth join */); - - // Lower-left corners - radiusX = innerRadii.BottomLeft.X - innerRect.BottomLeft.X; - radiusY = innerRect.BottomLeft.Y - innerRadii.LeftBottom.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - sc.ArcTo(innerRadii.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); - } - - // Left line - sc.LineTo(innerRadii.LeftTop, true /* is stroked */, false /* is smooth join */); - - // Upper-left corners - radiusX = innerRadii.TopLeft.X - innerRect.TopLeft.X; - radiusY = innerRadii.LeftTop.Y - innerRect.TopLeft.Y; - if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) - { - sc.ArcTo(innerRadii.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); - } - } - - backgroundGeometry.Freeze(); - backgroundGeometryCache = backgroundGeometry; - } - } - - return finalSize; - } - - protected override void OnRender(DrawingContext dc) - { - if (useComplexRender) - { - ComplexRender(dc); - } else - { - SimpleRender(dc); - } - } - - #endregion - - #region Private Methods - - private void SimpleRender(DrawingContext dc) - { - var useLayoutRounding = UseLayoutRounding; - var dpi = DpiUtil.GetDpi(this); - - Brush brush; - var borderStyle = BorderStyle; - - var borders = BorderThickness; - var cornerRadius = CornerRadius; - - var outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radius - var roundedCorners = !DoubleUtil.IsZero(outerCornerRadius); - - var width = RenderSize.Width; - var height = RenderSize.Height; - - // Draw border - if (!ThicknessUtil.IsZero(borders) && (brush = BorderBrush) != null) - { - var pen = GetPen(brush, borderStyle, borders.Left, dpi.DpiScaleX, useLayoutRounding); - var penThickness = pen.Thickness; - - double x = penThickness * 0.5; - var rect = new Rect(x, x, width - penThickness, height - penThickness); - - if (roundedCorners) - { - dc.DrawRoundedRectangle(null, pen, rect, outerCornerRadius, outerCornerRadius); - } - else - { - dc.DrawRectangle(null, pen, rect); - } - } - - // Draw background in rectangle inside border. - if ((brush = Background) != null) - { - // Intialize background - Point ptTL, ptBR; - - if (useLayoutRounding) - { - ptTL = new Point(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), - UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY)); - ptBR = new Point(width - UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), - height - UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); - } - else - { - ptTL = new Point(borders.Left, borders.Top); - ptBR = new Point(width - borders.Right, height - borders.Bottom); - } - - // Do not draw background if the borders are so large that they overlap. - if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y) - { - if (roundedCorners) - { - // Determine the inner edge radius - var innerCornerRadius = Math.Max(0.0, outerCornerRadius - borders.Top * 0.5); - dc.DrawRoundedRectangle(brush, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius); - } - else - { - dc.DrawRectangle(brush, null, new Rect(ptTL, ptBR)); - } - } - } - } - - private void ComplexRender(DrawingContext dc) - { - Brush brush; - var width = RenderSize.Width; - var height = RenderSize.Height; - - //Draw border - if (!DoubleUtil.IsZero(width) && !DoubleUtil.IsZero(height) && (brush = BorderBrush) != null) - { - var useLayoutRounding = UseLayoutRounding; - var dpi = DpiUtil.GetDpi(this); - - var borders = BorderThickness; - var borderStyle = BorderStyle; - var radius = CornerRadius; - double x, y; - - // Left Line - if (!DoubleUtil.IsZero(borders.Left)) - { - if (leftPenCache == null) - { - leftPenCache = GetPen(brush, borderStyle, borders.Left, dpi.DpiScaleX, useLayoutRounding); - } - - x = leftPenCache.Thickness * 0.5; - dc.DrawLine(leftPenCache, new Point(x, radius.TopLeft), new Point(x, height - radius.BottomLeft)); - } - - // Top Line - if (!DoubleUtil.IsZero(borders.Top)) - { - if (topPenCache == null) - { - topPenCache = GetPen(brush, borderStyle, borders.Top, dpi.DpiScaleY, useLayoutRounding); - } - - y = topPenCache.Thickness * 0.5; - dc.DrawLine(topPenCache, new Point(radius.TopLeft, y), new Point(width - radius.TopRight, y)); - } - - // Right Line - if (!DoubleUtil.IsZero(borders.Right)) - { - if (rightPenCache == null) - { - rightPenCache = GetPen(brush, borderStyle, borders.Right, dpi.DpiScaleX, useLayoutRounding); - } - - x = width - rightPenCache.Thickness * 0.5; - dc.DrawLine(rightPenCache, new Point(x, radius.TopRight), new Point(x, height - radius.BottomRight)); - } - - // Bottom Line - if (!DoubleUtil.IsZero(borders.Bottom)) - { - if (bottomPenCache == null) - { - bottomPenCache = GetPen(brush, borderStyle, borders.Bottom, dpi.DpiScaleY, useLayoutRounding); - } - - y = height - bottomPenCache.Thickness * 0.5; - dc.DrawLine(bottomPenCache, new Point(radius.BottomLeft, y), new Point(width - radius.BottomRight, y)); - } - - // Draw Rounded - Pen pen; - - if (upperLeftCache != null && (pen = GetMaxPen(leftPenCache, topPenCache)) != null) - { - dc.DrawGeometry(null, pen, upperLeftCache); - } - - if (upperRightCache != null && (pen = GetMaxPen(topPenCache, rightPenCache)) != null) - { - dc.DrawGeometry(null, pen, upperRightCache); - } - - if (lowerRightCache != null && (pen = GetMaxPen(rightPenCache, bottomPenCache)) != null) - { - dc.DrawGeometry(null, pen, lowerRightCache); - } - - if (lowerLeftCache != null && (pen = GetMaxPen(bottomPenCache, leftPenCache)) != null) - { - dc.DrawGeometry(null, pen, lowerLeftCache); - } - } - - // Draw background in rectangle inside border. - if (backgroundGeometryCache != null && (brush = Background) != null) - { - dc.DrawGeometry(brush, null, backgroundGeometryCache); - } - } - - private Pen GetMaxPen(Pen pen1, Pen pen2) - { - if (pen2 == null || (pen1 != null && pen2.Thickness < pen1.Thickness)) - { - return pen1; - } - - return pen2; - } - - private static StreamGeometry GenerateRoundedGeometry(Point startPoint, Point endPoint, Size size) - { - var streamGeometry = new StreamGeometry(); - - using (StreamGeometryContext sc = streamGeometry.Open()) - { - sc.BeginFigure(startPoint, true, false); - sc.ArcTo(endPoint, size, 0, false, SweepDirection.Clockwise, true, false); - } - - streamGeometry.Freeze(); - return streamGeometry; - } - - private static Pen GetPen(Brush brush, BorderStyle borderStyle, double thickness, double dpi, bool useLayoutRounding) - { - var pen = new Pen - { - Brush = brush, - DashCap = PenLineCap.Flat, - Thickness = useLayoutRounding ? UIElementUtil.RoundLayoutValue(thickness, dpi) : thickness, - }; - - switch (borderStyle) - { - case BorderStyle.Dotted: - pen.DashStyle = new DashStyle(new double[] { 1 }, 0d); - break; - case BorderStyle.Dashed: - pen.DashStyle = new DashStyle(new double[] { 4, 2 }, 0d); - break; - default: - break; - } - - if (brush.IsFrozen) - { - pen.Freeze(); - } - - return pen; - } - - #endregion - - #region Private Structures Classes - - private struct Radii - { - #region Fields - - internal readonly Point LeftTop; - - internal readonly Point LeftBottom; - - internal readonly Point TopLeft; - - internal readonly Point TopRight; - - internal readonly Point RightTop; - - internal readonly Point RightBottom; - - internal readonly Point BottomRight; - - internal readonly Point BottomLeft; - - #endregion - - internal Radii(Rect rect, CornerRadius radius, Thickness borders, bool outer) - { - var left = borders.Left * 0.5; - var top = borders.Top * 0.5; - var right = borders.Right * 0.5; - var bottom = borders.Bottom * 0.5; - - LeftTop = new Point(0d, 0d); - LeftBottom = new Point(0d, rect.Height); - - TopLeft = new Point(0d, 0d); - TopRight = new Point(rect.Width, 0d); - - RightTop = new Point(rect.Width, 0d); - RightBottom = new Point(rect.Width, rect.Height); - - BottomRight = new Point(rect.Width, rect.Height); - BottomLeft = new Point(0d, rect.Height); - - if (outer) - { - LeftTop.X = left; - LeftBottom.X = left; - - TopLeft.Y = top; - TopRight.Y = top; - - RightTop.X -= right; - RightBottom.X -= right; - - BottomLeft.Y -= bottom; - BottomRight.Y -= bottom; - - if (!DoubleUtil.IsZero(radius.TopLeft)) - { - TopLeft.X = radius.TopLeft; // + left; - LeftTop.Y = radius.TopLeft;// + top; - } - - if (!DoubleUtil.IsZero(radius.TopRight)) - { - RightTop.Y = radius.TopRight;// + top; - TopRight.X -= radius.TopRight;// + right; - } - - if (!DoubleUtil.IsZero(radius.BottomRight)) - { - BottomRight.X -= radius.BottomRight;// + right; - RightBottom.Y -= radius.BottomRight;// + bottom; ; - } - - if (!DoubleUtil.IsZero(radius.BottomLeft)) - { - LeftBottom.Y -= radius.BottomLeft; // + bottom; - BottomLeft.X = radius.BottomLeft;// + left; - } - } else - { - TopLeft.X = Math.Max(0.0, radius.TopLeft - left); - LeftTop.Y = Math.Max(0.0, radius.TopLeft - top); - - RightTop.Y = Math.Max(0.0, radius.TopRight - top); - TopRight.X -= Math.Max(0.0, radius.TopRight - right); - - BottomRight.X -= Math.Max(0.0, radius.BottomRight - right); - RightBottom.Y -= Math.Max(0.0, radius.BottomRight - bottom); - - LeftBottom.Y -= Math.Max(0.0, radius.BottomLeft - bottom); - BottomLeft.X = Math.Max(0.0, radius.BottomLeft - left); - } - - // check keypoints for overlap and resolve by partitioning corners according to - // the percentage of each one. - - // top edge - if (TopLeft.X > TopRight.X) - { - var v = TopLeft.X / (TopLeft.X + rect.Width - TopRight.X) * rect.Width; - TopLeft.X = v; - TopRight.X = v; - } - - // right edge - if (RightTop.Y > RightBottom.Y) - { - var v = RightTop.Y / (RightTop.Y + rect.Height - RightBottom.Y) * rect.Height; - RightTop.Y = v; - RightBottom.Y = v; - } - - // bottom edge - if (BottomRight.X < BottomLeft.X) - { - var v = BottomLeft.X / (BottomLeft.X + rect.Width - BottomRight.X) * rect.Width; - BottomRight.X = v; - BottomLeft.X = v; - } - - // left edge - if (LeftBottom.Y < LeftTop.Y) - { - var v = LeftTop.Y / (LeftTop.Y + rect.Height - LeftBottom.Y) * rect.Height; - LeftBottom.Y = v; - LeftTop.Y = v; - } - - // Apply offset - var offset = new Vector(rect.TopLeft.X, rect.TopLeft.Y); - - LeftTop += offset; - LeftBottom += offset; - - TopRight += offset; - TopLeft += offset; - - RightTop += offset; - RightBottom += offset; - - BottomRight += offset; - BottomLeft += offset; - } - } - - #endregion Private Structures Classes - } -} diff --git a/AntdWpf/Controls/Button.cs b/AntdWpf/Controls/Button.cs deleted file mode 100644 index 4c65b82..0000000 --- a/AntdWpf/Controls/Button.cs +++ /dev/null @@ -1,340 +0,0 @@ -namespace AntdWpf.Controls -{ - using System; - using System.Windows; - using System.Windows.Media; - using System.Windows.Media.Animation; - using System.Windows.Shapes; - using ButtonBase = System.Windows.Controls.Button; - - /// - /// To trigger an operation. - /// - [TemplatePart(Name = PART_Border, Type = typeof(FrameworkElement))] - [TemplateVisualState(Name = "Loaded", GroupName = "LoadStates")] - [TemplateVisualState(Name = "Unloaded", GroupName = "LoadStates")] - public class Button : ButtonBase - { - #region Fields - - private const string PART_Border = "PART_Border"; - - private FrameworkElement border; - - private VisualState mouseOverState; - - private VisualState pressedState; - - private VisualState focusedState; - - #endregion - - #region Properties - - public static readonly DependencyProperty GhostProperty = - DependencyProperty.Register("Ghost", typeof(bool), typeof(Button), new PropertyMetadata(false, OnEffectBrushChanged)); - - /// - /// Gets/sets whether to make the background transparent and invert text and border colors. - /// - public bool Ghost - { - get { return (bool)GetValue(GhostProperty); } - set { SetValue(GhostProperty, value); } - } - - public static readonly DependencyProperty IconProperty = - DependencyProperty.Register("Icon", typeof(string), typeof(Button), new PropertyMetadata(null)); - - /// - /// Gets/sets the icon type of the button. - /// - public string Icon - { - get { return (string)GetValue(IconProperty); } - set { SetValue(IconProperty, value); } - } - - public static readonly DependencyProperty LoadingProperty = - DependencyProperty.Register("Loading", typeof(bool), typeof(Button), new PropertyMetadata(false, OnLoadingChanged)); - - /// - /// Gets/sets the loading state of the button. - /// - public bool Loading - { - get { return (bool)GetValue(LoadingProperty); } - set { SetValue(LoadingProperty, value); } - } - - private static void OnLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as Button).SetLoadVisualState(); - } - - private void SetLoadVisualState() - { - VisualStateManager.GoToState(this, (Loading ? "Loaded" : "Unloaded"), true); - } - - - public static readonly DependencyProperty ShapeProperty = - DependencyProperty.Register("Shape", typeof(Shapes), typeof(Button), new PropertyMetadata(Shapes.Square)); - - /// - /// Gets/sets the shape of button. - /// - public Shapes Shape - { - get { return (Shapes)GetValue(ShapeProperty); } - set { SetValue(ShapeProperty, value); } - } - - public static readonly DependencyProperty SizeProperty = - DependencyProperty.Register("Size", typeof(Sizes?), typeof(Button), new PropertyMetadata(null)); - - /// - /// Gets/sets the size of the button. - /// - public Sizes? Size - { - get { return (Sizes?)GetValue(SizeProperty); } - set { SetValue(SizeProperty, value); } - } - - public static readonly DependencyProperty TypeProperty = - DependencyProperty.Register("Type", typeof(ButtonType?), typeof(Button), new PropertyMetadata(null)); - - /// - /// Gets/sets the type of the button. - /// - public ButtonType? Type - { - get { return (ButtonType?)GetValue(TypeProperty); } - set { SetValue(TypeProperty, value); } - } - - public static readonly DependencyProperty EffectBrushProperty = DependencyProperty.Register( - "EffectBrush", - typeof(Brush), - typeof(Button), - new FrameworkPropertyMetadata( - Brushes.Transparent, - FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits, - OnEffectBrushChanged)); - - /// - /// Gets/sets the border effect brush of the button. - /// - public Brush EffectBrush - { - get { return (Brush)GetValue(EffectBrushProperty); } - set { SetValue(EffectBrushProperty, value); } - } - - private static void OnEffectBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as Button).SetVisualStateAnimation(); - } - - /// - /// Force background transparent in Ghost state. - /// - private static object OnBackgroundCoerceValue(DependencyObject d, object baseValue) - { - var button = d as Button; - - if (button.Ghost) - { - return Brushes.Transparent; - } - - return baseValue; - } - - #endregion - - #region Constructors - - static Button() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(Button), new FrameworkPropertyMetadata(typeof(Button))); - BackgroundProperty.OverrideMetadata(typeof(Button), new FrameworkPropertyMetadata { CoerceValueCallback = OnBackgroundCoerceValue }); - } - - #endregion - - #region Overrides - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - border = GetTemplateChild(PART_Border) as FrameworkElement; - mouseOverState = GetTemplateChild("MouseOver") as VisualState; - - focusedState = GetTemplateChild("Focused") as VisualState; - pressedState = GetTemplateChild("Pressed") as VisualState; - - SetVisualStateAnimation(); - SetLoadVisualState(); - } - - #endregion - - #region Private Methods - - private void SetVisualStateAnimation() - { - // No initialization or no need for me to handle. - if (border == null || mouseOverState == null && focusedState == null && pressedState == null) return; - - // Unable to extract color. - if (EffectBrush is SolidColorBrush brush) - { - var isShape = border is Shape; - Func func; - - if (!Type.HasValue || Type.Value == ButtonType.Dashed) - { - func = CreateDefaultStoryboard; - } - else if (Type.Value == ButtonType.Primary) - { - func = CreatePrimaryStoryboard; - } - else - { - // Danger - func = CreateDangerStoryboard; - } - - if (mouseOverState != null) - { - mouseOverState.Storyboard = func(this, brush.Color, 5, isShape, false, null); - } - - if (focusedState != null) - { - focusedState.Storyboard = func(this, brush.Color, 5, isShape, true, null); - } - - if (pressedState != null) - { - pressedState.Storyboard = func(this, brush.Color, 7, isShape, false, TimeSpan.FromSeconds(0)); - } - } - } - - private static Storyboard CreateDefaultStoryboard(Button button, Color color, int index, bool IsShape, bool focused, Duration? duration = null) - { - var storyboard = new Storyboard(); - var children = storyboard.Children; - - color = ColorPalette.Toning(color, index); - children.Add(CreateForegroundAnimation(button, color, duration)); - children.Add(CreateBorderAnimation(PART_Border, color, IsShape, duration)); - - return storyboard; - } - - private static Storyboard CreatePrimaryStoryboard(Button button, Color color, int index, bool IsShape, bool focused, Duration? duration = null) - { - var storyboard = new Storyboard(); - var children = storyboard.Children; - - color = ColorPalette.Toning(color, index); - - if (button.Ghost) - { - children.Add(CreateForegroundAnimation(button, color, duration)); - } else - { - children.Add(CreateBackgroundAnimation(PART_Border, color, IsShape, duration)); - } - - children.Add(CreateBorderAnimation(PART_Border, color, IsShape, duration)); - - return storyboard; - } - - private static Storyboard CreateDangerStoryboard(Button button, Color color, int index, bool IsShape, bool focused, Duration? duration = null) - { - var storyboard = new Storyboard(); - var children = storyboard.Children; - - Color foreground; - color = ColorPalette.Toning(color, index); - - if (button.Ghost) - { - foreground = color; - } else - { - Color background; - - if (focused) - { - foreground = color; - background = Colors.White; - } - else - { - foreground = Colors.White; - background = color; - } - - children.Add(CreateBackgroundAnimation(PART_Border, background, IsShape, duration)); - } - - children.Add(CreateForegroundAnimation(button, foreground, duration)); - children.Add(CreateBorderAnimation(PART_Border, color, IsShape, duration)); - - return storyboard; - } - - private static Timeline CreateForegroundAnimation(DependencyObject target, Color color, Duration? duration = null) - { - return CreateColorAnimation(target, "(Control.Foreground).(SolidColorBrush.Color)", color, duration); - } - - private static Timeline CreateBackgroundAnimation(string target, Color color, bool IsShape, Duration? duration = null) - { - return CreateColorAnimation(target, (IsShape ? "Fill" : "Background") + ".Color", color, duration); - } - - private static Timeline CreateBorderAnimation(string target, Color color, bool IsShape, Duration? duration = null) - { - return CreateColorAnimation(target, (IsShape ? "Stroke" : "BorderBrush") + ".Color", color, duration); - } - - private static Timeline CreateColorAnimation(object target, string path, Color color, Duration? duration) - { - var animation = new ColorAnimation() { To = color }; - - if (duration.HasValue) - { - animation.Duration = duration.Value; - } - - if (target is DependencyObject) - { - Storyboard.SetTarget(animation, (DependencyObject)target); - } else - { - Storyboard.SetTargetName(animation, (string)target); - } - - Storyboard.SetTargetProperty(animation, new PropertyPath(path)); - - return animation; - } - - #endregion - } - - public enum ButtonType : byte - { - Primary, Dashed, Danger - } -} diff --git a/AntdWpf/Controls/CodeBox.cs b/AntdWpf/Controls/CodeBox.cs index 5304c65..6a32cc5 100644 --- a/AntdWpf/Controls/CodeBox.cs +++ b/AntdWpf/Controls/CodeBox.cs @@ -3,7 +3,7 @@ using System.Windows.Controls; namespace AntdWpf.Controls { - public class CodeBox : ContentControl + public class CodeBox : AntdContentControl { #region Properties diff --git a/AntdWpf/Controls/ISpinable.cs b/AntdWpf/Controls/ISpinable.cs deleted file mode 100644 index 77485e2..0000000 --- a/AntdWpf/Controls/ISpinable.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace AntdWpf.Controls -{ - /// - /// Represents a spinable control. From https://github.com/charri/Font-Awesome-WPF/blob/master/src/WPF/FontAwesome.WPF/ISpinable.cs - /// - public interface ISpinable - { - bool? Spin { get; set; } - } -} diff --git a/AntdWpf/Controls/Icon.cs b/AntdWpf/Controls/Icon.cs index bc3b809..5ceddbb 100644 --- a/AntdWpf/Controls/Icon.cs +++ b/AntdWpf/Controls/Icon.cs @@ -1,499 +1,499 @@ -namespace AntdWpf.Controls -{ - using System; - using System.ComponentModel; - using System.Diagnostics; - using System.Windows; - using System.Windows.Documents; - using System.Windows.Media; + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Media; - using AntdWpf.Utils; +using AntdWpf.Contracts; +using AntdWpf.Utils; + +namespace AntdWpf.Controls; +/// +/// 头像、警告提示语义矢量图形 +/// +public class Icon : FrameworkElement, ISpinable +{ + #region Fields + + private Geometry definingGeometry; + + #endregion + + #region Document Properties /// - /// Semantic vector graphics. + /// DependencyProperty for property. /// - public class Icon : FrameworkElement, ISpinable + public static readonly DependencyProperty FontSizeProperty = + TextElement.FontSizeProperty.AddOwner(typeof(Icon)); + + /// + /// The FontSize property specifies the size of the font. + /// + [TypeConverter(typeof(FontSizeConverter))] + [Localizability(LocalizationCategory.None)] + public double FontSize { - #region Fields + get { return (double)GetValue(FontSizeProperty); } + set { SetValue(FontSizeProperty, value); } + } - private Geometry definingGeometry; - - #endregion - - #region Document Properties - - /// - /// DependencyProperty for property. - /// - public static readonly DependencyProperty FontSizeProperty = - TextElement.FontSizeProperty.AddOwner(typeof(Icon)); - - /// - /// The FontSize property specifies the size of the font. - /// - [TypeConverter(typeof(FontSizeConverter))] - [Localizability(LocalizationCategory.None)] - public double FontSize + /// + /// DependencyProperty setter for property. + /// + /// The element to which to write the attached property. + /// The property value to set + public static void SetFontSize(DependencyObject element, double value) + { + if (element == null) { - get { return (double)GetValue(FontSizeProperty); } - set { SetValue(FontSizeProperty, value); } + throw new ArgumentNullException("element"); } - /// - /// DependencyProperty setter for property. - /// - /// The element to which to write the attached property. - /// The property value to set - public static void SetFontSize(DependencyObject element, double value) + element.SetValue(FontSizeProperty, value); + } + + /// + /// DependencyProperty getter for property. + /// + /// The element from which to read the attached property. + [TypeConverter(typeof(FontSizeConverter))] + public static double GetFontSize(DependencyObject element) + { + if (element == null) { - if (element == null) + throw new ArgumentNullException("element"); + } + + return (double)element.GetValue(FontSizeProperty); + } + + /// + /// DependencyProperty for property. + /// + public static readonly DependencyProperty ForegroundProperty = + TextElement.ForegroundProperty.AddOwner(typeof(Icon)); + + /// + /// The Foreground property specifies the foreground brush of an element's text content. + /// + public Brush Foreground + { + get { return (Brush)GetValue(ForegroundProperty); } + set { SetValue(ForegroundProperty, value); } + } + + /// + /// DependencyProperty setter for property. + /// + /// The element to which to write the attached property. + /// The property value to set + public static void SetForeground(DependencyObject element, Brush value) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + element.SetValue(ForegroundProperty, value); + } + + /// + /// DependencyProperty getter for property. + /// + /// The element from which to read the attached property. + public static Brush GetForeground(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + return (Brush)element.GetValue(ForegroundProperty); + } + + public static readonly DependencyProperty BackgroundProperty = + TextElement.BackgroundProperty.AddOwner( + typeof(Icon), + new FrameworkPropertyMetadata( + Brushes.Transparent, + FrameworkPropertyMetadataOptions.AffectsRender)); + + /// + /// The Background property defines the brush used to fill the content area. + /// + public Brush Background + { + get { return (Brush)GetValue(BackgroundProperty); } + set { SetValue(BackgroundProperty, value); } + } + + #endregion + + #region Properties + + /// + /// Get the geometry that defines this icon. + /// + protected Geometry DefiningGeometry + { + get + { + if (definingGeometry == null) { - throw new ArgumentNullException("element"); - } - - element.SetValue(FontSizeProperty, value); - } - - /// - /// DependencyProperty getter for property. - /// - /// The element from which to read the attached property. - [TypeConverter(typeof(FontSizeConverter))] - public static double GetFontSize(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (double)element.GetValue(FontSizeProperty); - } - - /// - /// DependencyProperty for property. - /// - public static readonly DependencyProperty ForegroundProperty = - TextElement.ForegroundProperty.AddOwner(typeof(Icon)); - - /// - /// The Foreground property specifies the foreground brush of an element's text content. - /// - public Brush Foreground - { - get { return (Brush)GetValue(ForegroundProperty); } - set { SetValue(ForegroundProperty, value); } - } - - /// - /// DependencyProperty setter for property. - /// - /// The element to which to write the attached property. - /// The property value to set - public static void SetForeground(DependencyObject element, Brush value) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(ForegroundProperty, value); - } - - /// - /// DependencyProperty getter for property. - /// - /// The element from which to read the attached property. - public static Brush GetForeground(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (Brush)element.GetValue(ForegroundProperty); - } - - public static readonly DependencyProperty BackgroundProperty = - TextElement.BackgroundProperty.AddOwner( - typeof(Icon), - new FrameworkPropertyMetadata( - Brushes.Transparent, - FrameworkPropertyMetadataOptions.AffectsRender)); - - /// - /// The Background property defines the brush used to fill the content area. - /// - public Brush Background - { - get { return (Brush)GetValue(BackgroundProperty); } - set { SetValue(BackgroundProperty, value); } - } - - #endregion - - #region Properties - - /// - /// Get the geometry that defines this icon. - /// - protected Geometry DefiningGeometry - { - get - { - if (definingGeometry == null) + if (!string.IsNullOrEmpty(Type)) { - if (!string.IsNullOrEmpty(Type)) - { - var key = "anticon." + Type.ToLower(); + var key = "anticon." + Type.ToLower(); - // With theme suffix. - if (Theme == IconTheme.Filled) - { - key += ".fill"; - } else if (Theme == IconTheme.Colorful) - { - key += ".colorful"; - } - - definingGeometry = TryFindResource(key) as Geometry ?? Geometry.Empty; - } - else + // With theme suffix. + if (Theme == IconTheme.Filled) { - definingGeometry = Geometry.Empty; + key += ".fill"; + } else if (Theme == IconTheme.Colorful) + { + key += ".colorful"; } + + definingGeometry = TryFindResource(key) as Geometry ?? Geometry.Empty; } - - return definingGeometry; - } - } - - public static readonly DependencyProperty TypeProperty = - DependencyProperty.Register("Type", typeof(string), typeof(Icon), - new FrameworkPropertyMetadata(null, - FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnSpinChanged)); - - /// - /// Gets/sets the type of the ant design icon. - /// - public string Type - { - get { return (string)GetValue(TypeProperty); } - set { SetValue(TypeProperty, value); } - } - - public static readonly DependencyProperty ThemeProperty = - DependencyProperty.Register("Theme", typeof(IconTheme), typeof(Icon), - new FrameworkPropertyMetadata(IconTheme.Outlined, FrameworkPropertyMetadataOptions.AffectsRender)); - - - /// - /// Gets/sets the theme of the ant design icon. - /// - public IconTheme Theme - { - get { return (IconTheme)GetValue(ThemeProperty); } - set { SetValue(ThemeProperty, value); } - } - - public static readonly DependencyProperty SpinProperty = - DependencyProperty.Register("Spin", typeof(bool?), typeof(Icon), new PropertyMetadata(null, OnSpinChanged)); - - /// - /// Gets/sets whether the icon has a spin animation. - /// - public bool? Spin - { - get { return (bool?)GetValue(SpinProperty); } - set { SetValue(SpinProperty, value); } - } - - private static void OnSpinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as Icon).SetSpinAnimation(); - } - - #endregion - - #region Attached Propperties - - /// - /// Why is it not a dependency property? - /// icons are introduced by way of resources. if you define them as dependency properties, you will lose more flexibility. - /// For example, each icon needs to use different stretch parameters. - /// - public static readonly DependencyProperty ViewBoxProperty = - DependencyProperty.RegisterAttached("ViewBox", typeof(Rect), typeof(Icon), new PropertyMetadata(new Rect(0, 0, 1024, 1024)), OnViewBoxValidate); - - private static bool OnViewBoxValidate(object value) - { - var viewBox = (Rect)value; - return viewBox.IsEmpty || (viewBox.Width >= 0 && viewBox.Height >= 0); - } - - /// - /// Gets the rectangular area of the geometric stretch. - /// - [AttachedPropertyBrowsableForType(typeof(Geometry))] - public static Rect GetViewBox(DependencyObject obj) - { - return (Rect)obj.GetValue(ViewBoxProperty); - } - - /// - /// Sets the rectangular area of the geometric stretch. - /// - public static void SetViewBox(DependencyObject obj, Rect value) - { - obj.SetValue(ViewBoxProperty, value); - } - - /// - /// When you need colorful icons, you need to be able to support custom brushes. - /// - public static readonly DependencyProperty FillProperty = - DependencyProperty.RegisterAttached("Fill", typeof(Brush), typeof(Icon), new PropertyMetadata(null)); - - /// - /// Gets the brush that fill the geometry. - /// - /// - /// - [AttachedPropertyBrowsableForType(typeof(Geometry))] - public static Brush GetFill(DependencyObject obj) - { - return (Brush)obj.GetValue(FillProperty); - } - - /// - /// Sets the brush to fill the geometry. Valid when Theme is colorful. - /// - public static void SetFill(DependencyObject obj, Brush value) - { - obj.SetValue(FillProperty, value); - } - - #endregion - - #region Constructors - - static Icon() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(Icon), new FrameworkPropertyMetadata(typeof(Icon))); - } - - public Icon() - { - Loaded += (s, e) => SetSpinAnimation(); - } - - #endregion - - #region Overrides - - /// - /// Notification that a specified property has been invalidated. - /// - /// EventArgs that contains the property, metadata, old value, and new value for this change - protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) - { - if (e.NewValue != e.OldValue && (e.Property == TypeProperty || e.Property == ThemeProperty)) - { - // Reset definition geometry. - definingGeometry = null; - } - - base.OnPropertyChanged(e); - } - - /// - /// Updates DesiredSize of the icon. Called by parent UIElement during is the first pass of layout. - /// - /// Constraint size is an "upper limit" that should not exceed. - /// icon desired size. - protected override Size MeasureOverride(Size constraint) - { - return GetRenderSize(constraint, FontSize); - } - - /// - /// Compute the rendered geometry. - /// - /// - /// - protected override Size ArrangeOverride(Size finalSize) - { - return GetRenderSize(finalSize, FontSize); - } - - /// - /// Render callback. - /// - protected override void OnRender(DrawingContext dc) - { - Geometry rendered; - var geometry = DefiningGeometry; - - Debug.Assert(geometry != null); - - var foreground = Foreground; - var matrix = GetStretchMatrix(geometry, FontSize); - - // Need to use colorful render. - if (geometry is GeometryGroup) - { - Brush brush; - int index = 0; - var isSolidColor = foreground is SolidColorBrush; - var children = ((GeometryGroup)geometry).Children; - - foreach (var child in children) + else { - rendered = GetRenderedGeometry(child, matrix); + definingGeometry = Geometry.Empty; + } + } - if (rendered != Geometry.Empty) + return definingGeometry; + } + } + + public static readonly DependencyProperty TypeProperty = + DependencyProperty.Register("Type", typeof(string), typeof(Icon), + new FrameworkPropertyMetadata(null, + FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnSpinChanged)); + + /// + /// Gets/sets the type of the ant design icon. + /// + public string Type + { + get { return (string)GetValue(TypeProperty); } + set { SetValue(TypeProperty, value); } + } + + public static readonly DependencyProperty ThemeProperty = + DependencyProperty.Register("Theme", typeof(IconTheme), typeof(Icon), + new FrameworkPropertyMetadata(IconTheme.Outlined, FrameworkPropertyMetadataOptions.AffectsRender)); + + + /// + /// Gets/sets the theme of the ant design icon. + /// + public IconTheme Theme + { + get { return (IconTheme)GetValue(ThemeProperty); } + set { SetValue(ThemeProperty, value); } + } + + public static readonly DependencyProperty SpinProperty = + DependencyProperty.Register("Spin", typeof(bool?), typeof(Icon), new PropertyMetadata(null, OnSpinChanged)); + + /// + /// Gets/sets whether the icon has a spin animation. + /// + public bool? Spin + { + get { return (bool?)GetValue(SpinProperty); } + set { SetValue(SpinProperty, value); } + } + + private static void OnSpinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as Icon).SetSpinAnimation(); + } + + #endregion + + #region Attached Propperties + + /// + /// Why is it not a dependency property? + /// icons are introduced by way of resources. if you define them as dependency properties, you will lose more flexibility. + /// For example, each icon needs to use different stretch parameters. + /// + public static readonly DependencyProperty ViewBoxProperty = + DependencyProperty.RegisterAttached("ViewBox", typeof(Rect), typeof(Icon), new PropertyMetadata(new Rect(0, 0, 1024, 1024)), OnViewBoxValidate); + + private static bool OnViewBoxValidate(object value) + { + var viewBox = (Rect)value; + return viewBox.IsEmpty || (viewBox.Width >= 0 && viewBox.Height >= 0); + } + + /// + /// Gets the rectangular area of the geometric stretch. + /// + [AttachedPropertyBrowsableForType(typeof(Geometry))] + public static Rect GetViewBox(DependencyObject obj) + { + return (Rect)obj.GetValue(ViewBoxProperty); + } + + /// + /// Sets the rectangular area of the geometric stretch. + /// + public static void SetViewBox(DependencyObject obj, Rect value) + { + obj.SetValue(ViewBoxProperty, value); + } + + /// + /// When you need colorful icons, you need to be able to support custom brushes. + /// + public static readonly DependencyProperty FillProperty = + DependencyProperty.RegisterAttached("Fill", typeof(Brush), typeof(Icon), new PropertyMetadata(null)); + + /// + /// Gets the brush that fill the geometry. + /// + /// + /// + [AttachedPropertyBrowsableForType(typeof(Geometry))] + public static Brush GetFill(DependencyObject obj) + { + return (Brush)obj.GetValue(FillProperty); + } + + /// + /// Sets the brush to fill the geometry. Valid when Theme is colorful. + /// + public static void SetFill(DependencyObject obj, Brush value) + { + obj.SetValue(FillProperty, value); + } + + #endregion + + #region Constructors + + static Icon() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(Icon), new FrameworkPropertyMetadata(typeof(Icon))); + } + + public Icon() + { + Loaded += (s, e) => SetSpinAnimation(); + } + + #endregion + + #region Overrides + + /// + /// Notification that a specified property has been invalidated. + /// + /// EventArgs that contains the property, metadata, old value, and new value for this change + protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != e.OldValue && (e.Property == TypeProperty || e.Property == ThemeProperty)) + { + // Reset definition geometry. + definingGeometry = null; + } + + base.OnPropertyChanged(e); + } + + /// + /// Updates DesiredSize of the icon. Called by parent UIElement during is the first pass of layout. + /// + /// Constraint size is an "upper limit" that should not exceed. + /// icon desired size. + protected override Size MeasureOverride(Size constraint) + { + return GetRenderSize(constraint, FontSize); + } + + /// + /// Compute the rendered geometry. + /// + /// + /// + protected override Size ArrangeOverride(Size finalSize) + { + return GetRenderSize(finalSize, FontSize); + } + + /// + /// Render callback. + /// + protected override void OnRender(DrawingContext dc) + { + Geometry rendered; + var geometry = DefiningGeometry; + + Debug.Assert(geometry != null); + + var foreground = Foreground; + var matrix = GetStretchMatrix(geometry, FontSize); + + // Need to use colorful render. + if (geometry is GeometryGroup) + { + Brush brush; + int index = 0; + var isSolidColor = foreground is SolidColorBrush; + var children = ((GeometryGroup)geometry).Children; + + foreach (var child in children) + { + rendered = GetRenderedGeometry(child, matrix); + + if (rendered != Geometry.Empty) + { + brush = rendered.GetValue(FillProperty) as Brush; + + // It may need to be tinted + if (brush == null) { - brush = rendered.GetValue(FillProperty) as Brush; - - // It may need to be tinted - if (brush == null) + if (!isSolidColor || index == 0 || index == 6 || index > 9) { - if (!isSolidColor || index == 0 || index == 6 || index > 9) - { - brush = foreground; - }else - { - brush = new SolidColorBrush(ColorPalette.Toning(((SolidColorBrush)foreground).Color, index)); - } - - index++; + brush = foreground; + }else + { + brush = new SolidColorBrush(ColorPalette.Toning(((SolidColorBrush)foreground).Color, index)); } - dc.DrawGeometry(brush, null, rendered); + index++; } + + dc.DrawGeometry(brush, null, rendered); + } + } + + } else + { + rendered = GetRenderedGeometry(geometry, matrix); + + if (rendered != Geometry.Empty) + { + dc.DrawGeometry(foreground, null, rendered); + } + } + + // Without background, the mouse can penetrate geometry and cause event failure. + var background = Background; + + if (background != null) + { + dc.DrawRectangle(background, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height)); + } + } + + #endregion + + #region Private Methods + + private void SetSpinAnimation() + { + var spin = Spin ?? Type == "loading"; + + if (spin) + { + this.BeginSpin(1d); + } + else + { + this.StopSpin(); + } + } + + private Size GetRenderSize(Size availableSize, double fontSize) + { + if (IsGeometryEmpty(DefiningGeometry)) + { + return new Size(0d, 0d); + } + + return new Size(Math.Min(availableSize.Width, fontSize), Math.Min(availableSize.Height, fontSize)); + } + + private bool IsGeometryEmpty(Geometry geometry) + { + return geometry.IsEmpty() || geometry.Bounds.IsEmpty; + } + + /// + /// Get the rendered geometry. + /// + private Geometry GetRenderedGeometry(Geometry geometry, Matrix matrix) + { + var rendered = geometry.CloneCurrentValue(); + + if (ReferenceEquals(geometry, rendered)) + { + rendered = rendered.Clone(); + } + + var transform = rendered.Transform; + + if (transform == null) + { + rendered.Transform = new MatrixTransform(matrix); + } + else + { + rendered.Transform = new MatrixTransform(transform.Value * matrix); + } + + return rendered; + } + + /// + /// Get the stretch matrix of the geometry. + /// + private Matrix GetStretchMatrix(Geometry geometry, double size) + { + var matrix = Matrix.Identity; + + if (!IsGeometryEmpty(geometry)) + { + double scaleX, scaleY; + var viewBox = (Rect)geometry.GetValue(ViewBoxProperty); + + if (viewBox.IsEmpty) + { + viewBox = geometry.Bounds; + scaleX = size / viewBox.Right; + scaleY = size / viewBox.Bottom; + + if (scaleX > scaleY) + { + scaleX = scaleY; + } else + { + scaleY = scaleX; } } else { - rendered = GetRenderedGeometry(geometry, matrix); - - if (rendered != Geometry.Empty) - { - dc.DrawGeometry(foreground, null, rendered); - } + scaleX = size / viewBox.Width; + scaleY = size / viewBox.Height; + matrix.Translate(-(scaleX * viewBox.X), -(scaleY * viewBox.Y)); } - // Without background, the mouse can penetrate geometry and cause event failure. - var background = Background; - - if (background != null) - { - dc.DrawRectangle(background, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height)); - } + matrix.Scale(scaleX, scaleY); } - #endregion - - #region Private Methods - - private void SetSpinAnimation() - { - var spin = Spin ?? Type == "loading"; - - if (spin) - { - this.BeginSpin(1d); - } - else - { - this.StopSpin(); - } - } - - private Size GetRenderSize(Size availableSize, double fontSize) - { - if (IsGeometryEmpty(DefiningGeometry)) - { - return new Size(0d, 0d); - } - - return new Size(Math.Min(availableSize.Width, fontSize), Math.Min(availableSize.Height, fontSize)); - } - - private bool IsGeometryEmpty(Geometry geometry) - { - return geometry.IsEmpty() || geometry.Bounds.IsEmpty; - } - - /// - /// Get the rendered geometry. - /// - private Geometry GetRenderedGeometry(Geometry geometry, Matrix matrix) - { - var rendered = geometry.CloneCurrentValue(); - - if (ReferenceEquals(geometry, rendered)) - { - rendered = rendered.Clone(); - } - - var transform = rendered.Transform; - - if (transform == null) - { - rendered.Transform = new MatrixTransform(matrix); - } - else - { - rendered.Transform = new MatrixTransform(transform.Value * matrix); - } - - return rendered; - } - - /// - /// Get the stretch matrix of the geometry. - /// - private Matrix GetStretchMatrix(Geometry geometry, double size) - { - var matrix = Matrix.Identity; - - if (!IsGeometryEmpty(geometry)) - { - double scaleX, scaleY; - var viewBox = (Rect)geometry.GetValue(ViewBoxProperty); - - if (viewBox.IsEmpty) - { - viewBox = geometry.Bounds; - scaleX = size / viewBox.Right; - scaleY = size / viewBox.Bottom; - - if (scaleX > scaleY) - { - scaleX = scaleY; - } else - { - scaleY = scaleX; - } - - } else - { - scaleX = size / viewBox.Width; - scaleY = size / viewBox.Height; - matrix.Translate(-(scaleX * viewBox.X), -(scaleY * viewBox.Y)); - } - - matrix.Scale(scaleX, scaleY); - } - - return matrix; - } - - #endregion + return matrix; } - public enum IconTheme : byte - { - Filled, Outlined, Colorful - } + #endregion +} + +public enum IconTheme : byte +{ + Filled, Outlined, Colorful } diff --git a/AntdWpf/Controls/MaterialWindow.cs b/AntdWpf/Controls/MaterialWindow.cs new file mode 100644 index 0000000..76db111 --- /dev/null +++ b/AntdWpf/Controls/MaterialWindow.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace AntdWpf.Controls +{ + /// + /// Custom window class for a Material Design like styled window. + /// + public class MaterialWindow : Window + { + private const string MinimizeButtonName = "minimizeButton"; + private const string MaximizeRestoreButtonName = "maximizeRestoreButton"; + private const string CloseButtonName = "closeButton"; + + /// + /// The color for the border and caption area background of the window. + /// + public static readonly DependencyProperty BorderBackgroundBrushProperty = DependencyProperty.Register( + nameof(BorderBackgroundBrush), typeof(Brush), typeof(MaterialWindow), new FrameworkPropertyMetadata(null, null)); + + /// + /// The color for the border and caption area background of the window. + /// + public Brush BorderBackgroundBrush + { + get + { + return (Brush)GetValue(BorderBackgroundBrushProperty); + } + + set + { + SetValue(BorderBackgroundBrushProperty, value); + } + } + + /// + /// The forground color for the caption area of the window. + /// + public static readonly DependencyProperty BorderForegroundBrushProperty = DependencyProperty.Register( + nameof(BorderForegroundBrush), typeof(Brush), typeof(MaterialWindow), new FrameworkPropertyMetadata(null, null)); + + /// + /// The forground color for the caption area of the window. + /// + public Brush BorderForegroundBrush + { + get + { + return (Brush)GetValue(BorderForegroundBrushProperty); + } + + set + { + SetValue(BorderForegroundBrushProperty, value); + } + } + + /// + /// Lets the content of the window fade out if the window is inactive. + /// The default is true (enabled). + /// + public static readonly DependencyProperty FadeContentIfInactiveProperty = DependencyProperty.Register( + nameof(FadeContentIfInactive), typeof(bool), typeof(MaterialWindow), new FrameworkPropertyMetadata(true)); + + /// + /// Lets the content of the window fade out if the window is inactive. + /// The default is true (enabled). + /// + public bool FadeContentIfInactive + { + get + { + return (bool)GetValue(FadeContentIfInactiveProperty); + } + + set + { + SetValue(FadeContentIfInactiveProperty, value); + } + } + + /// + /// The template for the title bar. The default shows a with the title. + /// + public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register( + nameof(TitleTemplate), typeof(DataTemplate), typeof(MaterialWindow)); + + /// + /// The template for the title bar. The default shows a with the title. + /// + public DataTemplate TitleTemplate + { + get + { + return (DataTemplate)GetValue(TitleTemplateProperty); + } + + set + { + SetValue(TitleTemplateProperty, value); + } + } + private AntButton m_minimizeButton; + private AntButton m_maximizeRestoreButton; + private AntButton m_closeButton; + + static MaterialWindow() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(MaterialWindow), new FrameworkPropertyMetadata(typeof(MaterialWindow))); + } + + /// + /// Creates a new . + /// + public MaterialWindow() : base() { } + + public override void OnApplyTemplate() + { + if (m_minimizeButton != null) + { + m_minimizeButton.Click -= MinimizeButtonClickHandler; + } + + m_minimizeButton = GetTemplateChild(MinimizeButtonName) as AntButton; + + if (m_minimizeButton != null) + { + m_minimizeButton.Click += MinimizeButtonClickHandler; + } + + if (m_maximizeRestoreButton != null) + { + m_maximizeRestoreButton.Click -= MaximizeRestoreButtonClickHandler; + } + + m_maximizeRestoreButton = GetTemplateChild(MaximizeRestoreButtonName) as AntButton; + + if (m_maximizeRestoreButton != null) + { + m_maximizeRestoreButton.Click += MaximizeRestoreButtonClickHandler; + } + + if (m_closeButton != null) + { + m_closeButton.Click -= CloseButtonClickHandler; + } + + m_closeButton = GetTemplateChild(CloseButtonName) as AntButton; + + if (m_closeButton != null) + { + m_closeButton.Click += CloseButtonClickHandler; + } + + base.OnApplyTemplate(); + } + + private void CloseButtonClickHandler(object sender, RoutedEventArgs args) + { + Close(); + } + + private void MaximizeRestoreButtonClickHandler(object sender, RoutedEventArgs args) + { + WindowState = WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal; + } + + private void MinimizeButtonClickHandler(object sender, RoutedEventArgs args) + { + WindowState = WindowState.Minimized; + } + } +} diff --git a/AntdWpf/Controls/TabControl.cs b/AntdWpf/Controls/TabControl.cs index 9795fd0..4cc552e 100644 --- a/AntdWpf/Controls/TabControl.cs +++ b/AntdWpf/Controls/TabControl.cs @@ -1,9 +1,8 @@ namespace AntdWpf.Controls { using System.Windows; - using TabControlBase = System.Windows.Controls.TabControl; - public class TabControl : TabControlBase + public class TabControl : System.Windows.Controls.TabControl { #region Constructors diff --git a/AntdWpf/Controls/ThumbContentControl.cs b/AntdWpf/Controls/ThumbContentControl.cs index 629c5cc..0a73d0e 100644 --- a/AntdWpf/Controls/ThumbContentControl.cs +++ b/AntdWpf/Controls/ThumbContentControl.cs @@ -9,7 +9,7 @@ using AntdWpf.Contracts; - public class ThumbContentControl : ContentControl, IThumb + public class ThumbContentControl : AntdContentControl, IThumb { #region Events diff --git a/AntdWpf/Controls/WindowButtons.cs b/AntdWpf/Controls/WindowButtons.cs index f460703..feef361 100644 --- a/AntdWpf/Controls/WindowButtons.cs +++ b/AntdWpf/Controls/WindowButtons.cs @@ -145,9 +145,9 @@ namespace AntdWpf.Controls (d as WindowButtons).ApplyStyle(); } - private AntdWpf.Controls.Window _parentWindow; + private AntdWpf.Controls.AntdWindow _parentWindow; - public AntdWpf.Controls.Window ParentWindow + public AntdWpf.Controls.AntdWindow ParentWindow { get { return _parentWindow; } set diff --git a/AntdWpf/Controls/WindowCommands.cs b/AntdWpf/Controls/WindowCommands.cs index d19920c..cea2848 100644 --- a/AntdWpf/Controls/WindowCommands.cs +++ b/AntdWpf/Controls/WindowCommands.cs @@ -19,9 +19,9 @@ namespace AntdWpf.Controls #region Properties - private Window _parentWindow; + private AntdWindow _parentWindow; - public Window ParentWindow + public AntdWindow ParentWindow { get { return _parentWindow; } set @@ -60,7 +60,7 @@ namespace AntdWpf.Controls #endregion } - public class WindowCommandsItem : ContentControl + public class WindowCommandsItem : AntdContentControl { static WindowCommandsItem() { diff --git a/AntdWpf/Converters/CornerRadiusToDoubleConverter.cs b/AntdWpf/Converters/CornerRadiusToDoubleConverter.cs index 122d9ee..e44636b 100644 --- a/AntdWpf/Converters/CornerRadiusToDoubleConverter.cs +++ b/AntdWpf/Converters/CornerRadiusToDoubleConverter.cs @@ -9,7 +9,7 @@ public class CornerRadiusToDoubleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (!(value is CornerRadius)) + if (value is not CornerRadius) { return default(double); } diff --git a/AntdWpf/Converters/DoubleToCornerRadiusConverter.cs b/AntdWpf/Converters/DoubleToCornerRadiusConverter.cs index 0c0bec5..e3c342f 100644 --- a/AntdWpf/Converters/DoubleToCornerRadiusConverter.cs +++ b/AntdWpf/Converters/DoubleToCornerRadiusConverter.cs @@ -11,7 +11,7 @@ { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (!(value is double)) + if (value is not double) { return default(CornerRadius); } diff --git a/AntdWpf/Converters/GenericConverterExtension.cs b/AntdWpf/Converters/GenericConverterExtension.cs new file mode 100644 index 0000000..55ead27 --- /dev/null +++ b/AntdWpf/Converters/GenericConverterExtension.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Markup; + +namespace AntdWpf.Converters; + +/// +/// 构造单例的Converter的markup +/// +/// +/// 示例代码: +/// +/// ]]> +/// +/// +public class GenericConverterExtension : MarkupExtension +{ + public Type Type { get; set; } + + private static readonly Dictionary _instances = new(); + public override object ProvideValue(IServiceProvider serviceProvider) + { + if (Type == null || !typeof(IValueConverter).IsAssignableFrom(Type)|| !typeof(IMultiValueConverter).IsAssignableFrom(Type)) + throw new InvalidOperationException("类型必须是值转换器"); + + if (!_instances.TryGetValue(Type, out var instance)) + _instances[Type] = instance = Activator.CreateInstance(Type); + + return instance; + } +} + diff --git a/AntdWpf/Converters/ThicknessToDoubleConverter.cs b/AntdWpf/Converters/ThicknessToDoubleConverter.cs index af9a7e3..0863475 100644 --- a/AntdWpf/Converters/ThicknessToDoubleConverter.cs +++ b/AntdWpf/Converters/ThicknessToDoubleConverter.cs @@ -12,7 +12,7 @@ { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (!(value is Thickness)) + if (value is not Thickness) { return default(double); } diff --git a/AntdWpf/Helpers/Control.cs b/AntdWpf/Helpers/AntdControl.cs similarity index 96% rename from AntdWpf/Helpers/Control.cs rename to AntdWpf/Helpers/AntdControl.cs index 7a62bc8..5ced198 100644 --- a/AntdWpf/Helpers/Control.cs +++ b/AntdWpf/Helpers/AntdControl.cs @@ -9,14 +9,14 @@ /// /// A helper class that provides various controls. /// - public static class Control + public static class AntdControl { #region Border public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached( "CornerRadius", typeof(CornerRadius), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( default(CornerRadius), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender @@ -42,7 +42,7 @@ public static readonly DependencyProperty BorderStyleProperty = DependencyProperty.RegisterAttached( "BorderStyle", typeof(BorderStyle), - typeof(Control), + typeof(AntdControl), new PropertyMetadata(BorderStyle.Solid)); /// @@ -68,7 +68,7 @@ public static readonly DependencyProperty SizeProperty = DependencyProperty.RegisterAttached( "Size", typeof(Sizes?), - typeof(Control), + typeof(AntdControl), new PropertyMetadata(null)); /// @@ -94,7 +94,7 @@ public static readonly DependencyProperty MouseOverForegroundProperty = DependencyProperty.RegisterAttached( "MouseOverForeground", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -118,7 +118,7 @@ public static readonly DependencyProperty MouseOverBorderBrushProperty = DependencyProperty.RegisterAttached( "MouseOverBorderBrush", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -142,7 +142,7 @@ public static readonly DependencyProperty MouseOverBackgroundProperty = DependencyProperty.RegisterAttached( "MouseOverBackground", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -166,7 +166,7 @@ public static readonly DependencyProperty FocusedForegroundProperty = DependencyProperty.RegisterAttached( "FocusedForeground", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -190,7 +190,7 @@ public static readonly DependencyProperty FocusedBorderBrushProperty = DependencyProperty.RegisterAttached( "FocusedBorderBrush", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -214,7 +214,7 @@ public static readonly DependencyProperty FocusedBackgroundProperty = DependencyProperty.RegisterAttached( "FocusedBackground", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -238,7 +238,7 @@ public static readonly DependencyProperty PressedForegroundProperty = DependencyProperty.RegisterAttached( "PressedForeground", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -262,7 +262,7 @@ public static readonly DependencyProperty PressedBorderBrushProperty = DependencyProperty.RegisterAttached( "PressedBorderBrush", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); @@ -286,7 +286,7 @@ public static readonly DependencyProperty PressedBackgroundProperty = DependencyProperty.RegisterAttached( "PressedBackground", typeof(Brush), - typeof(Control), + typeof(AntdControl), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits )); diff --git a/AntdWpf/Microsoft.Windows.Shell/Standard/Verify.cs b/AntdWpf/Microsoft.Windows.Shell/Standard/Verify.cs index fa652eb..11cf368 100644 --- a/AntdWpf/Microsoft.Windows.Shell/Standard/Verify.cs +++ b/AntdWpf/Microsoft.Windows.Shell/Standard/Verify.cs @@ -1,10 +1,9 @@ using Standard; -// This file contains general utilities to aid in development. -// Classes here generally shouldn't be exposed publicly since -// they're not particular to any library functionality. -// Because the classes here are internal, it's likely this file -// might be included in multiple assemblies. -#pragma warning disable 1591, 618 +// 该文件包含一般实用程序,用于帮助开发。 +// 这里的类一般不应公开暴露,因为 +// 它们与任何库函数无关。 +// 因为这里的类是内部类,所以这个文件 +// 可能包含在多个程序集中。 namespace AntdWpf.Microsoft.Windows.Shell.Standard { using System; @@ -15,8 +14,8 @@ namespace AntdWpf.Microsoft.Windows.Shell.Standard using System.Threading; /// - /// A static class for retail validated assertions. - /// Instead of breaking into the debugger an exception is thrown. + /// 用于验证断言的静态类。 + /// 不会进入调试器,而是抛出一个异常。 /// internal static class Verify { diff --git a/AntdWpf/Microsoft.Windows.Shell/SystemCommands.cs b/AntdWpf/Microsoft.Windows.Shell/SystemCommands.cs index 79cb127..f8935e0 100644 --- a/AntdWpf/Microsoft.Windows.Shell/SystemCommands.cs +++ b/AntdWpf/Microsoft.Windows.Shell/SystemCommands.cs @@ -1,5 +1,4 @@ -#pragma warning disable 1591, 618 -namespace AntdWpf.Microsoft.Windows.Shell +namespace AntdWpf.Microsoft.Windows.Shell { using System; using System.Windows; @@ -53,6 +52,7 @@ namespace AntdWpf.Microsoft.Windows.Shell public static void MinimizeWindow(Window window) { Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.MINIMIZE); } diff --git a/AntdWpf/Styles/Alert.xaml b/AntdWpf/Styles/Alert.xaml index d560eb7..b9fa0ed 100644 --- a/AntdWpf/Styles/Alert.xaml +++ b/AntdWpf/Styles/Alert.xaml @@ -19,8 +19,8 @@ - - + + - + BorderStyle="{TemplateBinding helpers:AntdControl.BorderStyle}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}"> @@ -147,7 +147,7 @@ Style="{StaticResource Ant.AlertCloseButton}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> - + - + diff --git a/AntdWpf/Styles/Window.xaml b/AntdWpf/Styles/AntWindow.xaml similarity index 94% rename from AntdWpf/Styles/Window.xaml rename to AntdWpf/Styles/AntWindow.xaml index ddb5596..9985993 100644 --- a/AntdWpf/Styles/Window.xaml +++ b/AntdWpf/Styles/AntWindow.xaml @@ -4,7 +4,6 @@ xmlns:Shell="clr-namespace:Microsoft.Windows.Shell" xmlns:AntdShell="clr-namespace:AntdWpf.Microsoft.Windows.Shell" xmlns:helpers="clr-namespace:AntdWpf.Helpers"> - @@ -20,10 +19,11 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AntdWpf/Styles/PasswordBox.xaml b/AntdWpf/Styles/PasswordBox.xaml index 53d1888..ccaf165 100644 --- a/AntdWpf/Styles/PasswordBox.xaml +++ b/AntdWpf/Styles/PasswordBox.xaml @@ -41,18 +41,18 @@ Focusable="False" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{DynamicResource OutlineThickness}" - CornerRadius="{TemplateBinding helpers:Control.CornerRadius}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}" Margin="{Binding BorderThickness, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource ThicknessReverseConverter}}" /> - + BorderStyle="{TemplateBinding helpers:AntdControl.BorderStyle}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}"> @@ -95,7 +95,7 @@ Content="{TemplateBinding helpers:Input.Suffix}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> - + @@ -143,18 +143,18 @@ Focusable="False" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{DynamicResource OutlineThickness}" - CornerRadius="{TemplateBinding helpers:Control.CornerRadius}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}" Margin="{Binding BorderThickness, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource ThicknessReverseConverter}}" /> - + BorderStyle="{TemplateBinding helpers:AntdControl.BorderStyle}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}"> @@ -213,7 +213,7 @@ - + diff --git a/AntdWpf/Styles/ProgressBar.xaml b/AntdWpf/Styles/ProgressBar.xaml index 29a468b..f57e35f 100644 --- a/AntdWpf/Styles/ProgressBar.xaml +++ b/AntdWpf/Styles/ProgressBar.xaml @@ -145,6 +145,7 @@ + + - @@ -51,7 +51,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" - CornerRadius="{Binding Path=(helpers:Control.CornerRadius), Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" /> + CornerRadius="{Binding Path=(helpers:AntdControl.CornerRadius), Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" /> - - + + @@ -75,17 +75,17 @@ BorderThickness="0" BorderBrush="{DynamicResource PrimaryBrush}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" - CornerRadius="{TemplateBinding helpers:Control.CornerRadius}" /> + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}" /> - + BorderStyle="{TemplateBinding helpers:AntdControl.BorderStyle}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}"> @@ -119,7 +119,7 @@ VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" /> - + diff --git a/AntdWpf/Styles/TextBox.xaml b/AntdWpf/Styles/TextBox.xaml index 018edb8..6fc214d 100644 --- a/AntdWpf/Styles/TextBox.xaml +++ b/AntdWpf/Styles/TextBox.xaml @@ -20,18 +20,18 @@ Focusable="False" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{DynamicResource OutlineThickness}" - CornerRadius="{TemplateBinding helpers:Control.CornerRadius}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}" Margin="{Binding BorderThickness, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource ThicknessReverseConverter}}" /> - + BorderStyle="{TemplateBinding helpers:AntdControl.BorderStyle}" + CornerRadius="{TemplateBinding helpers:AntdControl.CornerRadius}"> @@ -76,7 +76,7 @@ Content="{TemplateBinding helpers:Input.Suffix}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> - + diff --git a/AntdWpf/Styles/ToolTip.xaml b/AntdWpf/Styles/ToolTip.xaml index 4b601d8..015ad01 100644 --- a/AntdWpf/Styles/ToolTip.xaml +++ b/AntdWpf/Styles/ToolTip.xaml @@ -13,7 +13,7 @@ - + @@ -25,7 +25,7 @@ BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" - CornerRadius="{Binding Path=(Helpers:Control.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"> + CornerRadius="{Binding Path=(helpers:AntdControl.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"> - - + + + RelativeSource={RelativeSource AncestorType={x:Type controls:AntdWindow}}}" /> @@ -32,13 +32,13 @@ diff --git a/AntdWpf/Styles/WindowButtons.xaml b/AntdWpf/Styles/WindowButtons.xaml index e38758b..4ab58b5 100644 --- a/AntdWpf/Styles/WindowButtons.xaml +++ b/AntdWpf/Styles/WindowButtons.xaml @@ -9,9 +9,9 @@ @@ -28,7 +28,7 @@