(nameof(RightDrawerExpandThresholdWidth));
+
+ ///
+ /// Internal use!
+ /// This property is used to binding the margin of inner content.
+ ///
+ public Thickness ContentMargin
+ {
+ get => GetValue(ContentMarginProperty);
+ set => SetValue(ContentMarginProperty, value);
+ }
+
+ ///
+ /// Gets or sets the content to display.
+ ///
+ [DependsOn(nameof(LeftDrawerContentTemplate))]
+ public object LeftDrawerContent
+ {
+ get => GetValue(LeftDrawerContentProperty);
+ set => SetValue(LeftDrawerContentProperty, value);
+ }
+
+ ///
+ /// Gets or sets the data template used to display the content of the control.
+ ///
+ public IDataTemplate LeftDrawerContentTemplate
+ {
+ get => GetValue(LeftDrawerContentTemplateProperty);
+ set => SetValue(LeftDrawerContentTemplateProperty, value);
+ }
+
+ public bool LeftDrawerOpened
+ {
+ get => GetValue(LeftDrawerOpenedProperty);
+ set => SetValue(LeftDrawerOpenedProperty, value);
+ }
+
+ public double LeftDrawerWidth
+ {
+ get => GetValue(LeftDrawerWidthProperty);
+ set => SetValue(LeftDrawerWidthProperty, value);
+ }
+
+ ///
+ /// Get or sets the width threshold of the NavigationDrawer for expand left drawer automatically. Most used on desktop application.
+ /// For more information, please visit material.io - Standard navigation drawer, Permanently visible page.
+ /// Use it on desktop application is recommended!!
+ ///
+ public double? LeftDrawerExpandThresholdWidth
+ {
+ get => GetValue(LeftDrawerExpandThresholdWidthProperty);
+ set => SetValue(LeftDrawerExpandThresholdWidthProperty, value);
+ }
+
+ ///
+ /// Gets or sets the content to display.
+ ///
+ [DependsOn(nameof(RightDrawerContentTemplate))]
+ public object RightDrawerContent
+ {
+ get => GetValue(RightDrawerContentProperty);
+ set => SetValue(RightDrawerContentProperty, value);
+ }
+
+ ///
+ /// Gets or sets the data template used to display the content of the control.
+ ///
+ public IDataTemplate RightDrawerContentTemplate
+ {
+ get => GetValue(RightDrawerContentTemplateProperty);
+ set => SetValue(RightDrawerContentTemplateProperty, value);
+ }
+
+ public bool RightDrawerOpened
+ {
+ get => GetValue(RightDrawerOpenedProperty);
+ set => SetValue(RightDrawerOpenedProperty, value);
+ }
+
+ public double RightDrawerWidth
+ {
+ get => GetValue(RightDrawerWidthProperty);
+ set => SetValue(RightDrawerWidthProperty, value);
+ }
+
+ ///
+ /// Get or sets the width threshold of the NavigationDrawer for expand right drawer automatically. Most used on desktop application.
+ /// For more information, please visit material.io - Standard navigation drawer, Permanently visible page.
+ /// This feature is not recommended if your application is Left-to-Right language orientated. Reference: material.io.
+ ///
+ public double? RightDrawerExpandThresholdWidth
+ {
+ get => GetValue(RightDrawerExpandThresholdWidthProperty);
+ set => SetValue(RightDrawerExpandThresholdWidthProperty, value);
+ }
+
+ ///
+ /// Closes the left or right drawer, it wont be closed if it is permanent visible.
+ ///
+ /// set it to false for close the right drawer, otherwise it closes the left drawer.
+ public void OptionalCloseDrawer(bool isLeftDrawer = true)
+ {
+ switch (isLeftDrawer)
+ {
+ case true:
+ OptionalCloseLeftDrawer();
+ break;
+ case false:
+ OptionalCloseRightDrawer();
+ break;
+ }
+ }
+
+ ///
+ /// Close the left drawer, it wont be closed if it is permanent visible.
+ ///
+ public void OptionalCloseLeftDrawer()
+ {
+ if (_isLeftDrawerDesktopExpanded)
+ return;
+
+ LeftDrawerOpened = false;
+ }
+
+ ///
+ /// Close the right drawer, it wont be closed if it is permanent visible.
+ ///
+ public void OptionalCloseRightDrawer()
+ {
+ if (_isRightDrawerDesktopExpanded)
+ return;
+
+ RightDrawerOpened = false;
+ }
+
+ ///
+ /// Switch visibility of the left drawer.
+ ///
+ public void SwitchLeftDrawerOpened()
+ {
+ LeftDrawerOpened = !LeftDrawerOpened;
+ }
+
+ ///
+ /// Switch visibility of the right drawer.
+ ///
+ public void SwitchRightDrawerOpened()
+ {
+ RightDrawerOpened = !RightDrawerOpened;
+ }
+
+ private bool _isLeftDrawerDesktopExpanded;
+ private bool _isRightDrawerDesktopExpanded;
+
+ static NavigationDrawer()
+ {
+ BoundsProperty.Changed.AddClassHandler(OnDrawerResized);
+
+ LeftDrawerWidthProperty.Changed.AddClassHandler(OnDrawerWidthChanged);
+ RightDrawerWidthProperty.Changed.AddClassHandler(OnDrawerWidthChanged);
+
+ LeftDrawerOpenedProperty.Changed.AddClassHandler(OnDrawerOpenedChanged);
+ RightDrawerOpenedProperty.Changed.AddClassHandler(OnDrawerOpenedChanged);
+
+ LeftDrawerExpandThresholdWidthProperty.Changed.AddClassHandler(
+ OnDrawerExpandThresholdWidthChanged);
+ RightDrawerExpandThresholdWidthProperty.Changed.AddClassHandler(
+ OnDrawerExpandThresholdWidthChanged);
+ }
+
+ private static void OnDrawerResized(NavigationDrawer drawer, AvaloniaPropertyChangedEventArgs args)
+ {
+ drawer.UpdateDesktopExpand(drawer.Bounds.Width);
+ drawer.UpdateContentMargin();
+ }
+
+ private static void OnDrawerWidthChanged(NavigationDrawer drawer, AvaloniaPropertyChangedEventArgs args)
+ {
+ if (drawer.Classes.Contains(":closed"))
+ return;
+
+ drawer.UpdateContentMargin();
+ }
+
+ private static void OnDrawerExpandThresholdWidthChanged(
+ NavigationDrawer drawer, AvaloniaPropertyChangedEventArgs args)
+ {
+ drawer.UpdateDesktopExpand(drawer.Bounds.Width);
+ }
+
+ private static void OnDrawerOpenedChanged(NavigationDrawer drawer,
+ AvaloniaPropertyChangedEventArgs args)
+ {
+ drawer.UpdatePseudoClasses();
+ drawer.UpdateContentMargin();
+ }
+
+ // ReSharper disable once InconsistentNaming
+ private Border? PART_Scrim;
+
+ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
+ {
+ if (e.NameScope.Find("PART_Scrim") is Border border)
+ {
+ PART_Scrim = border;
+
+ PART_Scrim.PointerPressed += PART_Scrim_Pressed;
+ }
+
+ base.OnApplyTemplate(e);
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ if (PART_Scrim != null)
+ PART_Scrim.PointerPressed += PART_Scrim_Pressed;
+
+ base.OnAttachedToVisualTree(e);
+ }
+
+ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ if (PART_Scrim != null)
+ PART_Scrim.PointerPressed -= PART_Scrim_Pressed;
+
+ base.OnDetachedFromVisualTree(e);
+ }
+
+ private void UpdateDesktopExpand(double w)
+ {
+ if (LeftDrawerExpandThresholdWidth.HasValue)
+ {
+ var status = w > LeftDrawerExpandThresholdWidth.Value;
+ _isLeftDrawerDesktopExpanded = status;
+
+ if (Classes.Contains(":left-expand") != status)
+ {
+ LeftDrawerOpened = status;
+ }
+
+ PseudoClasses.Set(":left-expand", status);
+ }
+ else
+ {
+ _isLeftDrawerDesktopExpanded = false;
+ }
+
+ if (RightDrawerExpandThresholdWidth.HasValue)
+ {
+ var status = w > RightDrawerExpandThresholdWidth.Value;
+ _isRightDrawerDesktopExpanded = status;
+
+ if (Classes.Contains(":right-expand") != status)
+ {
+ RightDrawerOpened = status;
+ }
+
+ PseudoClasses.Set(":right-expand", status);
+ }
+ else
+ {
+ _isRightDrawerDesktopExpanded = false;
+ }
+ }
+
+ private void UpdateContentMargin()
+ {
+ var left = _isLeftDrawerDesktopExpanded && LeftDrawerOpened ? LeftDrawerWidth : 0;
+ var right = _isRightDrawerDesktopExpanded && RightDrawerOpened ? RightDrawerWidth : 0;
+
+ ContentMargin = new Thickness(left, 0, right, 0);
+ }
+
+ private void PART_Scrim_Pressed(object sender, RoutedEventArgs e)
+ {
+ LeftDrawerOpened = false;
+ RightDrawerOpened = false;
+ }
+
+ private void UpdatePseudoClasses()
+ {
+ var open = LeftDrawerOpened || RightDrawerOpened;
+ PseudoClasses.Set(":open", open);
+ PseudoClasses.Set(":closed", !open);
+ PseudoClasses.Set(":left", LeftDrawerOpened);
+ PseudoClasses.Set(":right", RightDrawerOpened);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Material.Styles/Controls/Rotator.cs b/Material.Styles/Controls/Rotator.cs
index 637bc3f..ba1be02 100644
--- a/Material.Styles/Controls/Rotator.cs
+++ b/Material.Styles/Controls/Rotator.cs
@@ -27,18 +27,19 @@ namespace Material.Styles.Controls
set
{
if (value < 0)
- throw new ArgumentOutOfRangeException(nameof(value), "MinimumSpeed should not less than zero. You can set it as zero, if you wish your rotator keep running.");
+ throw new ArgumentOutOfRangeException(nameof(value),
+ "MinimumSpeed should not less than zero. You can set it as zero, if you wish your rotator keep running.");
_minimumSpeed = value;
}
}
-
+
private bool _running;
private double _speed = 0.4;
private double _rotateDegree;
-
+
private readonly RenderLoopClock _loopTask;
private TimeSpan _prev;
@@ -64,7 +65,7 @@ namespace Material.Styles.Controls
{
if (rotator.IsEffectivelyVisible == false || rotator.IsEffectivelyEnabled == false)
return;
-
+
rotator._speed = v;
OnSpeedChanged(rotator, v);
});
@@ -74,7 +75,7 @@ namespace Material.Styles.Controls
{
if (IsEffectivelyVisible == false || IsEffectivelyEnabled == false)
return;
-
+
var delta = renderTime - _prev;
_rotateDegree += _speed * delta.TotalMilliseconds;
_prev = renderTime;
@@ -84,7 +85,7 @@ namespace Material.Styles.Controls
RenderTransform = new RotateTransform(_rotateDegree);
}
-
+
private static void OnSpeedChanged(Rotator rotator, double d)
{
// We should stop rotator if speed is lower than minimum speed
diff --git a/Material.Styles/Controls/Scroller.cs b/Material.Styles/Controls/Scroller.cs
index 232bc85..c5d3c94 100644
--- a/Material.Styles/Controls/Scroller.cs
+++ b/Material.Styles/Controls/Scroller.cs
@@ -188,7 +188,7 @@ namespace Material.Styles.Controls
RoutedEvent.Register(
nameof(ScrollChanged),
RoutingStrategies.Bubble);
-
+
///
/// Defines the property.
///
@@ -196,7 +196,7 @@ namespace Material.Styles.Controls
AvaloniaProperty.RegisterDirect(
nameof(CanScrollLeft),
o => o.CanScrollLeft);
-
+
///
/// Defines the property.
///
@@ -227,8 +227,10 @@ namespace Material.Styles.Controls
///