diff --git a/src/OpenSilver.ControlsKit.Controls/ExtendedCheckBox.cs b/src/OpenSilver.ControlsKit.Controls/ExtendedCheckBox.cs
new file mode 100644
index 0000000..53f15a8
--- /dev/null
+++ b/src/OpenSilver.ControlsKit.Controls/ExtendedCheckBox.cs
@@ -0,0 +1,1227 @@
+ο»Ώ/*===================================================================================
+*
+* Copyright (c) Userware (OpenSilver.net)
+*
+* This file is part of the OpenSilver.ControlsKit (https://opensilver.net), which
+* is licensed under the MIT license (https://opensource.org/licenses/MIT).
+*
+* As stated in the MIT license, "the above copyright notice and this permission
+* notice shall be included in all copies or substantial portions of the Software."
+*
+*====================================================================================*/
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Media.Effects;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+
+namespace OpenSilver.ControlsKit.Controls
+{
+ ///
+ /// Specifies the size of the checkbox control.
+ ///
+ public enum CheckBoxSize
+ {
+ ///
+ /// Small checkbox size.
+ ///
+ Small,
+ ///
+ /// Medium checkbox size.
+ ///
+ Medium,
+ ///
+ /// Large checkbox size.
+ ///
+ Large,
+ ///
+ /// Custom checkbox size.
+ ///
+ Custom
+ }
+
+ ///
+ /// Specifies the style of the check mark.
+ ///
+ public enum CheckMarkStyle
+ {
+ ///
+ /// Check mark is visible using the current CheckMarkGeometry.
+ ///
+ Show,
+ ///
+ /// No check mark displayed.
+ ///
+ None
+ }
+
+ ///
+ /// Specifies the animation style for the checkbox transition.
+ ///
+ public enum CheckBoxAnimationStyle
+ {
+ ///
+ /// Smooth linear animation.
+ ///
+ Linear,
+ ///
+ /// Ease-in-out animation.
+ ///
+ EaseInOut,
+ ///
+ /// Bounce animation.
+ ///
+ Bounce,
+ ///
+ /// No animation.
+ ///
+ None
+ }
+
+ ///
+ /// Specifies the position of the text relative to the checkbox.
+ ///
+ public enum TextPosition
+ {
+ ///
+ /// Text is positioned to the left of the checkbox.
+ ///
+ Left,
+ ///
+ /// Text is positioned above the checkbox.
+ ///
+ Top,
+ ///
+ /// Text is positioned to the right of the checkbox.
+ ///
+ Right,
+ ///
+ /// Text is positioned below the checkbox.
+ ///
+ Bottom
+ }
+
+ ///
+ /// A customizable checkbox control with smooth animations, hover effects, and flexible styling options.
+ /// Provides advanced visual capabilities including shadows, custom colors for different states, and smooth transitions.
+ ///
+ public class ExtendedCheckBox : CheckBox
+ {
+ #region Private Fields
+ private Border _checkBoxBorder;
+ private Path _checkMarkPath;
+ private Grid _contentGrid;
+ private TextBlock _textBlock;
+ private DropShadowEffect _shadowEffect;
+ private bool _isHovered;
+ private bool _templateApplied;
+ private DispatcherTimer _animationTimer;
+ private DateTime _animationStartTime;
+ private IEasingFunction _currentEasingFunction;
+ private double _animationStartOpacity;
+ private double _animationTargetOpacity;
+ private TransformGroup _checkMarkTransformGroup;
+ private ScaleTransform _checkMarkScaleTransform;
+ #endregion
+
+ #region Dependency Properties
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CheckBoxSizeProperty =
+ DependencyProperty.Register(nameof(CheckBoxSize), typeof(CheckBoxSize), typeof(ExtendedCheckBox),
+ new PropertyMetadata(CheckBoxSize.Medium, OnCheckBoxSizeChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty BoxWidthProperty =
+ DependencyProperty.Register(nameof(BoxWidth), typeof(double), typeof(ExtendedCheckBox),
+ new PropertyMetadata(20.0, OnLayoutPropertyChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty BoxHeightProperty =
+ DependencyProperty.Register(nameof(BoxHeight), typeof(double), typeof(ExtendedCheckBox),
+ new PropertyMetadata(20.0, OnLayoutPropertyChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CornerRadiusProperty =
+ DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(ExtendedCheckBox),
+ new PropertyMetadata(new CornerRadius(3), OnCornerRadiusChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CheckMarkStyleProperty =
+ DependencyProperty.Register(nameof(CheckMarkStyle), typeof(CheckMarkStyle), typeof(ExtendedCheckBox),
+ new PropertyMetadata(CheckMarkStyle.Show, OnCheckMarkStyleChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CheckMarkGeometryProperty =
+ DependencyProperty.Register(nameof(CheckMarkGeometry), typeof(Geometry), typeof(ExtendedCheckBox),
+ new PropertyMetadata(GetDefaultCheckMarkGeometry(), OnCheckMarkGeometryChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CheckMarkBrushProperty =
+ DependencyProperty.Register(nameof(CheckMarkBrush), typeof(Brush), typeof(ExtendedCheckBox),
+ new PropertyMetadata(new SolidColorBrush(Colors.White), OnCheckMarkBrushChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CheckMarkSizeProperty =
+ DependencyProperty.Register(nameof(CheckMarkSize), typeof(double), typeof(ExtendedCheckBox),
+ new PropertyMetadata(12.0, OnCheckMarkSizeChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty BoxBrushProperty =
+ DependencyProperty.Register(nameof(BoxBrush), typeof(Brush), typeof(ExtendedCheckBox),
+ new PropertyMetadata(new SolidColorBrush(Colors.White), OnBoxBrushChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CheckedBoxBrushProperty =
+ DependencyProperty.Register(nameof(CheckedBoxBrush), typeof(Brush), typeof(ExtendedCheckBox),
+ new PropertyMetadata(new SolidColorBrush(Colors.DodgerBlue), OnBoxBrushChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty HoverBoxBrushProperty =
+ DependencyProperty.Register(nameof(HoverBoxBrush), typeof(Brush), typeof(ExtendedCheckBox),
+ new PropertyMetadata(null));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty HoverCheckedBoxBrushProperty =
+ DependencyProperty.Register(nameof(HoverCheckedBoxBrush), typeof(Brush), typeof(ExtendedCheckBox),
+ new PropertyMetadata(null));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty BoxBorderBrushProperty =
+ DependencyProperty.Register(nameof(BoxBorderBrush), typeof(Brush), typeof(ExtendedCheckBox),
+ new PropertyMetadata(new SolidColorBrush(Colors.Gray), OnBoxBorderBrushChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CheckedBoxBorderBrushProperty =
+ DependencyProperty.Register(nameof(CheckedBoxBorderBrush), typeof(Brush), typeof(ExtendedCheckBox),
+ new PropertyMetadata(null, OnBoxBorderBrushChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty BoxBorderThicknessProperty =
+ DependencyProperty.Register(nameof(BoxBorderThickness), typeof(Thickness), typeof(ExtendedCheckBox),
+ new PropertyMetadata(new Thickness(1), OnBoxBorderThicknessChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty HasShadowProperty =
+ DependencyProperty.Register(nameof(HasShadow), typeof(bool), typeof(ExtendedCheckBox),
+ new PropertyMetadata(false, OnShadowChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty AnimationDurationProperty =
+ DependencyProperty.Register(nameof(AnimationDuration), typeof(TimeSpan), typeof(ExtendedCheckBox),
+ new PropertyMetadata(TimeSpan.FromMilliseconds(200)));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty AnimationStyleProperty =
+ DependencyProperty.Register(nameof(AnimationStyle), typeof(CheckBoxAnimationStyle), typeof(ExtendedCheckBox),
+ new PropertyMetadata(CheckBoxAnimationStyle.EaseInOut));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty TextProperty =
+ DependencyProperty.Register(nameof(Text), typeof(string), typeof(ExtendedCheckBox),
+ new PropertyMetadata("", OnTextChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty TextPositionProperty =
+ DependencyProperty.Register(nameof(TextPosition), typeof(TextPosition), typeof(ExtendedCheckBox),
+ new PropertyMetadata(TextPosition.Right, OnLayoutPropertyChanged));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty TextMarginProperty =
+ DependencyProperty.Register(nameof(TextMargin), typeof(Thickness), typeof(ExtendedCheckBox),
+ new PropertyMetadata(new Thickness(8, 0, 0, 0), OnLayoutPropertyChanged));
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the predefined size of the checkbox.
+ ///
+ /// The checkbox size. Default is Medium.
+ public CheckBoxSize CheckBoxSize
+ {
+ get => (CheckBoxSize)GetValue(CheckBoxSizeProperty);
+ set => SetValue(CheckBoxSizeProperty, value);
+ }
+
+ ///
+ /// Gets or sets the width of the checkbox.
+ ///
+ /// The box width in device-independent pixels. Default is 20.
+ public double BoxWidth
+ {
+ get => (double)GetValue(BoxWidthProperty);
+ set => SetValue(BoxWidthProperty, value);
+ }
+
+ ///
+ /// Gets or sets the height of the checkbox.
+ ///
+ /// The box height in device-independent pixels. Default is 20.
+ public double BoxHeight
+ {
+ get => (double)GetValue(BoxHeightProperty);
+ set => SetValue(BoxHeightProperty, value);
+ }
+
+ ///
+ /// Gets or sets the corner radius of the checkbox.
+ ///
+ /// The corner radius. Default is 3. Set to half of box size for circular appearance.
+ public CornerRadius CornerRadius
+ {
+ get => (CornerRadius)GetValue(CornerRadiusProperty);
+ set => SetValue(CornerRadiusProperty, value);
+ }
+
+ ///
+ /// Gets or sets the style of the check mark.
+ ///
+ /// The check mark style. Default is Show.
+ public CheckMarkStyle CheckMarkStyle
+ {
+ get => (CheckMarkStyle)GetValue(CheckMarkStyleProperty);
+ set => SetValue(CheckMarkStyleProperty, value);
+ }
+
+ ///
+ /// Gets or sets the geometry used for the check mark.
+ ///
+ /// The check mark geometry. Default is Material Design check mark.
+ public Geometry CheckMarkGeometry
+ {
+ get => (Geometry)GetValue(CheckMarkGeometryProperty);
+ set => SetValue(CheckMarkGeometryProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the check mark.
+ ///
+ /// The check mark brush. Default is white.
+ public Brush CheckMarkBrush
+ {
+ get => (Brush)GetValue(CheckMarkBrushProperty);
+ set => SetValue(CheckMarkBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the size of the check mark.
+ ///
+ /// The check mark size in device-independent pixels. Default is 12.
+ public double CheckMarkSize
+ {
+ get => (double)GetValue(CheckMarkSizeProperty);
+ set => SetValue(CheckMarkSizeProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the checkbox background when unchecked.
+ ///
+ /// The box brush. Default is white.
+ public Brush BoxBrush
+ {
+ get => (Brush)GetValue(BoxBrushProperty);
+ set => SetValue(BoxBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the checkbox background when checked.
+ ///
+ /// The checked box brush. Default is dodger blue.
+ public Brush CheckedBoxBrush
+ {
+ get => (Brush)GetValue(CheckedBoxBrushProperty);
+ set => SetValue(CheckedBoxBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the checkbox when hovered and unchecked.
+ ///
+ /// The hover box brush. If null, a calculated lighter color is used.
+ public Brush HoverBoxBrush
+ {
+ get => (Brush)GetValue(HoverBoxBrushProperty);
+ set => SetValue(HoverBoxBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the checkbox when hovered and checked.
+ ///
+ /// The hover checked box brush. If null, a calculated lighter color is used.
+ public Brush HoverCheckedBoxBrush
+ {
+ get => (Brush)GetValue(HoverCheckedBoxBrushProperty);
+ set => SetValue(HoverCheckedBoxBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the border brush of the checkbox when unchecked.
+ ///
+ /// The box border brush. Default is gray.
+ public Brush BoxBorderBrush
+ {
+ get => (Brush)GetValue(BoxBorderBrushProperty);
+ set => SetValue(BoxBorderBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the border brush of the checkbox when checked.
+ ///
+ /// The checked box border brush. If null, uses the same as CheckedBoxBrush.
+ public Brush CheckedBoxBorderBrush
+ {
+ get => (Brush)GetValue(CheckedBoxBorderBrushProperty);
+ set => SetValue(CheckedBoxBorderBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the border thickness of the checkbox.
+ ///
+ /// The box border thickness. Default is 1.
+ public Thickness BoxBorderThickness
+ {
+ get => (Thickness)GetValue(BoxBorderThicknessProperty);
+ set => SetValue(BoxBorderThicknessProperty, value);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the checkbox has a drop shadow effect.
+ ///
+ /// true if the checkbox has a shadow; otherwise, false. Default is false.
+ public bool HasShadow
+ {
+ get => (bool)GetValue(HasShadowProperty);
+ set => SetValue(HasShadowProperty, value);
+ }
+
+ ///
+ /// Gets or sets the duration of the check animation.
+ ///
+ /// The animation duration. Default is 200 milliseconds.
+ public TimeSpan AnimationDuration
+ {
+ get => (TimeSpan)GetValue(AnimationDurationProperty);
+ set => SetValue(AnimationDurationProperty, value);
+ }
+
+ ///
+ /// Gets or sets the animation style for the check transition.
+ ///
+ /// The animation style. Default is EaseInOut.
+ public CheckBoxAnimationStyle AnimationStyle
+ {
+ get => (CheckBoxAnimationStyle)GetValue(AnimationStyleProperty);
+ set => SetValue(AnimationStyleProperty, value);
+ }
+
+ ///
+ /// Gets or sets the text content of the checkbox.
+ ///
+ /// The text content. Takes precedence over the Content property for text display.
+ public string Text
+ {
+ get => (string)GetValue(TextProperty);
+ set => SetValue(TextProperty, value);
+ }
+
+ ///
+ /// Gets or sets the position of the text relative to the checkbox.
+ ///
+ /// The text position. Default is Right.
+ public TextPosition TextPosition
+ {
+ get => (TextPosition)GetValue(TextPositionProperty);
+ set => SetValue(TextPositionProperty, value);
+ }
+
+ ///
+ /// Gets or sets the margin around the text.
+ ///
+ /// The text margin. Default is 8,0,0,0 (8px right margin).
+ public Thickness TextMargin
+ {
+ get => (Thickness)GetValue(TextMarginProperty);
+ set => SetValue(TextMarginProperty, value);
+ }
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Static constructor to override metadata for IsChecked property.
+ ///
+ static ExtendedCheckBox()
+ {
+ // Override IsChecked property to handle programmatic changes
+ IsCheckedProperty.OverrideMetadata(typeof(ExtendedCheckBox),
+ new FrameworkPropertyMetadata(OnIsCheckedChanged));
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ExtendedCheckBox()
+ {
+ DefaultStyleKey = typeof(ExtendedCheckBox);
+ Loaded += ExtendedCheckBox_Loaded;
+ Cursor = Cursors.Hand;
+ FontSize = 13;
+ SetupEventHandlers();
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ ///
+ /// Sets up event handlers for checkbox interactions.
+ ///
+ private void SetupEventHandlers()
+ {
+ MouseEnter += OnMouseEnter;
+ MouseLeave += OnMouseLeave;
+ }
+
+ ///
+ /// Handles the Loaded event to create the checkbox template if not already applied.
+ ///
+ /// The event sender.
+ /// The event arguments.
+ private void ExtendedCheckBox_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (!_templateApplied)
+ {
+ CreateTemplate();
+ }
+ }
+
+ ///
+ /// Creates the visual template for the checkbox programmatically.
+ ///
+ private void CreateTemplate()
+ {
+ ApplySizePreset();
+
+ var initialBackground = IsChecked == true ? CheckedBoxBrush : BoxBrush;
+ var initialBorderBrush = IsChecked == true
+ ? (CheckedBoxBorderBrush ?? CheckedBoxBrush)
+ : BoxBorderBrush;
+
+ _checkBoxBorder = new Border
+ {
+ Width = BoxWidth,
+ Height = BoxHeight,
+ CornerRadius = CornerRadius,
+ Background = initialBackground,
+ BorderBrush = initialBorderBrush,
+ BorderThickness = BoxBorderThickness,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Center
+ };
+
+ _checkMarkScaleTransform = new ScaleTransform { ScaleX = 0, ScaleY = 0 };
+ _checkMarkTransformGroup = new TransformGroup();
+ _checkMarkTransformGroup.Children.Add(_checkMarkScaleTransform);
+
+ _checkMarkPath = new Path
+ {
+ Data = CheckMarkGeometry,
+ Fill = CheckMarkBrush,
+ Stretch = Stretch.Uniform,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Center,
+ RenderTransform = _checkMarkTransformGroup,
+ RenderTransformOrigin = new Point(0.5, 0.5),
+ Opacity = 0
+ };
+
+ var checkMarkViewBox = new Viewbox
+ {
+ Width = CheckMarkSize,
+ Height = CheckMarkSize,
+ Stretch = Stretch.Uniform,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Center,
+ Child = _checkMarkPath
+ };
+
+ var boxGrid = new Grid
+ {
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Center
+ };
+ boxGrid.Children.Add(checkMarkViewBox);
+ _checkBoxBorder.Child = boxGrid;
+
+ _textBlock = new TextBlock
+ {
+ Text = !string.IsNullOrEmpty(Text) ? Text : (Content?.ToString() ?? ""),
+ Foreground = Foreground ?? new SolidColorBrush(Colors.Black),
+ FontFamily = FontFamily,
+ FontSize = FontSize,
+ FontWeight = FontWeight,
+ Margin = TextMargin,
+ VerticalAlignment = VerticalAlignment.Center
+ };
+
+ _shadowEffect = new DropShadowEffect
+ {
+ BlurRadius = 6,
+ Direction = 270,
+ ShadowDepth = 2,
+ Opacity = 0.25,
+ Color = Colors.Black
+ };
+
+ _contentGrid = new Grid();
+ SetupLayout();
+
+ Content = _contentGrid;
+
+ UpdateCheckMarkVisibility(false);
+ UpdateShadow();
+ _templateApplied = true;
+ }
+
+
+
+ ///
+ /// Gets the default check mark geometry.
+ ///
+ /// The default check mark path geometry.
+ private static Geometry GetDefaultCheckMarkGeometry()
+ {
+ // Material Design check mark
+ return Geometry.Parse("M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z");
+ }
+
+ ///
+ /// Applies predefined size settings based on CheckBoxSize property.
+ ///
+ private void ApplySizePreset()
+ {
+ switch (CheckBoxSize)
+ {
+ case CheckBoxSize.Small:
+ SetValue(BoxWidthProperty, 16.0);
+ SetValue(BoxHeightProperty, 16.0);
+ SetValue(CheckMarkSizeProperty, 10.0);
+ break;
+ case CheckBoxSize.Medium:
+ SetValue(BoxWidthProperty, 20.0);
+ SetValue(BoxHeightProperty, 20.0);
+ SetValue(CheckMarkSizeProperty, 12.0);
+ break;
+ case CheckBoxSize.Large:
+ SetValue(BoxWidthProperty, 24.0);
+ SetValue(BoxHeightProperty, 24.0);
+ SetValue(CheckMarkSizeProperty, 16.0);
+ break;
+ case CheckBoxSize.Custom:
+ // Keep current values
+ break;
+ }
+ }
+
+ ///
+ /// Sets up the layout of the checkbox and text based on TextPosition.
+ ///
+ private void SetupLayout()
+ {
+ if (_contentGrid == null) return;
+
+ // Clear previous layout
+ _contentGrid.Children.Clear();
+ _contentGrid.RowDefinitions.Clear();
+ _contentGrid.ColumnDefinitions.Clear();
+
+ bool hasText = !string.IsNullOrEmpty(Text) || (Content != null && !string.IsNullOrEmpty(Content.ToString()));
+
+ if (!hasText)
+ {
+ // Only checkbox
+ _contentGrid.Children.Add(_checkBoxBorder);
+ }
+ else
+ {
+ // Checkbox with text
+ switch (TextPosition)
+ {
+ case TextPosition.Left:
+ SetupHorizontalLayout(textFirst: true);
+ break;
+ case TextPosition.Right:
+ SetupHorizontalLayout(textFirst: false);
+ break;
+ case TextPosition.Top:
+ SetupVerticalLayout(textFirst: true);
+ break;
+ case TextPosition.Bottom:
+ SetupVerticalLayout(textFirst: false);
+ break;
+ }
+
+ _contentGrid.Children.Add(_checkBoxBorder);
+ _contentGrid.Children.Add(_textBlock);
+ }
+ }
+
+ ///
+ /// Sets up horizontal layout (Left/Right text positions).
+ ///
+ /// Whether the text should be placed first.
+ private void SetupHorizontalLayout(bool textFirst)
+ {
+ _contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
+ _contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
+
+ if (textFirst)
+ {
+ Grid.SetColumn(_textBlock, 0);
+ Grid.SetColumn(_checkBoxBorder, 1);
+ _textBlock.Margin = new Thickness(TextMargin.Left, TextMargin.Top, TextMargin.Right, TextMargin.Bottom);
+ _checkBoxBorder.Margin = new Thickness(8, 0, 0, 0);
+ }
+ else
+ {
+ Grid.SetColumn(_checkBoxBorder, 0);
+ Grid.SetColumn(_textBlock, 1);
+ _checkBoxBorder.Margin = new Thickness(0);
+ _textBlock.Margin = TextMargin;
+ }
+ }
+
+ ///
+ /// Sets up vertical layout (Top/Bottom text positions).
+ ///
+ /// Whether the text should be placed first.
+ private void SetupVerticalLayout(bool textFirst)
+ {
+ _contentGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
+ _contentGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
+
+ if (textFirst)
+ {
+ Grid.SetRow(_textBlock, 0);
+ Grid.SetRow(_checkBoxBorder, 1);
+ _textBlock.Margin = new Thickness(TextMargin.Left, TextMargin.Top, TextMargin.Right, TextMargin.Bottom);
+ _checkBoxBorder.Margin = new Thickness(0, 8, 0, 0);
+ }
+ else
+ {
+ Grid.SetRow(_checkBoxBorder, 0);
+ Grid.SetRow(_textBlock, 1);
+ _checkBoxBorder.Margin = new Thickness(0);
+ _textBlock.Margin = TextMargin;
+ }
+
+ _textBlock.HorizontalAlignment = HorizontalAlignment.Center;
+ _checkBoxBorder.HorizontalAlignment = HorizontalAlignment.Center;
+ }
+
+ ///
+ /// Updates the check mark geometry based on current settings.
+ ///
+ private void UpdateCheckMarkGeometry()
+ {
+ if (_checkMarkPath == null) return;
+
+ // Simple logic: Show uses CheckMarkGeometry, None hides it
+ Geometry geometry = CheckMarkStyle == CheckMarkStyle.Show ? CheckMarkGeometry : null;
+
+ _checkMarkPath.Data = geometry;
+ _checkMarkPath.Visibility = geometry != null ? Visibility.Visible : Visibility.Collapsed;
+ }
+
+ ///
+ /// Updates the visibility and animation of the check mark.
+ ///
+ /// Whether to animate the transition.
+ private void UpdateCheckMarkVisibility(bool animate)
+ {
+ if (_checkMarkPath == null) return;
+
+ bool shouldShow = IsChecked == true && CheckMarkStyle == CheckMarkStyle.Show;
+
+ if (animate && AnimationStyle != CheckBoxAnimationStyle.None)
+ {
+ AnimateCheckMark(shouldShow);
+ }
+ else
+ {
+ _checkMarkScaleTransform.ScaleX = shouldShow ? 1 : 0;
+ _checkMarkScaleTransform.ScaleY = shouldShow ? 1 : 0;
+ _checkMarkPath.Opacity = shouldShow ? 1 : 0;
+ }
+ }
+
+ ///
+ /// Animates the check mark appearance/disappearance.
+ ///
+ /// Whether to show or hide the check mark.
+ private void AnimateCheckMark(bool show)
+ {
+ // Stop any existing animation
+ if (_animationTimer != null)
+ {
+ _animationTimer.Stop();
+ _animationTimer = null;
+ }
+
+ if (AnimationStyle == CheckBoxAnimationStyle.None)
+ {
+ _checkMarkScaleTransform.ScaleX = show ? 1 : 0;
+ _checkMarkScaleTransform.ScaleY = show ? 1 : 0;
+ _checkMarkPath.Opacity = show ? 1 : 0;
+ return;
+ }
+
+ // Setup animation parameters
+ _animationStartOpacity = _checkMarkPath.Opacity;
+ _animationTargetOpacity = show ? 1 : 0;
+ _animationStartTime = DateTime.Now;
+
+ // Set easing function
+ switch (AnimationStyle)
+ {
+ case CheckBoxAnimationStyle.EaseInOut:
+ _currentEasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseInOut };
+ break;
+ case CheckBoxAnimationStyle.Bounce:
+ _currentEasingFunction = new BounceEase { EasingMode = EasingMode.EaseOut, Bounces = 2, Bounciness = 2 };
+ break;
+ case CheckBoxAnimationStyle.Linear:
+ default:
+ _currentEasingFunction = null;
+ break;
+ }
+
+ // Create and start timer
+ _animationTimer = new DispatcherTimer();
+ _animationTimer.Interval = TimeSpan.FromMilliseconds(16); // ~60fps
+ _animationTimer.Tick += OnCheckMarkAnimationTick;
+ _animationTimer.Start();
+ }
+
+ ///
+ /// Handles animation timer tick for check mark animation.
+ ///
+ /// The event sender.
+ /// The event arguments.
+ private void OnCheckMarkAnimationTick(object sender, EventArgs e)
+ {
+ if (_animationTimer == null) return;
+
+ var elapsed = DateTime.Now - _animationStartTime;
+ var progress = Math.Min(1.0, elapsed.TotalMilliseconds / AnimationDuration.TotalMilliseconds);
+
+ // Apply easing function if available
+ var easedProgress = progress;
+ if (_currentEasingFunction != null)
+ {
+ easedProgress = _currentEasingFunction.Ease(progress);
+ }
+
+ // Update check mark scale and opacity
+ _checkMarkScaleTransform.ScaleX = easedProgress * (_animationTargetOpacity > 0 ? 1 : 0) +
+ (1 - easedProgress) * (_animationTargetOpacity > 0 ? 0 : 1);
+ _checkMarkScaleTransform.ScaleY = _checkMarkScaleTransform.ScaleX;
+
+ var opacityDistance = _animationTargetOpacity - _animationStartOpacity;
+ _checkMarkPath.Opacity = _animationStartOpacity + (opacityDistance * easedProgress);
+
+ // Check if animation is complete
+ if (progress >= 1.0)
+ {
+ _animationTimer.Stop();
+ _animationTimer = null;
+
+ // Ensure final values are set
+ _checkMarkScaleTransform.ScaleX = _animationTargetOpacity > 0 ? 1 : 0;
+ _checkMarkScaleTransform.ScaleY = _animationTargetOpacity > 0 ? 1 : 0;
+ _checkMarkPath.Opacity = _animationTargetOpacity;
+ }
+ }
+
+ ///
+ /// Updates the shadow effect based on the HasShadow property.
+ ///
+ private void UpdateShadow()
+ {
+ if (_checkBoxBorder == null) return;
+ _checkBoxBorder.Effect = HasShadow ? _shadowEffect : null;
+ }
+
+ ///
+ /// Updates the visual state of the checkbox.
+ ///
+ private void UpdateVisualState()
+ {
+ if (_checkBoxBorder == null) return;
+
+ // Update background color
+ Brush backgroundBrush;
+ Brush borderBrush;
+
+ if (_isHovered)
+ {
+ backgroundBrush = IsChecked == true
+ ? (HoverCheckedBoxBrush ?? GetCalculatedHoverColor(CheckedBoxBrush))
+ : (HoverBoxBrush ?? GetCalculatedHoverColor(BoxBrush));
+ }
+ else
+ {
+ backgroundBrush = IsChecked == true ? CheckedBoxBrush : BoxBrush;
+ }
+
+ borderBrush = IsChecked == true
+ ? (CheckedBoxBorderBrush ?? CheckedBoxBrush)
+ : BoxBorderBrush;
+
+ _checkBoxBorder.Background = backgroundBrush;
+ _checkBoxBorder.BorderBrush = borderBrush;
+ }
+
+ ///
+ /// Calculates a lighter color variant for hover states.
+ ///
+ /// The original brush.
+ /// A brush with a lighter color, or the original brush if not a solid color.
+ private Brush GetCalculatedHoverColor(Brush originalBrush)
+ {
+ if (originalBrush is SolidColorBrush solidBrush)
+ {
+ var color = solidBrush.Color;
+ return new SolidColorBrush(Color.FromArgb(
+ color.A,
+ (byte)Math.Min(255, color.R + 20),
+ (byte)Math.Min(255, color.G + 20),
+ (byte)Math.Min(255, color.B + 20)
+ ));
+ }
+ return originalBrush;
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ ///
+ /// Handles the mouse enter event to trigger hover state.
+ ///
+ /// The event sender.
+ /// The mouse event arguments.
+ private void OnMouseEnter(object sender, MouseEventArgs e)
+ {
+ if (IsEnabled)
+ {
+ _isHovered = true;
+ UpdateVisualState();
+ }
+ }
+
+ ///
+ /// Handles the mouse leave event to return to normal state.
+ ///
+ /// The event sender.
+ /// The mouse event arguments.
+ private void OnMouseLeave(object sender, MouseEventArgs e)
+ {
+ if (IsEnabled)
+ {
+ _isHovered = false;
+ UpdateVisualState();
+ }
+ }
+
+ #endregion
+
+ #region Property Change Handlers
+
+ ///
+ /// Handles changes to the IsChecked property (including programmatic changes).
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox)
+ {
+ if (checkBox._templateApplied)
+ {
+ checkBox.UpdateCheckMarkVisibility(true);
+ checkBox.UpdateVisualState();
+ }
+ // If template is not applied yet, the CreateTemplate() method will handle the initial state
+ }
+ }
+
+ ///
+ /// Handles changes to the CheckBoxSize property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnCheckBoxSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox)
+ {
+ checkBox.ApplySizePreset();
+ if (checkBox._templateApplied)
+ {
+ checkBox.UpdateLayout();
+ }
+ }
+ }
+
+ ///
+ /// Handles changes to layout-affecting properties.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnLayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox && checkBox._templateApplied)
+ {
+ checkBox.UpdateLayout();
+ }
+ }
+
+ ///
+ /// Updates layout when properties change.
+ ///
+ private void UpdateLayout()
+ {
+ if (_checkBoxBorder == null) return;
+
+ _checkBoxBorder.Width = BoxWidth;
+ _checkBoxBorder.Height = BoxHeight;
+ _checkBoxBorder.CornerRadius = CornerRadius;
+
+ if (_checkMarkPath != null)
+ {
+ if (_checkMarkPath.Parent is Viewbox vb)
+ {
+ vb.Width = CheckMarkSize;
+ vb.Height = CheckMarkSize;
+ }
+ _checkMarkPath.Stretch = Stretch.Uniform;
+ UpdateCheckMarkGeometry();
+ }
+
+ if (_textBlock != null)
+ {
+ _textBlock.Text = !string.IsNullOrEmpty(Text) ? Text : (Content?.ToString() ?? "");
+ }
+
+ SetupLayout();
+ UpdateShadow();
+ }
+
+
+ ///
+ /// Handles changes to the CornerRadius property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnCornerRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox && checkBox._checkBoxBorder != null)
+ {
+ checkBox._checkBoxBorder.CornerRadius = (CornerRadius)e.NewValue;
+ }
+ }
+
+ ///
+ /// Handles changes to the CheckMarkStyle property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnCheckMarkStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox)
+ {
+ checkBox.UpdateCheckMarkGeometry();
+ checkBox.UpdateCheckMarkVisibility(false);
+ }
+ }
+
+ ///
+ /// Handles changes to the CheckMarkGeometry property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnCheckMarkGeometryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox && checkBox._checkMarkPath != null)
+ {
+ // Directly update the Path.Data when geometry changes
+ checkBox._checkMarkPath.Data = (Geometry)e.NewValue;
+ checkBox.UpdateCheckMarkGeometry();
+ }
+ }
+
+ ///
+ /// Handles changes to the CheckMarkBrush property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnCheckMarkBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox && checkBox._checkMarkPath != null)
+ {
+ checkBox._checkMarkPath.Fill = (Brush)e.NewValue;
+ }
+ }
+
+ ///
+ /// Handles changes to the CheckMarkSize property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnCheckMarkSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox && checkBox._checkMarkPath != null)
+ {
+ var size = (double)e.NewValue;
+ checkBox._checkMarkPath.Width = size;
+ checkBox._checkMarkPath.Height = size;
+ }
+ }
+
+ ///
+ /// Handles changes to box brush properties.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnBoxBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox)
+ {
+ checkBox.UpdateVisualState();
+ }
+ }
+
+ ///
+ /// Handles changes to box border brush properties.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnBoxBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox)
+ {
+ checkBox.UpdateVisualState();
+ }
+ }
+
+ ///
+ /// Handles changes to the BoxBorderThickness property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnBoxBorderThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox && checkBox._checkBoxBorder != null)
+ {
+ checkBox._checkBoxBorder.BorderThickness = (Thickness)e.NewValue;
+ }
+ }
+
+ ///
+ /// Handles changes to the HasShadow property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnShadowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox)
+ {
+ checkBox.UpdateShadow();
+ }
+ }
+
+ ///
+ /// Handles changes to the Text property.
+ ///
+ /// The dependency object.
+ /// The dependency property changed event arguments.
+ private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is ExtendedCheckBox checkBox && checkBox._templateApplied)
+ {
+ checkBox.UpdateLayout();
+ }
+ }
+
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// Called when the content property changes.
+ ///
+ /// The old content.
+ /// The new content.
+ protected override void OnContentChanged(object oldContent, object newContent)
+ {
+ // Don't call base to prevent default content handling
+ // We handle content ourselves in the template
+
+ if (_templateApplied)
+ {
+ UpdateLayout();
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/OpenSilver.ControlsKit.Controls/ExtendedSlider.cs b/src/OpenSilver.ControlsKit.Controls/ExtendedSlider.cs
new file mode 100644
index 0000000..fd95588
--- /dev/null
+++ b/src/OpenSilver.ControlsKit.Controls/ExtendedSlider.cs
@@ -0,0 +1,744 @@
+ο»Ώ/*===================================================================================
+*
+* Copyright (c) Userware (OpenSilver.net)
+*
+* This file is part of the OpenSilver.ControlsKit (https://opensilver.net), which
+* is licensed under the MIT license (https://opensource.org/licenses/MIT).
+*
+* As stated in the MIT license, "the above copyright notice and this permission
+* notice shall be included in all copies or substantial portions of the Software."
+*
+*====================================================================================*/
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Media.Effects;
+
+namespace OpenSilver.ControlsKit.Controls
+{
+ ///
+ /// Specifies the size of the slider control.
+ ///
+ public enum SliderSize
+ {
+ ///
+ /// Small slider size.
+ ///
+ Small,
+ ///
+ /// Medium slider size.
+ ///
+ Medium,
+ ///
+ /// Large slider size.
+ ///
+ Large,
+ ///
+ /// Custom slider size.
+ ///
+ Custom
+ }
+
+ ///
+ /// A customizable slider control with smooth animations, hover effects, and flexible styling options.
+ /// Provides advanced visual capabilities including shadows, custom colors for different states, and smooth transitions.
+ ///
+ public class ExtendedSlider : ContentControl
+ {
+ #region Events
+
+ ///
+ /// Occurs when the Value property changes.
+ ///
+ public event RoutedPropertyChangedEventHandler ValueChanged;
+
+ #endregion
+
+ #region Dependency Properties
+
+ ///
+ /// Identifies the Value dependency property.
+ ///
+ public static readonly DependencyProperty ValueProperty =
+ DependencyProperty.Register(nameof(Value), typeof(double), typeof(ExtendedSlider),
+ new PropertyMetadata(0.0, OnValueChanged, CoerceValue));
+
+ ///
+ /// Identifies the Minimum dependency property.
+ ///
+ public static readonly DependencyProperty MinimumProperty =
+ DependencyProperty.Register(nameof(Minimum), typeof(double), typeof(ExtendedSlider),
+ new PropertyMetadata(0.0, OnRangeChanged));
+
+ ///
+ /// Identifies the Maximum dependency property.
+ ///
+ public static readonly DependencyProperty MaximumProperty =
+ DependencyProperty.Register(nameof(Maximum), typeof(double), typeof(ExtendedSlider),
+ new PropertyMetadata(100.0, OnRangeChanged));
+
+ ///
+ /// Identifies the SliderSize dependency property.
+ ///
+ public static readonly DependencyProperty SliderSizeProperty =
+ DependencyProperty.Register(nameof(SliderSize), typeof(SliderSize), typeof(ExtendedSlider),
+ new PropertyMetadata(SliderSize.Medium, OnSliderSizeChanged));
+
+ ///
+ /// Identifies the TrackWidth dependency property.
+ ///
+ public static readonly DependencyProperty TrackWidthProperty =
+ DependencyProperty.Register(nameof(TrackWidth), typeof(double), typeof(ExtendedSlider),
+ new PropertyMetadata(200.0, OnLayoutChanged));
+
+ ///
+ /// Identifies the TrackHeight dependency property.
+ ///
+ public static readonly DependencyProperty TrackHeightProperty =
+ DependencyProperty.Register(nameof(TrackHeight), typeof(double), typeof(ExtendedSlider),
+ new PropertyMetadata(6.0, OnLayoutChanged));
+
+ ///
+ /// Identifies the ThumbSize dependency property.
+ ///
+ public static readonly DependencyProperty ThumbSizeProperty =
+ DependencyProperty.Register(nameof(ThumbSize), typeof(double), typeof(ExtendedSlider),
+ new PropertyMetadata(20.0, OnLayoutChanged));
+
+ ///
+ /// Identifies the CornerRadius dependency property.
+ ///
+ public static readonly DependencyProperty CornerRadiusProperty =
+ DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(ExtendedSlider),
+ new PropertyMetadata(new CornerRadius(3), OnStyleChanged));
+
+ ///
+ /// Identifies the TrackBrush dependency property.
+ ///
+ public static readonly DependencyProperty TrackBrushProperty =
+ DependencyProperty.Register(nameof(TrackBrush), typeof(Brush), typeof(ExtendedSlider),
+ new PropertyMetadata(new SolidColorBrush(Colors.LightGray), OnStyleChanged));
+
+ ///
+ /// Identifies the TrackBorderBrush dependency property.
+ ///
+ public static readonly DependencyProperty TrackBorderBrushProperty =
+ DependencyProperty.Register(nameof(TrackBorderBrush), typeof(Brush), typeof(ExtendedSlider),
+ new PropertyMetadata(null, OnStyleChanged));
+
+ ///
+ /// Identifies the TrackBorderThickness dependency property.
+ ///
+ public static readonly DependencyProperty TrackBorderThicknessProperty =
+ DependencyProperty.Register(nameof(TrackBorderThickness), typeof(Thickness), typeof(ExtendedSlider),
+ new PropertyMetadata(new Thickness(0), OnStyleChanged));
+
+ ///
+ /// Identifies the FillBrush dependency property.
+ ///
+ public static readonly DependencyProperty FillBrushProperty =
+ DependencyProperty.Register(nameof(FillBrush), typeof(Brush), typeof(ExtendedSlider),
+ new PropertyMetadata(new SolidColorBrush(Colors.DodgerBlue), OnStyleChanged));
+
+ ///
+ /// Identifies the ThumbBrush dependency property.
+ ///
+ public static readonly DependencyProperty ThumbBrushProperty =
+ DependencyProperty.Register(nameof(ThumbBrush), typeof(Brush), typeof(ExtendedSlider),
+ new PropertyMetadata(new SolidColorBrush(Colors.White), OnStyleChanged));
+
+ ///
+ /// Identifies the ThumbBorderBrush dependency property.
+ ///
+ public static readonly DependencyProperty ThumbBorderBrushProperty =
+ DependencyProperty.Register(nameof(ThumbBorderBrush), typeof(Brush), typeof(ExtendedSlider),
+ new PropertyMetadata(new SolidColorBrush(Colors.Gray), OnStyleChanged));
+
+ ///
+ /// Identifies the ThumbBorderThickness dependency property.
+ ///
+ public static readonly DependencyProperty ThumbBorderThicknessProperty =
+ DependencyProperty.Register(nameof(ThumbBorderThickness), typeof(Thickness), typeof(ExtendedSlider),
+ new PropertyMetadata(new Thickness(1), OnStyleChanged));
+
+ ///
+ /// Identifies the HasShadow dependency property.
+ ///
+ public static readonly DependencyProperty HasShadowProperty =
+ DependencyProperty.Register(nameof(HasShadow), typeof(bool), typeof(ExtendedSlider),
+ new PropertyMetadata(true, OnStyleChanged));
+
+ ///
+ /// Identifies the IsAnimated dependency property.
+ ///
+ public static readonly DependencyProperty IsAnimatedProperty =
+ DependencyProperty.Register(nameof(IsAnimated), typeof(bool), typeof(ExtendedSlider),
+ new PropertyMetadata(true));
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the current value of the slider.
+ ///
+ public double Value
+ {
+ get => (double)GetValue(ValueProperty);
+ set => SetValue(ValueProperty, value);
+ }
+
+ ///
+ /// Gets or sets the minimum value of the slider.
+ ///
+ public double Minimum
+ {
+ get => (double)GetValue(MinimumProperty);
+ set => SetValue(MinimumProperty, value);
+ }
+
+ ///
+ /// Gets or sets the maximum value of the slider.
+ ///
+ public double Maximum
+ {
+ get => (double)GetValue(MaximumProperty);
+ set => SetValue(MaximumProperty, value);
+ }
+
+ ///
+ /// Gets or sets the predefined size of the slider.
+ ///
+ public SliderSize SliderSize
+ {
+ get => (SliderSize)GetValue(SliderSizeProperty);
+ set => SetValue(SliderSizeProperty, value);
+ }
+
+ ///
+ /// Gets or sets the width of the track.
+ ///
+ public double TrackWidth
+ {
+ get => (double)GetValue(TrackWidthProperty);
+ set => SetValue(TrackWidthProperty, value);
+ }
+
+ ///
+ /// Gets or sets the height of the track.
+ ///
+ public double TrackHeight
+ {
+ get => (double)GetValue(TrackHeightProperty);
+ set => SetValue(TrackHeightProperty, value);
+ }
+
+ ///
+ /// Gets or sets the size of the thumb.
+ ///
+ public double ThumbSize
+ {
+ get => (double)GetValue(ThumbSizeProperty);
+ set => SetValue(ThumbSizeProperty, value);
+ }
+
+ ///
+ /// Gets or sets the corner radius of the slider track.
+ ///
+ public CornerRadius CornerRadius
+ {
+ get => (CornerRadius)GetValue(CornerRadiusProperty);
+ set => SetValue(CornerRadiusProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the track background.
+ ///
+ public Brush TrackBrush
+ {
+ get => (Brush)GetValue(TrackBrushProperty);
+ set => SetValue(TrackBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the border brush of the track.
+ ///
+ public Brush TrackBorderBrush
+ {
+ get => (Brush)GetValue(TrackBorderBrushProperty);
+ set => SetValue(TrackBorderBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the border thickness of the track.
+ ///
+ public Thickness TrackBorderThickness
+ {
+ get => (Thickness)GetValue(TrackBorderThicknessProperty);
+ set => SetValue(TrackBorderThicknessProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the filled portion of the track.
+ ///
+ public Brush FillBrush
+ {
+ get => (Brush)GetValue(FillBrushProperty);
+ set => SetValue(FillBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the brush used for the thumb.
+ ///
+ public Brush ThumbBrush
+ {
+ get => (Brush)GetValue(ThumbBrushProperty);
+ set => SetValue(ThumbBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the border brush of the thumb.
+ ///
+ public Brush ThumbBorderBrush
+ {
+ get => (Brush)GetValue(ThumbBorderBrushProperty);
+ set => SetValue(ThumbBorderBrushProperty, value);
+ }
+
+ ///
+ /// Gets or sets the border thickness of the thumb.
+ ///
+ public Thickness ThumbBorderThickness
+ {
+ get => (Thickness)GetValue(ThumbBorderThicknessProperty);
+ set => SetValue(ThumbBorderThicknessProperty, value);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the slider has a drop shadow effect.
+ ///
+ public bool HasShadow
+ {
+ get => (bool)GetValue(HasShadowProperty);
+ set => SetValue(HasShadowProperty, value);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether value changes are animated.
+ ///
+ public bool IsAnimated
+ {
+ get => (bool)GetValue(IsAnimatedProperty);
+ set => SetValue(IsAnimatedProperty, value);
+ }
+
+ #endregion
+
+ #region Private Fields
+
+ private Canvas _rootCanvas;
+ private Border _trackBorder;
+ private Border _fillBorder;
+ private Border _thumbBorder;
+ private bool _isDragging;
+ private bool _isHovered;
+ private Point _lastMousePosition;
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Initializes a new instance of the ExtendedSlider class.
+ ///
+ public ExtendedSlider()
+ {
+ InitializeComponent();
+ Loaded += OnLoaded;
+ }
+
+ #endregion
+
+ #region Initialization
+
+ private void InitializeComponent()
+ {
+ _rootCanvas = new Canvas
+ {
+ Background = new SolidColorBrush(Colors.Transparent)
+ };
+
+ _trackBorder = new Border
+ {
+ Background = TrackBrush,
+ BorderBrush = TrackBorderBrush,
+ BorderThickness = TrackBorderThickness,
+ CornerRadius = CornerRadius
+ };
+
+ _fillBorder = new Border
+ {
+ Background = FillBrush,
+ CornerRadius = CornerRadius
+ };
+
+ _thumbBorder = new Border
+ {
+ Background = ThumbBrush,
+ BorderBrush = ThumbBorderBrush,
+ BorderThickness = ThumbBorderThickness,
+ CornerRadius = new CornerRadius(10),
+ Cursor = Cursors.Hand
+ };
+
+ _rootCanvas.Children.Add(_trackBorder);
+ _rootCanvas.Children.Add(_fillBorder);
+ _rootCanvas.Children.Add(_thumbBorder);
+
+ Content = _rootCanvas;
+
+ SetupEventHandlers();
+ }
+
+ private void SetupEventHandlers()
+ {
+ _rootCanvas.MouseLeftButtonDown += OnCanvasMouseDown;
+ _rootCanvas.MouseMove += OnCanvasMouseMove;
+ _rootCanvas.MouseLeftButtonUp += OnCanvasMouseUp;
+
+ _thumbBorder.MouseLeftButtonDown += OnThumbMouseDown;
+ _thumbBorder.MouseEnter += OnThumbMouseEnter;
+ _thumbBorder.MouseLeave += OnThumbMouseLeave;
+
+ KeyDown += OnKeyDown;
+ Focusable = true;
+ }
+
+ private void OnLoaded(object sender, RoutedEventArgs e)
+ {
+ ApplySizePreset();
+ UpdateLayout();
+ UpdateVisualElements();
+ UpdateValueDisplay();
+ }
+
+ #endregion
+
+ #region Layout and Visual Updates
+
+ private void ApplySizePreset()
+ {
+ switch (SliderSize)
+ {
+ case SliderSize.Small:
+ TrackWidth = 150;
+ TrackHeight = 4;
+ ThumbSize = 16;
+ break;
+ case SliderSize.Medium:
+ TrackWidth = 200;
+ TrackHeight = 6;
+ ThumbSize = 20;
+ break;
+ case SliderSize.Large:
+ TrackWidth = 250;
+ TrackHeight = 8;
+ ThumbSize = 24;
+ break;
+ case SliderSize.Custom:
+ break;
+ }
+ }
+
+ private void UpdateLayout()
+ {
+ if (_rootCanvas == null) return;
+
+ var canvasHeight = Math.Max(TrackHeight, ThumbSize) + 4;
+ _rootCanvas.Width = TrackWidth;
+ _rootCanvas.Height = canvasHeight;
+
+ _trackBorder.Width = TrackWidth;
+ _trackBorder.Height = TrackHeight;
+ Canvas.SetLeft(_trackBorder, 0);
+ Canvas.SetTop(_trackBorder, (canvasHeight - TrackHeight) / 2);
+
+ UpdateValueDisplay();
+
+ _thumbBorder.Width = ThumbSize;
+ _thumbBorder.Height = ThumbSize;
+ _thumbBorder.CornerRadius = new CornerRadius(ThumbSize / 2);
+
+ UpdateShadowEffect();
+ }
+
+ private void UpdateValueDisplay()
+ {
+ if (_fillBorder == null || _thumbBorder == null) return;
+
+ var range = Maximum - Minimum;
+ if (range <= 0) return;
+
+ var normalizedValue = Math.Max(0, Math.Min(1, (Value - Minimum) / range));
+ var canvasHeight = _rootCanvas.Height;
+
+ var fillWidth = normalizedValue * TrackWidth;
+ _fillBorder.Width = fillWidth;
+ _fillBorder.Height = TrackHeight;
+ Canvas.SetLeft(_fillBorder, 0);
+ Canvas.SetTop(_fillBorder, (canvasHeight - TrackHeight) / 2);
+
+ var thumbPosition = normalizedValue * (TrackWidth - ThumbSize);
+
+ if (IsAnimated && !_isDragging)
+ {
+ AnimateThumbToPosition(thumbPosition);
+ }
+ else
+ {
+ Canvas.SetLeft(_thumbBorder, thumbPosition);
+ }
+
+ Canvas.SetTop(_thumbBorder, (canvasHeight - ThumbSize) / 2);
+ }
+
+ private void AnimateThumbToPosition(double targetPosition)
+ {
+ var currentPosition = Canvas.GetLeft(_thumbBorder);
+
+ if (double.IsNaN(currentPosition))
+ {
+ currentPosition = 0;
+ }
+
+ var animation = new DoubleAnimation
+ {
+ From = currentPosition,
+ To = targetPosition,
+ Duration = TimeSpan.FromMilliseconds(150),
+ EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut }
+ };
+
+ var storyboard = new Storyboard();
+ storyboard.Children.Add(animation);
+ Storyboard.SetTarget(animation, _thumbBorder);
+ Storyboard.SetTargetProperty(animation, new PropertyPath("(Canvas.Left)"));
+ storyboard.Begin();
+ }
+
+ private void UpdateVisualElements()
+ {
+ if (_trackBorder == null) return;
+
+ _trackBorder.Background = TrackBrush;
+ _trackBorder.BorderBrush = TrackBorderBrush;
+ _trackBorder.BorderThickness = TrackBorderThickness;
+ _trackBorder.CornerRadius = CornerRadius;
+
+ _fillBorder.Background = FillBrush;
+ _fillBorder.CornerRadius = CornerRadius;
+
+ _thumbBorder.Background = ThumbBrush;
+ _thumbBorder.BorderBrush = ThumbBorderBrush;
+ _thumbBorder.BorderThickness = ThumbBorderThickness;
+
+ ApplyHoverEffect();
+ }
+
+ private void ApplyHoverEffect()
+ {
+ if (_thumbBorder == null) return;
+
+ if (_isHovered)
+ {
+ var scaleTransform = new ScaleTransform { ScaleX = 1.1, ScaleY = 1.1 };
+ _thumbBorder.RenderTransform = scaleTransform;
+ _thumbBorder.RenderTransformOrigin = new Point(0.5, 0.5);
+ }
+ else
+ {
+ _thumbBorder.RenderTransform = null;
+ }
+ }
+
+ private void UpdateShadowEffect()
+ {
+ if (_thumbBorder == null) return;
+
+ if (HasShadow)
+ {
+ _thumbBorder.Effect = new DropShadowEffect
+ {
+ BlurRadius = 6,
+ Direction = 270,
+ ShadowDepth = 2,
+ Opacity = 0.25,
+ Color = Colors.Black
+ };
+ }
+ else
+ {
+ _thumbBorder.Effect = null;
+ }
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ private void OnCanvasMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (!IsEnabled) return;
+
+ var position = e.GetPosition(_rootCanvas);
+ UpdateValueFromPosition(position.X);
+
+ _isDragging = true;
+ _rootCanvas.CaptureMouse();
+ Focus();
+
+ e.Handled = true;
+ }
+
+ private void OnCanvasMouseMove(object sender, MouseEventArgs e)
+ {
+ if (!IsEnabled || !_isDragging) return;
+
+ var position = e.GetPosition(_rootCanvas);
+ UpdateValueFromPosition(position.X);
+
+ e.Handled = true;
+ }
+
+ private void OnCanvasMouseUp(object sender, MouseButtonEventArgs e)
+ {
+ if (_isDragging)
+ {
+ _isDragging = false;
+ _rootCanvas.ReleaseMouseCapture();
+ e.Handled = true;
+ }
+ }
+
+ private void OnThumbMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (!IsEnabled) return;
+
+ _isDragging = true;
+ _rootCanvas.CaptureMouse();
+ Focus();
+
+ e.Handled = true;
+ }
+
+ private void OnThumbMouseEnter(object sender, MouseEventArgs e)
+ {
+ _isHovered = true;
+ ApplyHoverEffect();
+ }
+
+ private void OnThumbMouseLeave(object sender, MouseEventArgs e)
+ {
+ _isHovered = false;
+ ApplyHoverEffect();
+ }
+
+ private void OnKeyDown(object sender, KeyEventArgs e)
+ {
+ if (!IsEnabled) return;
+
+ var step = (Maximum - Minimum) / 100;
+ var newValue = Value;
+
+ switch (e.Key)
+ {
+ case Key.Left:
+ case Key.Down:
+ newValue = Math.Max(Minimum, Value - step);
+ break;
+ case Key.Right:
+ case Key.Up:
+ newValue = Math.Min(Maximum, Value + step);
+ break;
+ case Key.Home:
+ newValue = Minimum;
+ break;
+ case Key.End:
+ newValue = Maximum;
+ break;
+ case Key.PageDown:
+ newValue = Math.Max(Minimum, Value - step * 10);
+ break;
+ case Key.PageUp:
+ newValue = Math.Min(Maximum, Value + step * 10);
+ break;
+ default:
+ return;
+ }
+
+ Value = newValue;
+ e.Handled = true;
+ }
+
+ private void UpdateValueFromPosition(double mouseX)
+ {
+ var normalizedPosition = Math.Max(0, Math.Min(1, mouseX / TrackWidth));
+ var newValue = Minimum + normalizedPosition * (Maximum - Minimum);
+ Value = newValue;
+ }
+
+ #endregion
+
+ #region Property Change Handlers
+
+ private static object CoerceValue(DependencyObject d, object value)
+ {
+ var slider = (ExtendedSlider)d;
+ var doubleValue = (double)value;
+ return Math.Max(slider.Minimum, Math.Min(slider.Maximum, doubleValue));
+ }
+
+ private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var slider = (ExtendedSlider)d;
+
+ slider.ValueChanged?.Invoke(slider, new RoutedPropertyChangedEventArgs(
+ (double)e.OldValue, (double)e.NewValue));
+
+ slider.UpdateValueDisplay();
+ }
+
+ private static void OnRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var slider = (ExtendedSlider)d;
+
+ slider.CoerceValue(ValueProperty);
+ slider.UpdateValueDisplay();
+ }
+
+ private static void OnSliderSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var slider = (ExtendedSlider)d;
+ slider.ApplySizePreset();
+ slider.UpdateLayout();
+ }
+
+ private static void OnLayoutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var slider = (ExtendedSlider)d;
+ slider.UpdateLayout();
+ }
+
+ private static void OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var slider = (ExtendedSlider)d;
+ slider.UpdateVisualElements();
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/TestApp/TestApp/Pages/TestExtendedCheckBox.xaml b/src/TestApp/TestApp/Pages/TestExtendedCheckBox.xaml
new file mode 100644
index 0000000..6ed0c39
--- /dev/null
+++ b/src/TestApp/TestApp/Pages/TestExtendedCheckBox.xaml
@@ -0,0 +1,540 @@
+ο»Ώ
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/TestApp/TestApp/Pages/TestExtendedCheckBox.xaml.cs b/src/TestApp/TestApp/Pages/TestExtendedCheckBox.xaml.cs
new file mode 100644
index 0000000..8278b96
--- /dev/null
+++ b/src/TestApp/TestApp/Pages/TestExtendedCheckBox.xaml.cs
@@ -0,0 +1,27 @@
+ο»Ώusing System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Navigation;
+
+namespace TestApp.Pages
+{
+ public partial class TestExtendedCheckBox : Page
+ {
+ public TestExtendedCheckBox()
+ {
+ this.InitializeComponent();
+ }
+
+ // Executes when the user navigates to this page.
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ }
+ }
+}
diff --git a/src/TestApp/TestApp/Pages/TestExtendedSlider.xaml b/src/TestApp/TestApp/Pages/TestExtendedSlider.xaml
new file mode 100644
index 0000000..e837166
--- /dev/null
+++ b/src/TestApp/TestApp/Pages/TestExtendedSlider.xaml
@@ -0,0 +1,617 @@
+ο»Ώ
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/TestApp/TestApp/Pages/TestExtendedSlider.xaml.cs b/src/TestApp/TestApp/Pages/TestExtendedSlider.xaml.cs
new file mode 100644
index 0000000..0a59ff1
--- /dev/null
+++ b/src/TestApp/TestApp/Pages/TestExtendedSlider.xaml.cs
@@ -0,0 +1,27 @@
+ο»Ώusing System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Navigation;
+
+namespace TestApp.Pages
+{
+ public partial class TestExtendedSlider : Page
+ {
+ public TestExtendedSlider()
+ {
+ this.InitializeComponent();
+ }
+
+ // Executes when the user navigates to this page.
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ }
+ }
+}
diff --git a/src/TestApp/TestApp/Registry/TestRegistry.cs b/src/TestApp/TestApp/Registry/TestRegistry.cs
index c5694d9..b4c67bd 100644
--- a/src/TestApp/TestApp/Registry/TestRegistry.cs
+++ b/src/TestApp/TestApp/Registry/TestRegistry.cs
@@ -17,6 +17,8 @@ static TestRegistry()
new TreeItem("FlexPanel", "FlexPanel"),
new TreeItem("ExtendedButton", "TestExtendedButtonControl"),
new TreeItem("ExtendedSwitch", "TestExtendedSwitch"),
+ new TreeItem("ExtendedSlider", "TestExtendedSlider"),
+ new TreeItem("ExtendedCheckBox", "TestExtendedCheckBox"),
};
}
}
diff --git a/src/TestApp/TestApp/TestApp.csproj b/src/TestApp/TestApp/TestApp.csproj
index 53f1c9e..02cc35d 100644
--- a/src/TestApp/TestApp/TestApp.csproj
+++ b/src/TestApp/TestApp/TestApp.csproj
@@ -32,6 +32,12 @@
MSBuild:Compile
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
MSBuild:Compile
@@ -48,6 +54,8 @@
+
+