Merge branch 'main' into winui
# Conflicts: # CommunityToolkit.WinUI.SampleApp/SamplePages/Implicit Animations/ImplicitAnimationsPage.xaml.cs # version.json
This commit is contained in:
Коммит
862b43a39c
|
@ -42,10 +42,11 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
|
|||
return;
|
||||
}
|
||||
|
||||
// Validate the language version
|
||||
if (context.ParseOptions is not CSharpParseOptions { LanguageVersion: >= LanguageVersion.CSharp9 })
|
||||
// Validate the language version (this needs at least C# 8.0 due to static local functions being used).
|
||||
// If a lower C# version is set, just skip the execution silently. The fallback path will be used just fine.
|
||||
if (context.ParseOptions is not CSharpParseOptions { LanguageVersion: >= LanguageVersion.CSharp8 })
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, null));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the symbol for the required attributes
|
||||
|
|
|
@ -39,10 +39,10 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
|
|||
return;
|
||||
}
|
||||
|
||||
// Validate the language version
|
||||
if (context.ParseOptions is not CSharpParseOptions { LanguageVersion: >= LanguageVersion.CSharp9 })
|
||||
// Like in the ObservableValidator.ValidateALlProperties generator, execution is skipped if C# >= 8.0 isn't available
|
||||
if (context.ParseOptions is not CSharpParseOptions { LanguageVersion: >= LanguageVersion.CSharp8 })
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, null));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the symbol for the IRecipient<T> interface type
|
||||
|
|
|
@ -488,6 +488,21 @@ namespace CommunityToolkit.Mvvm.ComponentModel
|
|||
// Fallback method to create the delegate with a compiled LINQ expression
|
||||
static Action<object> GetValidationActionFallback(Type type)
|
||||
{
|
||||
// Get the collection of all properties to validate
|
||||
(string Name, MethodInfo GetMethod)[] validatableProperties = (
|
||||
from property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
where property.GetIndexParameters().Length == 0 &&
|
||||
property.GetCustomAttributes<ValidationAttribute>(true).Any()
|
||||
let getMethod = property.GetMethod
|
||||
where getMethod is not null
|
||||
select (property.Name, getMethod)).ToArray();
|
||||
|
||||
// Short path if there are no properties to validate
|
||||
if (validatableProperties.Length == 0)
|
||||
{
|
||||
return static _ => { };
|
||||
}
|
||||
|
||||
// MyViewModel inst0 = (MyViewModel)arg0;
|
||||
ParameterExpression arg0 = Expression.Parameter(typeof(object));
|
||||
UnaryExpression inst0 = Expression.Convert(arg0, type);
|
||||
|
@ -513,14 +528,10 @@ namespace CommunityToolkit.Mvvm.ComponentModel
|
|||
// ObservableValidator externally, but that is fine because IL doesn't really have
|
||||
// a concept of member visibility, that's purely a C# build-time feature.
|
||||
BlockExpression body = Expression.Block(
|
||||
from property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
where property.GetIndexParameters().Length == 0 &&
|
||||
property.GetCustomAttributes<ValidationAttribute>(true).Any()
|
||||
let getter = property.GetMethod
|
||||
where getter is not null
|
||||
from property in validatableProperties
|
||||
select Expression.Call(inst0, validateMethod, new Expression[]
|
||||
{
|
||||
Expression.Convert(Expression.Call(inst0, getter), typeof(object)),
|
||||
Expression.Convert(Expression.Call(inst0, property.GetMethod), typeof(object)),
|
||||
Expression.Constant(property.Name)
|
||||
}));
|
||||
|
||||
|
|
|
@ -153,6 +153,20 @@ namespace CommunityToolkit.Mvvm.Messaging
|
|||
// The LINQ codegen bloat is not really important for the same reason.
|
||||
static Action<IMessenger, object, TToken> LoadRegistrationMethodsForTypeFallback(Type recipientType)
|
||||
{
|
||||
// Get the collection of validation methods
|
||||
MethodInfo[] registrationMethods = (
|
||||
from interfaceType in recipientType.GetInterfaces()
|
||||
where interfaceType.IsGenericType &&
|
||||
interfaceType.GetGenericTypeDefinition() == typeof(IRecipient<>)
|
||||
let messageType = interfaceType.GenericTypeArguments[0]
|
||||
select MethodInfos.RegisterIRecipient.MakeGenericMethod(messageType, typeof(TToken))).ToArray();
|
||||
|
||||
// Short path if there are no message handlers to register
|
||||
if (registrationMethods.Length == 0)
|
||||
{
|
||||
return static (_, _, _) => { };
|
||||
}
|
||||
|
||||
// Input parameters (IMessenger instance, non-generic recipient, token)
|
||||
ParameterExpression
|
||||
arg0 = Expression.Parameter(typeof(IMessenger)),
|
||||
|
@ -178,11 +192,7 @@ namespace CommunityToolkit.Mvvm.Messaging
|
|||
// We also add an explicit object conversion to cast the input recipient type to
|
||||
// the actual specific type, so that the exposed message handlers are accessible.
|
||||
BlockExpression body = Expression.Block(
|
||||
from interfaceType in recipientType.GetInterfaces()
|
||||
where interfaceType.IsGenericType &&
|
||||
interfaceType.GetGenericTypeDefinition() == typeof(IRecipient<>)
|
||||
let messageType = interfaceType.GenericTypeArguments[0]
|
||||
let registrationMethod = MethodInfos.RegisterIRecipient.MakeGenericMethod(messageType, typeof(TToken))
|
||||
from registrationMethod in registrationMethods
|
||||
select Expression.Call(registrationMethod, new Expression[]
|
||||
{
|
||||
arg0,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<Border Grid.Column="0">
|
||||
<Border.Background>
|
||||
<media:ImageBlendBrush
|
||||
Source="/SamplePages/DropShadowPanel/Unicorn.png"
|
||||
Source="/SamplePages/Shadows/Unicorn.png"
|
||||
Stretch="@[Unicorn Stretch:Enum:Stretch.None]"
|
||||
Mode="@[Unicorn Blend Mode:Enum:ImageBlendMode.ColorBurn]"
|
||||
/>
|
||||
|
@ -27,7 +27,7 @@
|
|||
<Border Grid.Column="1">
|
||||
<Border.Background>
|
||||
<media:ImageBlendBrush
|
||||
Source="/SamplePages/DropShadowPanel/Trex.png"
|
||||
Source="/SamplePages/Shadows/Trex.png"
|
||||
Stretch="@[Trex Stretch:Enum:Stretch.None]"
|
||||
Mode="@[Trex Blend Mode:Enum:ImageBlendMode.Subtract]"
|
||||
/>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using CommunityToolkit.WinUI.UI;
|
||||
using CommunityToolkit.WinUI.UI.Animations;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Hosting;
|
||||
|
@ -18,6 +19,8 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
|
|||
{
|
||||
private Random _random = new Random();
|
||||
private UIElement _element;
|
||||
private ImplicitAnimationSet _animationSet;
|
||||
private bool _areAnimationsToggled;
|
||||
|
||||
public ImplicitAnimationsPage()
|
||||
{
|
||||
|
@ -28,6 +31,8 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
|
|||
public void OnXamlRendered(FrameworkElement control)
|
||||
{
|
||||
_element = control.FindChild("Element");
|
||||
_animationSet = Implicit.GetAnimations(_element);
|
||||
_areAnimationsToggled = true;
|
||||
}
|
||||
|
||||
private void Load()
|
||||
|
@ -60,6 +65,16 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
|
|||
1);
|
||||
}
|
||||
});
|
||||
|
||||
SampleController.Current.RegisterNewCommand("Toggle animations", (sender, args) =>
|
||||
{
|
||||
if (_element != null)
|
||||
{
|
||||
Implicit.SetAnimations(_element, _areAnimationsToggled ? null : _animationSet);
|
||||
|
||||
_areAnimationsToggled = !_areAnimationsToggled;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
<media:BlurEffect Amount="16"/>
|
||||
<media:ShadeEffect Color="#FF222222" Intensity="0.2"/>
|
||||
<media:BlendEffect Mode="Overlay" Source="{media:TileSource Uri=ms-appx:///Assets/BrushAssets/NoiseTexture.png}"/>
|
||||
<media:BlendEffect Mode="Overlay" Source="{media:ImageSource Uri=ms-appx:///SamplePages/DropShadowPanel/Unicorn.png}"/>
|
||||
<media:BlendEffect Mode="Overlay" Source="{media:ImageSource Uri=ms-appx:///SamplePages/Shadows/Unicorn.png}"/>
|
||||
</media:PipelineBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<media:BlurEffect Amount="16"/>
|
||||
<media:ShadeEffect Color="#FF222222" Intensity="0.2"/>
|
||||
<media:BlendEffect Mode="Overlay" Source="{media:TileSource Uri=ms-appx:///Assets/BrushAssets/NoiseTexture.png}"/>
|
||||
<media:BlendEffect Mode="Overlay" Source="{media:ImageSource Uri=ms-appx:///SamplePages/DropShadowPanel/Unicorn.png}"/>
|
||||
<media:BlendEffect Mode="Overlay" Source="{media:ImageSource Uri=ms-appx:///SamplePages/Shadows/Unicorn.png}"/>
|
||||
</media:PipelineVisualFactory>
|
||||
</media:UIElementExtensions.VisualFactory>
|
||||
</Border>
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace CommunityToolkit.WinUI.UI.Animations
|
|||
|
||||
if (collection is null)
|
||||
{
|
||||
element.SetValue(ShowAnimationsProperty, collection = new());
|
||||
element.SetValue(ShowAnimationsProperty, collection = new ImplicitAnimationSet());
|
||||
}
|
||||
|
||||
return collection;
|
||||
|
@ -80,7 +80,7 @@ namespace CommunityToolkit.WinUI.UI.Animations
|
|||
|
||||
if (collection is null)
|
||||
{
|
||||
element.SetValue(HideAnimationsProperty, collection = new());
|
||||
element.SetValue(HideAnimationsProperty, collection = new ImplicitAnimationSet());
|
||||
}
|
||||
|
||||
return collection;
|
||||
|
@ -107,7 +107,7 @@ namespace CommunityToolkit.WinUI.UI.Animations
|
|||
|
||||
if (collection is null)
|
||||
{
|
||||
element.SetValue(AnimationsProperty, collection = new());
|
||||
element.SetValue(AnimationsProperty, collection = new ImplicitAnimationSet());
|
||||
}
|
||||
|
||||
return collection;
|
||||
|
@ -145,15 +145,21 @@ namespace CommunityToolkit.WinUI.UI.Animations
|
|||
oldCollection.AnimationsChanged -= OnAnimationsChanged;
|
||||
}
|
||||
|
||||
if (d is UIElement element &&
|
||||
e.NewValue is ImplicitAnimationSet collection)
|
||||
if (d is UIElement element)
|
||||
{
|
||||
collection.ParentReference = new(element);
|
||||
collection.AnimationsChanged -= OnAnimationsChanged;
|
||||
collection.AnimationsChanged += OnAnimationsChanged;
|
||||
if (e.NewValue is ImplicitAnimationSet collection)
|
||||
{
|
||||
collection.ParentReference = new(element);
|
||||
collection.AnimationsChanged -= OnAnimationsChanged;
|
||||
collection.AnimationsChanged += OnAnimationsChanged;
|
||||
|
||||
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
|
||||
ElementCompositionPreview.SetImplicitShowAnimation(element, collection.GetCompositionAnimationGroup(element));
|
||||
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
|
||||
ElementCompositionPreview.SetImplicitShowAnimation(element, collection.GetCompositionAnimationGroup(element));
|
||||
}
|
||||
else
|
||||
{
|
||||
ElementCompositionPreview.SetImplicitShowAnimation(element, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,15 +185,21 @@ namespace CommunityToolkit.WinUI.UI.Animations
|
|||
oldCollection.AnimationsChanged -= OnAnimationsChanged;
|
||||
}
|
||||
|
||||
if (d is UIElement element &&
|
||||
e.NewValue is ImplicitAnimationSet collection)
|
||||
if (d is UIElement element)
|
||||
{
|
||||
collection.ParentReference = new(element);
|
||||
collection.AnimationsChanged -= OnAnimationsChanged;
|
||||
collection.AnimationsChanged += OnAnimationsChanged;
|
||||
if (e.NewValue is ImplicitAnimationSet collection)
|
||||
{
|
||||
collection.ParentReference = new(element);
|
||||
collection.AnimationsChanged -= OnAnimationsChanged;
|
||||
collection.AnimationsChanged += OnAnimationsChanged;
|
||||
|
||||
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
|
||||
ElementCompositionPreview.SetImplicitHideAnimation(element, collection.GetCompositionAnimationGroup(element));
|
||||
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
|
||||
ElementCompositionPreview.SetImplicitHideAnimation(element, collection.GetCompositionAnimationGroup(element));
|
||||
}
|
||||
else
|
||||
{
|
||||
ElementCompositionPreview.SetImplicitHideAnimation(element, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,15 +225,21 @@ namespace CommunityToolkit.WinUI.UI.Animations
|
|||
oldCollection.AnimationsChanged -= OnAnimationsChanged;
|
||||
}
|
||||
|
||||
if (d is UIElement element &&
|
||||
e.NewValue is ImplicitAnimationSet collection)
|
||||
if (d is UIElement element)
|
||||
{
|
||||
collection.ParentReference = new(element);
|
||||
collection.AnimationsChanged -= OnAnimationsChanged;
|
||||
collection.AnimationsChanged += OnAnimationsChanged;
|
||||
if (e.NewValue is ImplicitAnimationSet collection)
|
||||
{
|
||||
collection.ParentReference = new(element);
|
||||
collection.AnimationsChanged -= OnAnimationsChanged;
|
||||
collection.AnimationsChanged += OnAnimationsChanged;
|
||||
|
||||
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
|
||||
ElementCompositionPreview.GetElementVisual(element).ImplicitAnimations = collection.GetImplicitAnimationCollection(element);
|
||||
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
|
||||
ElementCompositionPreview.GetElementVisual(element).ImplicitAnimations = collection.GetImplicitAnimationCollection(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
ElementCompositionPreview.GetElementVisual(element).ImplicitAnimations = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace CommunityToolkit.WinUI.UI
|
|||
timer.Tick += Timer_Tick;
|
||||
|
||||
// Store/Update function
|
||||
_debounceInstances.AddOrUpdate(timer, action, (k, v) => v);
|
||||
_debounceInstances.AddOrUpdate(timer, action, (k, v) => action);
|
||||
}
|
||||
|
||||
// Start the timer to keep track of the last call here.
|
||||
|
|
|
@ -12,7 +12,7 @@ using System.Reflection;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
#pragma warning disable SA1124
|
||||
#pragma warning disable SA1124, SA1307, SA1401
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
@ -371,7 +371,7 @@ namespace UnitTests.Mvvm
|
|||
[MinLength(5)]
|
||||
private string? value;
|
||||
}
|
||||
|
||||
|
||||
public partial class ViewModelWithValidatableGeneratedProperties : ObservableValidator
|
||||
{
|
||||
[Required]
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
@ -335,6 +336,54 @@ namespace UnitTests.Mvvm
|
|||
model.Age = -10;
|
||||
|
||||
model.ValidateAllProperties();
|
||||
|
||||
Assert.IsTrue(model.HasErrors);
|
||||
Assert.IsTrue(events.Count == 1);
|
||||
Assert.IsTrue(events.Any(e => e.PropertyName == nameof(Person.Age)));
|
||||
}
|
||||
|
||||
[TestCategory("Mvvm")]
|
||||
[TestMethod]
|
||||
public void Test_ObservableValidator_ValidateAllProperties_WithFallback()
|
||||
{
|
||||
var model = new PersonWithDeferredValidation();
|
||||
var events = new List<DataErrorsChangedEventArgs>();
|
||||
|
||||
MethodInfo[] staticMethods = typeof(ObservableValidator).GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
|
||||
MethodInfo validationMethod = staticMethods.Single(static m => m.Name.Contains("GetValidationActionFallback"));
|
||||
Func<Type, Action<object>> validationFunc = (Func<Type, Action<object>>)validationMethod.CreateDelegate(typeof(Func<Type, Action<object>>));
|
||||
Action<object> validationAction = validationFunc(model.GetType());
|
||||
|
||||
model.ErrorsChanged += (s, e) => events.Add(e);
|
||||
|
||||
validationAction(model);
|
||||
|
||||
Assert.IsTrue(model.HasErrors);
|
||||
Assert.IsTrue(events.Count == 2);
|
||||
|
||||
// Note: we can't use an index here because the order used to return properties
|
||||
// from reflection APIs is an implementation detail and might change at any time.
|
||||
Assert.IsTrue(events.Any(e => e.PropertyName == nameof(Person.Name)));
|
||||
Assert.IsTrue(events.Any(e => e.PropertyName == nameof(Person.Age)));
|
||||
|
||||
events.Clear();
|
||||
|
||||
model.Name = "James";
|
||||
model.Age = 42;
|
||||
|
||||
validationAction(model);
|
||||
|
||||
Assert.IsFalse(model.HasErrors);
|
||||
Assert.IsTrue(events.Count == 2);
|
||||
Assert.IsTrue(events.Any(e => e.PropertyName == nameof(Person.Name)));
|
||||
Assert.IsTrue(events.Any(e => e.PropertyName == nameof(Person.Age)));
|
||||
|
||||
events.Clear();
|
||||
|
||||
model.Age = -10;
|
||||
|
||||
validationAction(model);
|
||||
|
||||
Assert.IsTrue(model.HasErrors);
|
||||
Assert.IsTrue(events.Count == 1);
|
||||
Assert.IsTrue(events.Any(e => e.PropertyName == nameof(Person.Age)));
|
||||
|
@ -414,6 +463,34 @@ namespace UnitTests.Mvvm
|
|||
Assert.AreEqual(allErrors[1].ErrorMessage, $"SECOND: {nameof(ValidationWithDisplayName.AnotherRequiredField)}.");
|
||||
}
|
||||
|
||||
// See: https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4272
|
||||
[TestCategory("Mvvm")]
|
||||
[TestMethod]
|
||||
[DataRow(typeof(MyBase))]
|
||||
[DataRow(typeof(MyDerived2))]
|
||||
public void Test_ObservableRecipient_ValidationOnNonValidatableProperties(Type type)
|
||||
{
|
||||
MyBase viewmodel = (MyBase)Activator.CreateInstance(type);
|
||||
|
||||
viewmodel.ValidateAll();
|
||||
}
|
||||
|
||||
// See: https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4272
|
||||
[TestCategory("Mvvm")]
|
||||
[TestMethod]
|
||||
[DataRow(typeof(MyBase))]
|
||||
[DataRow(typeof(MyDerived2))]
|
||||
public void Test_ObservableRecipient_ValidationOnNonValidatableProperties_WithFallback(Type type)
|
||||
{
|
||||
MyBase viewmodel = (MyBase)Activator.CreateInstance(type);
|
||||
|
||||
MethodInfo[] staticMethods = typeof(ObservableValidator).GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
|
||||
MethodInfo validationMethod = staticMethods.Single(static m => m.Name.Contains("GetValidationActionFallback"));
|
||||
Func<Type, Action<object>> validationFunc = (Func<Type, Action<object>>)validationMethod.CreateDelegate(typeof(Func<Type, Action<object>>));
|
||||
|
||||
validationFunc(viewmodel.GetType())(viewmodel);
|
||||
}
|
||||
|
||||
public class Person : ObservableValidator
|
||||
{
|
||||
private string name;
|
||||
|
@ -631,5 +708,22 @@ namespace UnitTests.Mvvm
|
|||
set => SetProperty(ref this.anotherRequiredField, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
public class MyBase : ObservableValidator
|
||||
{
|
||||
public int? MyDummyInt { get; set; } = 0;
|
||||
|
||||
public void ValidateAll()
|
||||
{
|
||||
ValidateAllProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public class MyDerived2 : MyBase
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public int SomeRandomproperty { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -319,9 +319,9 @@ namespace UnitTests.Mvvm
|
|||
}
|
||||
}";
|
||||
|
||||
// This is explicitly allowed in C# < 9.0, as it doesn't use any new features
|
||||
VerifyGeneratedDiagnostics<ObservableValidatorValidateAllPropertiesGenerator>(
|
||||
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)),
|
||||
"MVVMTK0013");
|
||||
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)));
|
||||
}
|
||||
|
||||
[TestCategory("Mvvm")]
|
||||
|
@ -368,9 +368,9 @@ namespace UnitTests.Mvvm
|
|||
}
|
||||
}";
|
||||
|
||||
// This is explicitly allowed in C# < 9.0, as it doesn't use any new features
|
||||
VerifyGeneratedDiagnostics<IMessengerRegisterAllGenerator>(
|
||||
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)),
|
||||
"MVVMTK0013");
|
||||
CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// 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;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UnitTests.Extensions
|
||||
{
|
||||
[TestClass]
|
||||
public class Test_DispatcherQueueTimerExtensions
|
||||
{
|
||||
[TestCategory("DispatcherQueueTimerExtensions")]
|
||||
[TestMethod]
|
||||
public async Task Test_DispatcherQueueTimerExtensions_Debounce()
|
||||
{
|
||||
var debounceTimer = App.DispatcherQueue.CreateTimer();
|
||||
|
||||
var triggeredCount = 0;
|
||||
string triggeredValue = null;
|
||||
|
||||
var value = "He";
|
||||
debounceTimer.Debounce(
|
||||
() =>
|
||||
{
|
||||
triggeredCount++;
|
||||
triggeredValue = value;
|
||||
},
|
||||
TimeSpan.FromMilliseconds(60));
|
||||
|
||||
var value2 = "Hello";
|
||||
debounceTimer.Debounce(
|
||||
() =>
|
||||
{
|
||||
triggeredCount++;
|
||||
triggeredValue = value2;
|
||||
},
|
||||
TimeSpan.FromMilliseconds(60));
|
||||
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(110));
|
||||
|
||||
Assert.AreEqual(false, debounceTimer.IsRunning, "Expected to stop the timer.");
|
||||
Assert.AreEqual(value2, triggeredValue, "Expected to execute the last action.");
|
||||
Assert.AreEqual(1, triggeredCount, "Expected to postpone execution.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,6 +66,7 @@
|
|||
<Compile Include="Converters\Test_StringFormatConverter.cs" />
|
||||
<Compile Include="Converters\Test_TypeToObjectConverter.cs" />
|
||||
<Compile Include="Extensions\Helpers\ObjectWithNullableBoolProperty.cs" />
|
||||
<Compile Include="Extensions\Test_DispatcherQueueTimerExtensions.cs" />
|
||||
<Compile Include="Extensions\Test_StringExtensions.cs" />
|
||||
<Compile Include="Extensions\Test_UIElementExtensions_Coordinates.cs" />
|
||||
<Compile Include="Extensions\Test_VisualTreeExtensions.cs" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "7.0.3-build.{height}",
|
||||
"version": "7.1.0-build.{height}",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$", // we release out of main
|
||||
"^refs/heads/dev$", // we release out of dev
|
||||
|
@ -20,4 +20,4 @@
|
|||
"versionIncrement" : "build",
|
||||
"firstUnstableTag" : "preview"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче