Merge branch 'master' into feature/tabbedcommandbar

This commit is contained in:
Yoshi Askharoun 2021-02-10 07:11:30 -06:00 коммит произвёл GitHub
Родитель 68fd8054e1 31b26032f6
Коммит 8ba0622e64
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
27 изменённых файлов: 222 добавлений и 928 удалений

Просмотреть файл

@ -112,7 +112,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddButton(IToastButton button)
{
if (button is ToastButton toastButton && toastButton.Content == null)
if (button is ToastButton toastButton && toastButton.Content == null && toastButton.NeedsContent())
{
throw new InvalidOperationException("Content is required on button.");
}

Просмотреть файл

@ -20,6 +20,17 @@ namespace Microsoft.Toolkit.Uwp.Notifications
private bool _usingCustomArguments;
private bool _usingSnoozeActivation;
private string _snoozeSelectionBoxId;
private bool _usingDismissActivation;
internal bool NeedsContent()
{
// Snooze/dismiss buttons don't need content (the system will auto-add the localized strings).
return !_usingDismissActivation && !_usingSnoozeActivation;
}
/// <summary>
/// Initializes a new instance of the <see cref="ToastButton"/> class.
/// </summary>
@ -213,6 +224,11 @@ namespace Microsoft.Toolkit.Uwp.Notifications
throw new InvalidOperationException("You cannot use the AddArgument methods when using protocol activation.");
}
if (_usingDismissActivation || _usingSnoozeActivation)
{
throw new InvalidOperationException("You cannot use the AddArgument methods when using dismiss or snooze activation.");
}
bool alreadyExists = _arguments.ContainsKey(key);
_arguments[key] = value;
@ -314,6 +330,48 @@ namespace Microsoft.Toolkit.Uwp.Notifications
return this;
}
/// <summary>
/// Configures the button to use system snooze activation when the button is clicked, using the default system snooze time.
/// </summary>
/// <returns>The current instance of <see cref="ToastButton"/></returns>
public ToastButton SetSnoozeActivation()
{
return SetSnoozeActivation(null);
}
/// <summary>
/// Configures the button to use system snooze activation when the button is clicked, with a snooze time defined by the specified selection box.
/// </summary>
/// <param name="selectionBoxId">The ID of an existing <see cref="ToastSelectionBox"/> which allows the user to pick a custom snooze time. The ID's of the <see cref="ToastSelectionBoxItem"/>s inside the selection box must represent the snooze interval in minutes. For example, if the user selects an item that has an ID of "120", then the notification will be snoozed for 2 hours. When the user clicks this button, if you specified a SelectionBoxId, the system will parse the ID of the selected item and snooze by that amount of minutes.</param>
/// <returns>The current instance of <see cref="ToastButton"/></returns>
public ToastButton SetSnoozeActivation(string selectionBoxId)
{
if (_arguments.Count > 0)
{
throw new InvalidOperationException($"{nameof(SetSnoozeActivation)} cannot be used in conjunction with ${nameof(AddArgument)}.");
}
_usingSnoozeActivation = true;
_snoozeSelectionBoxId = selectionBoxId;
return this;
}
/// <summary>
/// Configures the button to use system dismiss activation when the button is clicked (the toast will simply dismiss rather than activating).
/// </summary>
/// <returns>The current instance of <see cref="ToastButton"/></returns>
public ToastButton SetDismissActivation()
{
if (_arguments.Count > 0)
{
throw new InvalidOperationException($"{nameof(SetDismissActivation)} cannot be used in conjunction with ${nameof(AddArgument)}.");
}
_usingDismissActivation = true;
return this;
}
/// <summary>
/// Sets an identifier used in telemetry to identify your category of action. This should be something like "Delete", "Reply", or "Archive". In the upcoming toast telemetry dashboard in Dev Center, you will be able to view how frequently your actions are being clicked.
/// </summary>
@ -349,7 +407,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
internal bool CanAddArguments()
{
return ActivationType != ToastActivationType.Protocol && !_usingCustomArguments;
return ActivationType != ToastActivationType.Protocol && !_usingCustomArguments && !_usingDismissActivation && !_usingSnoozeActivation;
}
internal bool ContainsArgument(string key)
@ -362,13 +420,44 @@ namespace Microsoft.Toolkit.Uwp.Notifications
var el = new Element_ToastAction()
{
Content = Content,
Arguments = Arguments,
ActivationType = Element_Toast.ConvertActivationType(ActivationType),
ImageUri = ImageUri,
InputId = TextBoxId,
HintActionId = HintActionId
};
if (_usingSnoozeActivation)
{
el.ActivationType = Element_ToastActivationType.System;
el.Arguments = "snooze";
if (_snoozeSelectionBoxId != null)
{
el.InputId = _snoozeSelectionBoxId;
}
// Content needs to be specified as empty for auto-generated Snooze content
if (el.Content == null)
{
el.Content = string.Empty;
}
}
else if (_usingDismissActivation)
{
el.ActivationType = Element_ToastActivationType.System;
el.Arguments = "dismiss";
// Content needs to be specified as empty for auto-generated Dismiss content
if (el.Content == null)
{
el.Content = string.Empty;
}
}
else
{
el.ActivationType = Element_Toast.ConvertActivationType(ActivationType);
el.Arguments = Arguments;
}
ActivationOptions?.PopulateElement(el);
return el;

Просмотреть файл

@ -13,7 +13,9 @@ private void PopToast()
("60", "1 hour"),
("240", "4 hours"),
("1440", "1 day"))
.AddButton(new ToastButtonSnooze() { SelectionBoxId = "snoozeTime" })
.AddButton(new ToastButtonDismiss())
.AddButton(new ToastButton()
.SetSnoozeActivation("snoozeTime"))
.AddButton(new ToastButton()
.SetDismissActivation())
.Show();
}

Просмотреть файл

@ -40,8 +40,10 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
("60", "1 hour"),
("240", "4 hours"),
("1440", "1 day"))
.AddButton(new ToastButtonSnooze() { SelectionBoxId = "snoozeTime" })
.AddButton(new ToastButtonDismiss());
.AddButton(new ToastButton()
.SetSnoozeActivation("snoozeTime"))
.AddButton(new ToastButton()
.SetDismissActivation());
return builder.Content;
}

Просмотреть файл

@ -1,42 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// Performs an blur animation using composition.
/// </summary>
/// <seealso>
/// <cref>Microsoft.Xaml.Interactivity.Behavior{Windows.UI.Xaml.UIElement}</cref>
/// </seealso>
public class Blur : CompositionBehaviorBase<FrameworkElement>
{
/// <summary>
/// The Blur value of the associated object
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(double), typeof(Blur), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// Gets or sets the Blur.
/// </summary>
/// <value>
/// The Blur.
/// </value>
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public override void StartAnimation()
{
AssociatedObject?.Blur(duration: Duration, delay: Delay, value: (float)Value, easingType: EasingType, easingMode: EasingMode)?.Start();
}
}
}

Просмотреть файл

