enhance: add TransitionMode prop fro Growl.
This commit is contained in:
1 parent
bb3c075398
commit
8405e7f2b1
2 files changed
+281
-100
No files matched your search
@@ -5,6 +5,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
@@ -26,6 +27,7 @@ public class Growl : Control
|
||||
private const string ElementGridMain = "PART_GridMain";
|
||||
private const string ElementButtonClose = "PART_ButtonClose";
|
||||
private const int MinWaitTime = 2;
|
||||
private const int TranslateTransformIndex = 3;
|
||||
|
||||
private static GrowlWindow GrowlWindow;
|
||||
|
||||
@@ -45,6 +47,12 @@ public class Growl : Control
|
||||
"ShowMode", typeof(GrowlShowMode), typeof(Growl),
|
||||
new FrameworkPropertyMetadata(default(GrowlShowMode), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static readonly DependencyProperty TransitionModeProperty = DependencyProperty.Register(
|
||||
nameof(TransitionMode), typeof(TransitionMode), typeof(Growl), new PropertyMetadata(default(TransitionMode)));
|
||||
|
||||
public static readonly DependencyProperty TransitionStoryboardProperty = DependencyProperty.Register(
|
||||
nameof(TransitionStoryboard), typeof(Storyboard), typeof(Growl), new PropertyMetadata(default(Storyboard)));
|
||||
|
||||
public static readonly DependencyProperty ShowDateTimeProperty = DependencyProperty.Register(
|
||||
nameof(ShowDateTime), typeof(bool), typeof(Growl), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
@@ -97,6 +105,18 @@ public class Growl : Control
|
||||
/// </summary>
|
||||
public static Panel GrowlPanel { get; set; }
|
||||
|
||||
public TransitionMode TransitionMode
|
||||
{
|
||||
get => (TransitionMode) GetValue(TransitionModeProperty);
|
||||
set => SetValue(TransitionModeProperty, value);
|
||||
}
|
||||
|
||||
public Storyboard TransitionStoryboard
|
||||
{
|
||||
get => (Storyboard) GetValue(TransitionStoryboardProperty);
|
||||
set => SetValue(TransitionStoryboardProperty, value);
|
||||
}
|
||||
|
||||
public InfoType Type
|
||||
{
|
||||
get => (InfoType) GetValue(TypeProperty);
|
||||
@@ -188,7 +208,12 @@ public class Growl : Control
|
||||
_buttonClose = GetTemplateChild(ElementButtonClose) as Button;
|
||||
|
||||
CheckNull();
|
||||
Update();
|
||||
this.Hide();
|
||||
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, () =>
|
||||
{
|
||||
Update();
|
||||
this.Show();
|
||||
});
|
||||
}
|
||||
|
||||
private void CheckNull()
|
||||
@@ -289,16 +314,15 @@ public class Growl : Control
|
||||
_panelMore.Show();
|
||||
}
|
||||
|
||||
var transform = new TranslateTransform
|
||||
StartTransition(false);
|
||||
|
||||
if (!_staysOpen)
|
||||
{
|
||||
X = FlowDirection == FlowDirection.LeftToRight ? MaxWidth : -MaxWidth
|
||||
};
|
||||
_gridMain.RenderTransform = transform;
|
||||
transform.BeginAnimation(TranslateTransform.XProperty, AnimationHelper.CreateAnimation(0));
|
||||
if (!_staysOpen) StartTimer();
|
||||
StartTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ShowInternal(Panel panel, UIElement growl)
|
||||
private static void ShowInternal(Panel panel, Growl growl)
|
||||
{
|
||||
if (panel is null)
|
||||
{
|
||||
@@ -321,37 +345,37 @@ public class Growl : Control
|
||||
#if NET40
|
||||
new Action(
|
||||
#endif
|
||||
() =>
|
||||
{
|
||||
if (GrowlWindow == null)
|
||||
() =>
|
||||
{
|
||||
GrowlWindow = new GrowlWindow();
|
||||
GrowlWindow.Show();
|
||||
InitGrowlPanel(GrowlWindow.GrowlPanel);
|
||||
GrowlWindow.Init();
|
||||
if (GrowlWindow == null)
|
||||
{
|
||||
GrowlWindow = new GrowlWindow();
|
||||
GrowlWindow.Show();
|
||||
InitGrowlPanel(GrowlWindow.GrowlPanel);
|
||||
GrowlWindow.Init();
|
||||
}
|
||||
|
||||
GrowlWindow.Show(true);
|
||||
|
||||
var ctl = new Growl
|
||||
{
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime),
|
||||
FlowDirection = growlInfo.FlowDirection
|
||||
};
|
||||
|
||||
ShowInternal(GrowlWindow.GrowlPanel, ctl);
|
||||
}
|
||||
|
||||
GrowlWindow.Show(true);
|
||||
|
||||
var ctl = new Growl
|
||||
{
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime),
|
||||
FlowDirection = growlInfo.FlowDirection
|
||||
};
|
||||
|
||||
ShowInternal(GrowlWindow.GrowlPanel, ctl);
|
||||
}
|
||||
#if NET40
|
||||
)
|
||||
#endif
|
||||
@@ -368,38 +392,38 @@ public class Growl : Control
|
||||
#if NET40
|
||||
new Action(
|
||||
#endif
|
||||
() =>
|
||||
{
|
||||
var ctl = new Growl
|
||||
() =>
|
||||
{
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(growlInfo.Token))
|
||||
{
|
||||
if (TokenManager.TryGetControl(growlInfo.Token, out var panel))
|
||||
var ctl = new Growl
|
||||
{
|
||||
ShowInternal(panel, ctl);
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(growlInfo.Token))
|
||||
{
|
||||
if (TokenManager.TryGetControl(growlInfo.Token, out var panel))
|
||||
{
|
||||
ShowInternal(panel, ctl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GrowlPanel is null, we create it automatically
|
||||
GrowlPanel ??= CreateDefaultPanel();
|
||||
ShowInternal(GrowlPanel, ctl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GrowlPanel is null, we create it automatically
|
||||
GrowlPanel ??= CreateDefaultPanel();
|
||||
ShowInternal(GrowlPanel, ctl);
|
||||
}
|
||||
}
|
||||
#if NET40
|
||||
)
|
||||
#endif
|
||||
@@ -816,36 +840,40 @@ public class Growl : Control
|
||||
}
|
||||
|
||||
_timerClose?.Stop();
|
||||
var transform = new TranslateTransform();
|
||||
_gridMain.RenderTransform = transform;
|
||||
var animation =
|
||||
AnimationHelper.CreateAnimation(FlowDirection == FlowDirection.LeftToRight ? ActualWidth : -ActualWidth);
|
||||
animation.Completed += (s, e) =>
|
||||
{
|
||||
if (Parent is Panel panel)
|
||||
{
|
||||
panel.Children.Remove(this);
|
||||
StartTransition(true, OnStoryboardCompleted);
|
||||
return;
|
||||
|
||||
if (GrowlWindow != null)
|
||||
{
|
||||
if (GrowlWindow.GrowlPanel is { Children.Count: 0 })
|
||||
{
|
||||
GrowlWindow.Close();
|
||||
GrowlWindow = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GrowlPanel is { Children.Count: 0 } && GetIsCreatedAutomatically(GrowlPanel))
|
||||
{
|
||||
// If the count of children is zero, we need to remove the panel, provided that the panel was created automatically
|
||||
RemoveDefaultPanel(GrowlPanel);
|
||||
GrowlPanel = null;
|
||||
}
|
||||
}
|
||||
void OnStoryboardCompleted()
|
||||
{
|
||||
if (Parent is not Panel panel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
transform.BeginAnimation(TranslateTransform.XProperty, animation);
|
||||
|
||||
panel.Children.Remove(this);
|
||||
|
||||
if (GrowlWindow != null)
|
||||
{
|
||||
if (GrowlWindow.GrowlPanel is not { Children.Count: 0 })
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GrowlWindow.Close();
|
||||
GrowlWindow = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GrowlPanel is not { Children.Count: 0 } || !GetIsCreatedAutomatically(GrowlPanel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the count of children is zero, we need to remove the panel, provided that the panel was created automatically
|
||||
RemoveDefaultPanel(GrowlPanel);
|
||||
GrowlPanel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -887,4 +915,153 @@ public class Growl : Control
|
||||
private void ButtonCancel_OnClick(object sender, RoutedEventArgs e) => Close(false);
|
||||
|
||||
private void ButtonOk_OnClick(object sender, RoutedEventArgs e) => Close(true);
|
||||
|
||||
private void StartTransition(bool isClose, Action completed = null)
|
||||
{
|
||||
var actualStoryboard = TransitionStoryboard ?? CreateStoryboard(isClose, TransitionMode);
|
||||
if (actualStoryboard is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (completed is not null)
|
||||
{
|
||||
actualStoryboard.Completed -= OnStoryboardCompleted;
|
||||
actualStoryboard.Completed += OnStoryboardCompleted;
|
||||
}
|
||||
|
||||
actualStoryboard.Begin();
|
||||
return;
|
||||
|
||||
void OnStoryboardCompleted(object s, EventArgs e)
|
||||
{
|
||||
completed?.Invoke();
|
||||
actualStoryboard.Completed -= OnStoryboardCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
private Storyboard CreateStoryboard(bool isClose, TransitionMode transitionMode)
|
||||
{
|
||||
var transformLength = GetTransformLength(isClose, transitionMode);
|
||||
var transformAnimation = CreateTransformAnimation(isClose, transitionMode, transformLength);
|
||||
_gridMain.RenderTransform = CreateRenderTransform(isClose, transitionMode, transformLength);
|
||||
|
||||
var storyboard = new Storyboard
|
||||
{
|
||||
Duration = transformAnimation.Duration
|
||||
};
|
||||
Storyboard.SetTarget(transformAnimation, _gridMain);
|
||||
storyboard.Children.Add(transformAnimation);
|
||||
|
||||
if (CreateFadeAnimation(transitionMode) is not { } fadeAnimation)
|
||||
{
|
||||
return storyboard;
|
||||
}
|
||||
|
||||
Storyboard.SetTarget(fadeAnimation, _gridMain);
|
||||
storyboard.Children.Add(fadeAnimation);
|
||||
|
||||
return storyboard;
|
||||
}
|
||||
|
||||
private double GetTransformLength(bool isClose, TransitionMode transitionMode)
|
||||
{
|
||||
var length = transitionMode switch
|
||||
{
|
||||
TransitionMode.Right2Left or TransitionMode.Right2LeftWithFade => ActualWidth,
|
||||
TransitionMode.Left2Right or TransitionMode.Left2RightWithFade => -ActualWidth,
|
||||
TransitionMode.Bottom2Top or TransitionMode.Bottom2TopWithFade => ActualHeight,
|
||||
TransitionMode.Top2Bottom or TransitionMode.Top2BottomWithFade => -ActualHeight,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
|
||||
return isClose ? -length : length;
|
||||
}
|
||||
|
||||
private static TransformGroup CreateOriginalTransform()
|
||||
{
|
||||
return new TransformGroup
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new ScaleTransform(),
|
||||
new SkewTransform(),
|
||||
new RotateTransform(),
|
||||
new TranslateTransform(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Transform CreateRenderTransform(bool isClose, TransitionMode transitionMode, double transformLength)
|
||||
{
|
||||
var transformGroup = CreateOriginalTransform();
|
||||
if (isClose)
|
||||
{
|
||||
return transformGroup;
|
||||
}
|
||||
|
||||
switch (GetOrientation(transitionMode))
|
||||
{
|
||||
case Orientation.Horizontal:
|
||||
((TranslateTransform) transformGroup.Children[TranslateTransformIndex]).X = transformLength;
|
||||
break;
|
||||
case Orientation.Vertical:
|
||||
((TranslateTransform) transformGroup.Children[TranslateTransformIndex]).Y = transformLength;
|
||||
break;
|
||||
}
|
||||
|
||||
return transformGroup;
|
||||
}
|
||||
|
||||
private static DoubleAnimation CreateTransformAnimation(bool isClose, TransitionMode transitionMode,
|
||||
double transformLength)
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(isClose ? -transformLength : 0);
|
||||
|
||||
switch (GetOrientation(transitionMode))
|
||||
{
|
||||
case Orientation.Horizontal:
|
||||
Storyboard.SetTargetProperty(animation,
|
||||
new PropertyPath(
|
||||
$"(UIElement.RenderTransform).(TransformGroup.Children)[{TranslateTransformIndex}].(TranslateTransform.X)"));
|
||||
break;
|
||||
case Orientation.Vertical:
|
||||
Storyboard.SetTargetProperty(animation,
|
||||
new PropertyPath(
|
||||
$"(UIElement.RenderTransform).(TransformGroup.Children)[{TranslateTransformIndex}].(TranslateTransform.Y)"));
|
||||
break;
|
||||
}
|
||||
|
||||
return animation;
|
||||
}
|
||||
|
||||
private static DoubleAnimation CreateFadeAnimation(TransitionMode transitionMode)
|
||||
{
|
||||
if (transitionMode is TransitionMode.Right2Left or
|
||||
TransitionMode.Left2Right or
|
||||
TransitionMode.Bottom2Top or
|
||||
TransitionMode.Top2Bottom)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var animation = AnimationHelper.CreateAnimation(1);
|
||||
animation.From = 0;
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("(UIElement.Opacity)"));
|
||||
|
||||
return animation;
|
||||
}
|
||||
|
||||
private static Orientation? GetOrientation(TransitionMode transitionMode)
|
||||
{
|
||||
return transitionMode switch
|
||||
{
|
||||
TransitionMode.Right2Left or TransitionMode.Right2LeftWithFade or TransitionMode.Left2Right
|
||||
or TransitionMode.Left2RightWithFade => Orientation.Horizontal,
|
||||
TransitionMode.Bottom2Top or TransitionMode.Bottom2TopWithFade or TransitionMode.Top2Bottom
|
||||
or TransitionMode.Top2BottomWithFade => Orientation.Vertical,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Windows;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
@@ -11,7 +12,8 @@ public class TransitioningContentControl : ContentControl
|
||||
{
|
||||
private FrameworkElement _contentPresenter;
|
||||
|
||||
private static Storyboard StoryboardBuildInDefault;
|
||||
private static readonly Lazy<Storyboard> StoryboardBuildInDefault = new(() =>
|
||||
ResourceHelper.GetResourceInternal<Storyboard>($"{default(TransitionMode)}Transition"), isThreadSafe: true);
|
||||
|
||||
private Storyboard _storyboardBuildIn;
|
||||
|
||||
@@ -22,7 +24,8 @@ public class TransitioningContentControl : ContentControl
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TransitionModeProperty = DependencyProperty.Register(
|
||||
nameof(TransitionMode), typeof(TransitionMode), typeof(TransitioningContentControl), new PropertyMetadata(default(TransitionMode), OnTransitionModeChanged));
|
||||
nameof(TransitionMode), typeof(TransitionMode), typeof(TransitioningContentControl),
|
||||
new PropertyMetadata(default(TransitionMode), OnTransitionModeChanged));
|
||||
|
||||
private static void OnTransitionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
@@ -43,7 +46,8 @@ public class TransitioningContentControl : ContentControl
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TransitionStoryboardProperty = DependencyProperty.Register(
|
||||
nameof(TransitionStoryboard), typeof(Storyboard), typeof(TransitioningContentControl), new PropertyMetadata(default(Storyboard)));
|
||||
nameof(TransitionStoryboard), typeof(Storyboard), typeof(TransitioningContentControl),
|
||||
new PropertyMetadata(default(Storyboard)));
|
||||
|
||||
public Storyboard TransitionStoryboard
|
||||
{
|
||||
@@ -51,7 +55,8 @@ public class TransitioningContentControl : ContentControl
|
||||
set => SetValue(TransitionStoryboardProperty, value);
|
||||
}
|
||||
|
||||
private void TransitioningContentControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) => StartTransition();
|
||||
private void TransitioningContentControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) =>
|
||||
StartTransition();
|
||||
|
||||
private void TransitioningContentControl_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -77,8 +82,7 @@ public class TransitioningContentControl : ContentControl
|
||||
}
|
||||
else
|
||||
{
|
||||
StoryboardBuildInDefault ??= ResourceHelper.GetResourceInternal<Storyboard>($"{default(TransitionMode)}Transition");
|
||||
StoryboardBuildInDefault?.Begin(_contentPresenter);
|
||||
StoryboardBuildInDefault.Value?.Begin(_contentPresenter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user