@ -1,141 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI.Behaviors;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Animation;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// A base class for all behaviors using composition.It contains some of the common properties to set on a visual.
/// </summary>
/// <typeparam name="T">The type of the associated object.</typeparam>
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Behaviors.BehaviorBase{T}" />
public abstract class CompositionBehaviorBase<T> : BehaviorBase<T>
where T : UIElement
{
/// <summary>
/// Called when the associated object has been loaded.
/// </summary>
protected override void OnAssociatedObjectLoaded()
{
base.OnAssociatedObjectLoaded();
if (AutomaticallyStart)
{
StartAnimation();
}
}
/// <summary>
/// The duration of the animation.
/// </summary>
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(nameof(Duration), typeof(double), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(1d, PropertyChangedCallback));
/// <summary>
/// The delay of the animation.
/// </summary>
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register(nameof(Delay), typeof(double), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// The property sets if the animation should automatically start.
/// </summary>
public static readonly DependencyProperty AutomaticallyStartProperty = DependencyProperty.Register(nameof(AutomaticallyStart), typeof(bool), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(true, PropertyChangedCallback));
/// <summary>
/// The <see cref="EasingType"/> used to generate the easing function of the animation.
/// </summary>
public static readonly DependencyProperty EasingTypeProperty = DependencyProperty.Register(nameof(EasingType), typeof(EasingType), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(EasingType.Default, PropertyChangedCallback));
/// <summary>
/// The <see cref="EasingMode"/> used to generate the easing function of the animation.
/// </summary>
public static readonly DependencyProperty EasingModeProperty = DependencyProperty.Register(nameof(EasingMode), typeof(EasingMode), typeof(CompositionBehaviorBase<T>), new PropertyMetadata(EasingMode.EaseOut, PropertyChangedCallback));
/// <summary>
/// Gets or sets a value indicating whether [automatically start] on the animation is set.
/// </summary>
/// <value>
/// <c>true</c> if [automatically start]; otherwise, <c>false</c>.
/// </value>
public bool AutomaticallyStart
{
get { return (bool)GetValue(AutomaticallyStartProperty); }
set { SetValue(AutomaticallyStartProperty, value); }
}
/// <summary>
/// Gets or sets the delay.
/// </summary>
/// <value>
/// The delay.
/// </value>
public double Delay
{
get { return (double)GetValue(DelayProperty); }
set { SetValue(DelayProperty, value); }
}
/// <summary>
/// Gets or sets the duration.
/// </summary>
/// <value>
/// The duration.
/// </value>
public double Duration
{
get { return (double)GetValue(DurationProperty); }
set { SetValue(DurationProperty, value); }
}
/// <summary>
/// Gets or sets the <see cref="EasingType"/> used to generate the easing function of the animation.
/// </summary>
/// <value>
/// The easing function
/// </value>
public EasingType EasingType
{
get { return (EasingType)GetValue(EasingTypeProperty); }
set { SetValue(EasingTypeProperty, value); }
}
/// <summary>
/// Gets or sets the <see cref="EasingMode"/> used to generate the easing function of the animation.
/// </summary>
/// <value>
/// The easing mode
/// </value>
public EasingMode EasingMode
{
get { return (EasingMode)GetValue(EasingModeProperty); }
set { SetValue(EasingModeProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public abstract void StartAnimation();
/// <summary>
/// If any of the properties are changed then the animation is automatically started depending on the AutomaticallyStart property.
/// </summary>
/// <param name="dependencyObject">The dependency object.</param>
/// <param name="dependencyPropertyChangedEventArgs">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
protected static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var behavior = dependencyObject as CompositionBehaviorBase<T>;
if (behavior == null)
{
return;
}
if (behavior.AutomaticallyStart)
{
behavior.StartAnimation();
}
}
}
}

Просмотреть файл

@ -1,16 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// Non-generic convenience implementation to provide backwards compatibility.
/// </summary>
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Animations.Behaviors.CompositionBehaviorBase{T}" />
public abstract class CompositionBehaviorBase : CompositionBehaviorBase<UIElement>
{
}
}

Просмотреть файл

@ -1,42 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// Performs an fade animation using composition.
/// </summary>
/// <seealso>
/// <cref>Microsoft.Xaml.Interactivity.Behavior{Windows.UI.Xaml.UIElement}</cref>
/// </seealso>
public class Fade : CompositionBehaviorBase<UIElement>
{
/// <summary>
/// The Opacity value of the associated object
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(double), typeof(Fade), new PropertyMetadata(1d, PropertyChangedCallback));
/// <summary>
/// Gets or sets the Opacity.
/// </summary>
/// <value>
/// The Opacity.
/// </value>
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public override void StartAnimation()
{
AssociatedObject.Fade((float)Value, Duration, Delay, EasingType, EasingMode)?.Start();
}
}
}

Просмотреть файл

@ -1,65 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// Applies a basic point light to a UIElement. You control the intensity by setting the distance of the light.
/// </summary>
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Animations.Behaviors.CompositionBehaviorBase" />
[Obsolete("The Light effect will be removed in a future major release. Please use XamlLight instead")]
public class Light : CompositionBehaviorBase<FrameworkElement>
{
/// <summary>
/// The Blur value of the associated object
/// </summary>
public static readonly DependencyProperty DistanceProperty = DependencyProperty.Register(nameof(Distance), typeof(double), typeof(Light), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// The Color of the spotlight no the associated object.
/// </summary>
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(Light), new PropertyMetadata(new SolidColorBrush(Colors.White)));
/// <summary>
/// Gets or sets the Blur.
/// </summary>
/// <value>
/// The Blur.
/// </value>
public double Distance
{
get { return (double)GetValue(DistanceProperty); }
set { SetValue(DistanceProperty, value); }
}
/// <summary>
/// Gets or sets the color of the spotlight.
/// </summary>
public Brush Color
{
get { return (Brush)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public override void StartAnimation()
{
AssociatedObject?.Light(
duration: Duration,
delay: Delay,
easingType: EasingType,
easingMode: EasingMode,
distance: (float)Distance,
color: ((SolidColorBrush)Color).Color)?.Start();
}
}
}

Просмотреть файл

@ -1,66 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// Performs an offset animation using composition.
/// </summary>
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Animations.Behaviors.CompositionBehaviorBase" />
/// <seealso>
/// <cref>Microsoft.Xaml.Interactivity.Behavior{Windows.UI.Xaml.UIElement}</cref>
/// </seealso>
public class Offset : CompositionBehaviorBase<UIElement>
{
/// <summary>
/// The Offset on the x axis of the associated object
/// </summary>
public static readonly DependencyProperty OffsetXProperty = DependencyProperty.Register(nameof(OffsetX), typeof(double), typeof(Offset), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// The Offset on the y axis of the associated object
/// </summary>
public static readonly DependencyProperty OffsetYProperty = DependencyProperty.Register(nameof(OffsetY), typeof(double), typeof(Offset), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// Gets or sets the Offset x.
/// </summary>
/// <value>
/// The Offset x.
/// </value>
public double OffsetX
{
get { return (double)GetValue(OffsetXProperty); }
set { SetValue(OffsetXProperty, value); }
}
/// <summary>
/// Gets or sets the Offset y.
/// </summary>
/// <value>
/// The Offset y.
/// </value>
public double OffsetY
{
get { return (double)GetValue(OffsetYProperty); }
set { SetValue(OffsetYProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public override void StartAnimation()
{
AssociatedObject.Offset(
duration: Duration,
delay: Delay,
easingType: EasingType,
easingMode: EasingMode,
offsetX: (float)OffsetX,
offsetY: (float)OffsetY)?.Start();
}
}
}

Просмотреть файл

@ -1,81 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// Performs a rotation animation using composition.
/// </summary>
public class Rotate : CompositionBehaviorBase<UIElement>
{
/// <summary>
/// The rotation of the associated object in degrees
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(double), typeof(Rotate), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// The center (x axis) of rotation for associated object
/// </summary>
public static readonly DependencyProperty CenterXProperty = DependencyProperty.Register(nameof(CenterX), typeof(double), typeof(Rotate), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// The center (y axis) of rotation for associated object
/// </summary>
public static readonly DependencyProperty CenterYProperty = DependencyProperty.Register(nameof(CenterY), typeof(double), typeof(Rotate), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// Gets or sets the center point (x axis) of the associated object.
/// </summary>
/// <value>
/// The center point (x axis) of the associated object.
/// </value>
public double CenterX
{
get { return (double)GetValue(CenterXProperty); }
set { SetValue(CenterXProperty, value); }
}
/// <summary>
/// Gets or sets the center point (y axis) of the associated object.
/// </summary>
/// <value>
/// The center point (y axis) of the associated object.
/// </value>
public double CenterY
{
get { return (double)GetValue(CenterYProperty); }
set { SetValue(CenterYProperty, value); }
}
/// <summary>
/// Gets or sets the Rotation in degrees.
/// </summary>
/// <value>
/// The Rotation of the associated object in degrees.
/// </value>
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public override void StartAnimation()
{
AssociatedObject.Rotate(
duration: Duration,
delay: Delay,
easingType: EasingType,
easingMode: EasingMode,
value: (float)Value,
centerX: (float)CenterX,
centerY: (float)CenterY)?
.Start();
}
}
}

Просмотреть файл

@ -1,61 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// A behavior to allow Saturation changes to a UI Element.
/// </summary>
public class Saturation : CompositionBehaviorBase
{
/// <summary>
/// The Saturation value of the associated object
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(double), typeof(Saturation), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// The _framework element
/// </summary>
private FrameworkElement _frameworkElement;
/// <summary>
/// Gets or sets the Saturation.
/// </summary>
/// <value>
/// The Saturation.
/// </value>
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public override void StartAnimation()
{
_frameworkElement?.Saturation(
duration: Duration,
delay: Delay,
easingType: EasingType,
easingMode: EasingMode,
value: (float)Value)?.StartAsync();
}
/// <summary>
/// Called after the behavior is attached to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />.
/// </summary>
/// <remarks>
/// Override this to hook up functionality to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />
/// </remarks>
protected override void OnAttached()
{
base.OnAttached();
_frameworkElement = AssociatedObject as FrameworkElement;
}
}
}

Просмотреть файл

@ -1,99 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Behaviors
{
/// <summary>
/// Performs a scale animation using composition.
/// </summary>
public class Scale : CompositionBehaviorBase<UIElement>
{
/// <summary>
/// The scale (x axis) of the associated object
/// </summary>
public static readonly DependencyProperty ScaleXProperty = DependencyProperty.Register(nameof(ScaleX), typeof(double), typeof(Scale), new PropertyMetadata(1d, PropertyChangedCallback));
/// <summary>
/// The scale (y axis) of the associated object
/// </summary>
public static readonly DependencyProperty ScaleYProperty = DependencyProperty.Register(nameof(ScaleY), typeof(double), typeof(Scale), new PropertyMetadata(1d, PropertyChangedCallback));
/// <summary>
/// The center (x axis) of scale for associated object
/// </summary>
public static readonly DependencyProperty CenterXProperty = DependencyProperty.Register(nameof(CenterX), typeof(double), typeof(Scale), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// The center (y axis) of scale for associated object
/// </summary>
public static readonly DependencyProperty CenterYProperty = DependencyProperty.Register(nameof(CenterY), typeof(double), typeof(Scale), new PropertyMetadata(0d, PropertyChangedCallback));
/// <summary>
/// Gets or sets the scale on the x axis.
/// </summary>
/// <value>
/// The scale on the x axis.
/// </value>
public double ScaleX
{
get { return (double)GetValue(ScaleXProperty); }
set { SetValue(ScaleXProperty, value); }
}
/// <summary>
/// Gets or sets the scale on the y axis.
/// </summary>
/// <value>
/// The scale on the y axis.
/// </value>
public double ScaleY
{
get { return (double)GetValue(ScaleYProperty); }
set { SetValue(ScaleYProperty, value); }
}
/// <summary>
/// Gets or sets the scale (x axis) of the associated object.
/// </summary>
/// <value>
/// The scale (x axis) of the associated object.
/// </value>
public double CenterX
{
get { return (double)GetValue(CenterXProperty); }
set { SetValue(CenterXProperty, value); }
}
/// <summary>
/// Gets or sets the scale (y axis) of the associated object.
/// </summary>
/// <value>
/// The scale (y axis) of the associated object.
/// </value>
public double CenterY
{
get { return (double)GetValue(CenterYProperty); }
set { SetValue(CenterYProperty, value); }
}
/// <summary>
/// Starts the animation.
/// </summary>
public override void StartAnimation()
{
AssociatedObject.Scale(
duration: Duration,
delay: Delay,
easingType: EasingType,
easingMode: EasingMode,
centerX: (float)CenterX,
centerY: (float)CenterY,
scaleX: (float)ScaleX,
scaleY: (float)ScaleY)?
.Start();
}
}
}

Просмотреть файл

@ -1,170 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Numerics;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Hosting;
using Windows.UI.Xaml.Media.Animation;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Effects
{
/// <summary>
/// An abstract class that provides the mechanism to create
/// an effect using composition.
/// </summary>
public abstract class AnimationEffect
{
private static string[] _effectProperties;
/// <summary>
/// Gets the name of the effect.
/// </summary>
/// <value>
/// The name of the effect.
/// </value>
public abstract string EffectName { get; }
/// <summary>
/// Gets or sets the compositor.
/// </summary>
/// <value>
/// The compositor.
/// </value>
public Compositor Compositor { get; set; }
/// <summary>
/// Gets or sets the effect brush.
/// </summary>
/// <value>
/// The effect brush.
/// </value>
public CompositionEffectBrush EffectBrush { get; set; }
/// <summary>
/// Applies the effect.
/// </summary>
/// <returns>An array of strings of the effect properties to change.</returns>
public abstract string[] ApplyEffect();
/// <summary>
/// An animation which will apply the derived effect.
/// </summary>
/// <param name="animationSet">The animation set.</param>
/// <param name="value">The value.</param>
/// <param name="duration">The duration in milliseconds.</param>
/// <param name="delay">The delay in milliseconds.</param>
/// <param name="easingType">The easing function to use</param>
/// <param name="easingMode">The easing mode to use</param>
/// <returns>An animation set with the effect added to it.</returns>
public AnimationSet EffectAnimation(
AnimationSet animationSet,
double value = 0d,
double duration = 500d,
double delay = 0d,
EasingType easingType = EasingType.Default,
EasingMode easingMode = EasingMode.EaseOut)
{
if (animationSet == null)
{
return null;
}
var visual = animationSet.Visual;
var associatedObject = animationSet.Element as FrameworkElement;
if (associatedObject == null)
{
return animationSet;
}
Compositor = visual?.Compositor;
if (Compositor == null)
{
return null;
}
// check to see if the visual already has an effect applied.
var spriteVisual = ElementCompositionPreview.GetElementChildVisual(associatedObject) as SpriteVisual;
EffectBrush = spriteVisual?.Brush as CompositionEffectBrush;
if (EffectBrush == null || EffectBrush?.Comment != EffectName)
{
_effectProperties = ApplyEffect();
EffectBrush.Comment = EffectName;
var sprite = Compositor.CreateSpriteVisual();
sprite.Brush = EffectBrush;
ElementCompositionPreview.SetElementChildVisual(associatedObject, sprite);
sprite.Size = new Vector2((float)associatedObject.ActualWidth, (float)associatedObject.ActualHeight);
associatedObject.SizeChanged +=
(s, e) =>
{
sprite.Size = new Vector2(
(float)associatedObject.ActualWidth,
(float)associatedObject.ActualHeight);
};
}
if (duration <= 0)
{
foreach (var effectProperty in _effectProperties)
{
animationSet.AddEffectDirectPropertyChange(EffectBrush, (float)value, effectProperty);
}
}
else
{
foreach (var effectProperty in _effectProperties)
{
var animation = Compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(1f, (float)value, AnimationExtensions.GetCompositionEasingFunction(easingType, Compositor, easingMode));
animation.Duration = TimeSpan.FromMilliseconds(duration);
animation.DelayTime = TimeSpan.FromMilliseconds(delay);
animationSet.AddCompositionEffectAnimation(EffectBrush, animation, effectProperty);
}
}
// Saturation starts from 1 to 0, instead of 0 to 1 so this makes sure the
// the brush isn't removed from the UI element incorrectly. Completing on
// Saturation as it's reusing the same sprite visual. Removing the Sprite removes the effect.
if (EffectName != "Saturation" && value == 0)
{
animationSet.Completed += AnimationSet_Completed;
}
return animationSet;
}
/// <summary>
/// Handles the Completed event of the AnimationSet control.
/// When an animation is completed the brush is removed from the sprite.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
private void AnimationSet_Completed(object sender, EventArgs e)
{
var animationSet = sender as AnimationSet;
if (animationSet != null)
{
animationSet.Completed -= AnimationSet_Completed;
var spriteVisual = ElementCompositionPreview.GetElementChildVisual(animationSet.Element) as SpriteVisual;
var brush = spriteVisual?.Brush as CompositionEffectBrush;
if (brush != null && brush.Comment == EffectName)
{
spriteVisual.Brush = null;
}
}
}
}
}

Просмотреть файл

@ -1,50 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Graphics.Canvas.Effects;
using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Effects
{
/// <summary>
/// An animation effect that applies blur.
/// </summary>
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Animations.Effects.AnimationEffect" />
public class Blur : AnimationEffect
{
/// <summary>
/// Gets the name of the effect.
/// </summary>
/// <value>
/// The name of the effect.
/// </value>
public override string EffectName { get; } = "Blur";
/// <summary>
/// Applies the effect.
/// </summary>
/// <returns>
/// An array of strings of the effect properties to change.
/// </returns>
public override string[] ApplyEffect()
{
var gaussianBlur = new GaussianBlurEffect
{
Name = EffectName,
BlurAmount = 0f,
Optimization = EffectOptimization.Balanced,
BorderMode = EffectBorderMode.Hard,
Source = new CompositionEffectSourceParameter("source")
};
var propertyToChange = $"{EffectName}.BlurAmount";
var propertiesToAnimate = new[] { propertyToChange };
EffectBrush = Compositor.CreateEffectFactory(gaussianBlur, propertiesToAnimate).CreateBrush();
EffectBrush.SetSourceParameter("source", Compositor.CreateBackdropBrush());
return propertiesToAnimate;
}
}
}

Просмотреть файл

@ -1,48 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Graphics.Canvas.Effects;
using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Effects
{
/// <summary>
/// An animation effect that applies saturation.
/// </summary>
/// <seealso cref="Microsoft.Toolkit.Uwp.UI.Animations.Effects.AnimationEffect" />
public class Saturation : AnimationEffect
{
/// <summary>
/// Gets the name of the effect.
/// </summary>
/// <value>
/// The name of the effect.
/// </value>
public override string EffectName { get; } = "Saturation";
/// <summary>
/// Applies the effect.
/// </summary>
/// <returns>
/// An array of strings of the effect properties to change.
/// </returns>
public override string[] ApplyEffect()
{
var saturationEffect = new SaturationEffect
{
Saturation = 1f,
Name = EffectName,
Source = new CompositionEffectSourceParameter("source")
};
var propertyToChange = $"{EffectName}.Saturation";
var propertiesToAnimate = new[] { propertyToChange };
EffectBrush = Compositor.CreateEffectFactory(saturationEffect, propertiesToAnimate).CreateBrush();
EffectBrush.SetSourceParameter("source", Compositor.CreateBackdropBrush());
return propertiesToAnimate;
}
}
}

Просмотреть файл

@ -18,22 +18,6 @@
<LangVersion>9.0</LangVersion>
</PropertyGroup>
<!-- TODO: Figure out where these go... -->
<ItemGroup>
<Compile Remove="Behaviors\**" />
<Compile Remove="Effects\**" />
<Compile Remove="fg\**" />
<EmbeddedResource Remove="Behaviors\**" />
<EmbeddedResource Remove="Effects\**" />
<EmbeddedResource Remove="fg\**" />
<None Remove="Behaviors\**" />
<None Remove="Effects\**" />
<None Remove="fg\**" />
<Page Remove="Behaviors\**" />
<Page Remove="Effects\**" />
<Page Remove="fg\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI\Microsoft.Toolkit.Uwp.UI.csproj" />

Просмотреть файл

@ -32,16 +32,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
public event EventHandler? Started;
/// <summary>
/// Raised whenever the current animation ends.
/// Raised whenever the current animation completes.
/// </summary>
public event EventHandler? Ended;
/// <summary>
/// An interface representing a node in an <see cref="AnimationSet"/> instance.
/// </summary>
public interface INode
{
}
public event EventHandler? Completed;
/// <summary>
/// Gets or sets a value indicating whether top level animation nodes in this collection are invoked
@ -73,7 +66,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
// Here we're using an async void method on purpose, in order to be able to await
// the completion of the animation and rethrow exceptions. We can't just use the
// synchronous AnimationBuilder.Start method here, as we also need to await for the
// animation to complete in either case in order to raise the Ended event when that
// animation to complete in either case in order to raise the Completed event when that
// happens. So we add an async state machine here to work around this.
await StartAsync();
}
@ -124,7 +117,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
if (IsSequential)
{
foreach (INode node in this)
foreach (object node in this)
{
if (node is ITimeline timeline)
{
@ -151,6 +144,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
break;
}
}
else
{
ThrowArgumentException();
}
// This should in theory only be necessary in the timeline branch, but doing this check
// after running activities too help guard against 3rd party activities that might not
@ -165,7 +162,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
{
var builder = AnimationBuilder.Create();
foreach (INode node in this)
foreach (object node in this)
{
switch (node)
{
@ -175,13 +172,18 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
case IActivity activity:
_ = activity.InvokeAsync(element, token);
break;
default:
ThrowArgumentException();
break;
}
}
await builder.StartAsync(element, token);
}
Ended?.Invoke(this, EventArgs.Empty);
Completed?.Invoke(this, EventArgs.Empty);
static void ThrowArgumentException() => throw new ArgumentException($"An animation set can only contain nodes implementing either ITimeline or IActivity");
}
/// <summary>

Просмотреть файл

@ -11,7 +11,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
/// <summary>
/// An interface representing a XAML model for a custom activity or action within an <see cref="AnimationSet"/>.
/// </summary>
public interface IActivity : AnimationSet.INode
public interface IActivity
{
/// <summary>
/// Invokes the current activity.

Просмотреть файл

@ -10,7 +10,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
/// <summary>
/// An interface representing a XAML model for a custom animation.
/// </summary>
public interface ITimeline : AnimationSet.INode
public interface ITimeline
{
/// <summary>
/// Appens the current animation to a target <see cref="AnimationBuilder"/> instance.

Просмотреть файл

@ -10,9 +10,9 @@ using Microsoft.Xaml.Interactivity;
namespace Microsoft.Toolkit.Uwp.UI.Behaviors
{
/// <summary>
/// A custom <see cref="Trigger"/> that fires whenever a linked <see cref="AnimationSet"/> ends.
/// A custom <see cref="Trigger"/> that fires whenever a linked <see cref="AnimationSet"/> completes.
/// </summary>
public sealed class AnimationEndBehavior : Trigger<AnimationSet>
public sealed class AnimationCompletedTriggerBehavior : Trigger<AnimationSet>
{
/// <summary>
/// The current <see cref="AnimationSet"/> instance in use.
@ -48,14 +48,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Behaviors
if (this.animationCollection is not null)
{
this.animationCollection.Ended -= AnimationCollection_Ended;
this.animationCollection.Completed -= AnimationCollection_Completed;
}
this.animationCollection = animationCollection;
if (animationCollection is not null)
{
animationCollection.Ended += AnimationCollection_Ended;
animationCollection.Completed += AnimationCollection_Completed;
}
}
@ -64,7 +64,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Behaviors
/// </summary>
/// <param name="sender">The source <see cref="AnimationSet"/> instance.</param>
/// <param name="e">The arguments for the event (unused).</param>
private void AnimationCollection_Ended(object sender, System.EventArgs e)
private void AnimationCollection_Completed(object sender, System.EventArgs e)
{
Interaction.ExecuteActions(sender, Actions, e);
}

Просмотреть файл

@ -12,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Behaviors
/// <summary>
/// A custom <see cref="Trigger"/> that fires whenever a linked <see cref="AnimationSet"/> starts.
/// </summary>
public sealed class AnimationStartBehavior : Trigger<AnimationSet>
public sealed class AnimationStartedTriggerBehavior : Trigger<AnimationSet>
{
/// <summary>
/// The current <see cref="AnimationSet"/> instance in use.

Просмотреть файл

@ -148,6 +148,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
var horizontalChange = e.Delta.Translation.X;
var verticalChange = e.Delta.Translation.Y;
if (this.FlowDirection == FlowDirection.RightToLeft)
{
horizontalChange *= -1;
}
if (_resizeDirection == GridResizeDirection.Columns)
{
if (HorizontalMove(horizontalChange))

Просмотреть файл

@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.Toolkit.Uwp.UI.Extensions;
using Microsoft.Toolkit.Uwp.Extensions;
using Windows.Foundation;
using Windows.System;
using Windows.UI.Xaml;

Просмотреть файл

@ -6,7 +6,7 @@ using System;
using System.Collections.Concurrent;
using Windows.System;
namespace Microsoft.Toolkit.Uwp.UI.Extensions
namespace Microsoft.Toolkit.Uwp.Extensions
{
/// <summary>
/// Set of extention methods for using <see cref="DispatcherQueueTimer"/>.

Просмотреть файл

@ -405,6 +405,36 @@ namespace UnitTests.Notifications
.SetProtocolActivation(new Uri("https://msn.com"));
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ToastButtonBuilders_InvalidDismissAfterArguments_ReturnSelf()
{
new ToastButton()
.SetContent("View")
.AddArgument("action", "view")
.SetDismissActivation();
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ToastButtonBuilders_InvalidSnoozeAfterArguments_ReturnSelf()
{
new ToastButton()
.SetContent("View")
.AddArgument("action", "view")
.SetSnoozeActivation();
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ToastButtonBuilders_InvalidSnoozeWithIdAfterArguments_ReturnSelf()
{
new ToastButton()
.SetContent("View")
.AddArgument("action", "view")
.SetSnoozeActivation("snoozeId");
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ToastButtonBuilders_InvalidArgumentsAfterProtocol_ReturnSelf()
@ -424,6 +454,36 @@ namespace UnitTests.Notifications
button.AddArgument("action", "view");
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ToastButtonBuilders_InvalidArgumentsAfterSnooze_ReturnSelf()
{
new ToastButton()
.SetContent("Later")
.SetSnoozeActivation()
.AddArgument("action", "later");
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ToastButtonBuilders_InvalidArgumentsAfterSnoozeWithId_ReturnSelf()
{
new ToastButton()
.SetContent("Later")
.SetSnoozeActivation("myId")
.AddArgument("action", "later");
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ToastButtonBuilders_InvalidArgumentsAfterDismissActivation_ReturnSelf()
{
new ToastButton()
.SetContent("Later")
.SetDismissActivation()
.AddArgument("action", "later");
}
[TestMethod]
public void SetToastDurationTest_WithCustomToastDuration_ReturnSelfWithCustomToastDurationSet()
{

Просмотреть файл

@ -977,6 +977,37 @@ namespace UnitTests.Notifications
Assert.Fail("Exception should have been thrown, only 5 actions are allowed.");
}
[TestMethod]
public void Test_Toast_Xml_Actions_SnoozeAndDismissUsingBuilders()
{
AssertActionsPayload("<actions><action content='' activationType='system' arguments='snooze'/><action content='' activationType='system' arguments='dismiss'/><action content='Hide' activationType='system' arguments='dismiss'/><action content='Later' activationType='system' arguments='snooze'/><action content='Remind me' activationType='system' arguments='snooze' hint-inputId='snoozePicker'/></actions>", new ToastActionsCustom()
{
Buttons =
{
// Allowing system to auto-generate text content
new ToastButton()
.SetSnoozeActivation(),
// Allowing system to auto-generate text content
new ToastButton()
.SetDismissActivation(),
// Specifying specific content
new ToastButton()
.SetContent("Hide")
.SetDismissActivation(),
new ToastButton()
.SetContent("Later")
.SetSnoozeActivation(),
new ToastButton()
.SetContent("Remind me")
.SetSnoozeActivation("snoozePicker")
}
});
}
[TestMethod]
public void Test_Toast_Xml_Actions_TwoContextMenuItems()
{