Merge branch 'master' into jamesmcroft/3506-carousel-automation

This commit is contained in:
James Croft 2021-02-16 16:21:46 +00:00
Родитель c544bb05a5 f9663197c4
Коммит 3b2d965424
887 изменённых файлов: 28605 добавлений и 9895 удалений

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

@ -324,4 +324,7 @@ dotnet_diagnostic.SA1652.severity = none
dotnet_diagnostic.SA1629.severity = none # DocumentationTextMustEndWithAPeriod: Let's enable this rule back when we shift to WinUI3 (v8.x). If we do it now, it would mean more than 400 file changes.
dotnet_diagnostic.SA1413.severity = none # UseTrailingCommasInMultiLineInitializers: This would also mean a lot of changes at the end of all multiline initializers. It's also debatable if we want this or not.
dotnet_diagnostic.SA1314.severity = none # TypeParameterNamesMustBeginWithT: We do have a few templates that don't start with T. We need to double check that changing this is not a breaking change. If not, we can re-enable this.
dotnet_diagnostic.SA1314.severity = none # TypeParameterNamesMustBeginWithT: We do have a few templates that don't start with T. We need to double check that changing this is not a breaking change. If not, we can re-enable this.
dotnet_diagnostic.SA1000.severity = none # Hide warnings when using the new() expression from C# 9.
dotnet_diagnostic.SA1313.severity = none # Hide warnings for record parameters.
dotnet_diagnostic.SA1101.severity = none # Hide warnings when accessing properties without "this".

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

@ -1,19 +1,21 @@
<Project>
<PropertyGroup>
<UseUWP Condition="'$(TargetFramework)' == 'uap10.0' or '$(TargetFramework)' == 'uap10.0.17763' or '$(TargetFramework)' == 'native' or '$(TargetFramework)' == 'net461'">true</UseUWP>
<UseUWP Condition="$(TargetFramework.Contains(`uap10.0`)) or '$(TargetFramework)' == 'net461'">true</UseUWP>
</PropertyGroup>
<Choose>
<When Condition="!$(TargetFramework.Contains(`uap10.0`)) and '$(TargetFramework)' != 'native' and '$(IsSampleProject)' != 'true'">
<!--We'll include signing the Notifications library since we need the DLL signature to match for interop from class libraries to main projects-->
<When Condition="(!$(TargetFramework.Contains(`uap10.0`)) and '$(TargetFramework)' != 'native' and '$(IsSampleProject)' != 'true') or $(MSBuildProjectName) == 'Microsoft.Toolkit.Uwp.Notifications'">
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)toolkit.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
</When>
</Choose>
<Import Project="$(MSBuildThisFileDirectory)build\Windows.Toolkit.Uwp.Build.targets" Condition="'$(UseUWP)' == 'true'"/>
<!--Exclude Notifications project from this since it sets different min versions than what we want for notifications-->
<Import Project="$(MSBuildThisFileDirectory)build\Windows.Toolkit.Uwp.Build.targets" Condition="'$(UseUWP)' == 'true' and $(MSBuildProjectName) != 'Microsoft.Toolkit.Uwp.Notifications'"/>
<Target Name="AddCommitHashToAssemblyAttributes" BeforeTargets="GetAssemblyAttributes">
<ItemGroup>

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

@ -12,7 +12,7 @@
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

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

@ -3026,5 +3026,507 @@ namespace Microsoft.Toolkit.Diagnostics
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must be equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="target">The target <see langword="nint"/> value to test for.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is != <paramref name="target"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsEqualTo(nint value, nint target, string name)
{
if (value == target)
{
return;
}
ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name);
}
/// <summary>
/// Asserts that the input value must be not equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="target">The target <see langword="nint"/> value to test for.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is == <paramref name="target"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotEqualTo(nint value, nint target, string name)
{
if (value != target)
{
return;
}
ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name);
}
/// <summary>
/// Asserts that the input value must be less than a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="maximum">The exclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="maximum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsLessThan(nint value, nint maximum, string name)
{
if (value < maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name);
}
/// <summary>
/// Asserts that the input value must be less than or equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="maximum">The inclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="maximum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsLessThanOrEqualTo(nint value, nint maximum, string name)
{
if (value <= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name);
}
/// <summary>
/// Asserts that the input value must be greater than a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt;= <paramref name="minimum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsGreaterThan(nint value, nint minimum, string name)
{
if (value > minimum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name);
}
/// <summary>
/// Asserts that the input value must be greater than or equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsGreaterThanOrEqualTo(nint value, nint minimum, string name)
{
if (value >= minimum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name);
}
/// <summary>
/// Asserts that the input value must be in a given range.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsInRange(nint value, nint minimum, nint maximum, string name)
{
if (value >= minimum && value < maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must not be in a given range.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or &lt; <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotInRange(nint value, nint minimum, nint maximum, string name)
{
if (value < minimum || value >= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt;= <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsBetween(nint value, nint minimum, nint maximum, string name)
{
if (value > minimum && value < maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must not be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="minimum"/> or &lt; <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> not in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotBetween(nint value, nint minimum, nint maximum, string name)
{
if (value <= minimum || value >= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/> or > <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsBetweenOrEqualTo(nint value, nint minimum, nint maximum, string name)
{
if (value >= minimum && value <= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must not be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nint"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see langword="nint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or &lt;= <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotBetweenOrEqualTo(nint value, nint minimum, nint maximum, string name)
{
if (value < minimum || value > maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must be equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="target">The target <see langword="nuint"/> value to test for.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is != <paramref name="target"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsEqualTo(nuint value, nuint target, string name)
{
if (value == target)
{
return;
}
ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name);
}
/// <summary>
/// Asserts that the input value must be not equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="target">The target <see langword="nuint"/> value to test for.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is == <paramref name="target"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotEqualTo(nuint value, nuint target, string name)
{
if (value != target)
{
return;
}
ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name);
}
/// <summary>
/// Asserts that the input value must be less than a specified value.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="maximum">The exclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="maximum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsLessThan(nuint value, nuint maximum, string name)
{
if (value < maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name);
}
/// <summary>
/// Asserts that the input value must be less than or equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="maximum">The inclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="maximum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsLessThanOrEqualTo(nuint value, nuint maximum, string name)
{
if (value <= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name);
}
/// <summary>
/// Asserts that the input value must be greater than a specified value.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt;= <paramref name="minimum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsGreaterThan(nuint value, nuint minimum, string name)
{
if (value > minimum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name);
}
/// <summary>
/// Asserts that the input value must be greater than or equal to a specified value.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsGreaterThanOrEqualTo(nuint value, nuint minimum, string name)
{
if (value >= minimum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name);
}
/// <summary>
/// Asserts that the input value must be in a given range.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsInRange(nuint value, nuint minimum, nuint maximum, string name)
{
if (value >= minimum && value < maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must not be in a given range.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or &lt; <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotInRange(nuint value, nuint minimum, nuint maximum, string name)
{
if (value < minimum || value >= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt;= <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsBetween(nuint value, nuint minimum, nuint maximum, string name)
{
if (value > minimum && value < maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must not be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="minimum"/> or &lt; <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> not in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotBetween(nuint value, nuint minimum, nuint maximum, string name)
{
if (value <= minimum || value >= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/> or > <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsBetweenOrEqualTo(nuint value, nuint minimum, nuint maximum, string name)
{
if (value >= minimum && value <= maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name);
}
/// <summary>
/// Asserts that the input value must not be in a given interval.
/// </summary>
/// <param name="value">The input <see langword="nuint"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see langword="nuint"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see langword="nuint"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or &lt;= <paramref name="maximum"/>.</exception>
/// <remarks>
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
/// The method is generic to avoid boxing the parameters, if they are value types.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotBetweenOrEqualTo(nuint value, nuint minimum, nuint maximum, string name)
{
if (value < minimum || value > maximum)
{
return;
}
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name);
}
}
}

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

@ -13,14 +13,15 @@ namespace Microsoft.Toolkit.Diagnostics
public static partial class Guard
{
<#
GenerateTextForItems(NumericTypes, type =>
GenerateTextForItems(NumericTypes, typeInfo =>
{
var (type, prefix) = typeInfo;
#>
/// <summary>
/// Asserts that the input value must be equal to a specified value.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="target">The target <see cref="<#=type#>"/> value to test for.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="target">The target <see <#=prefix#>="<#=type#>"/> value to test for.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is != <paramref name="target"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -37,8 +38,8 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be not equal to a specified value.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="target">The target <see cref="<#=type#>"/> value to test for.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="target">The target <see <#=prefix#>="<#=type#>"/> value to test for.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is == <paramref name="target"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
@ -56,8 +57,8 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be less than a specified value.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="maximum">The exclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="maximum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
@ -75,8 +76,8 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be less than or equal to a specified value.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="maximum">The inclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="maximum">The inclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="maximum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
@ -94,8 +95,8 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be greater than a specified value.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt;= <paramref name="minimum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
@ -113,8 +114,8 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be greater than or equal to a specified value.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/>.</exception>
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
@ -132,9 +133,9 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be in a given range.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
/// <remarks>
@ -155,9 +156,9 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must not be in a given range.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or &lt; <paramref name="maximum"/>.</exception>
/// <remarks>
@ -178,9 +179,9 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be in a given interval.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt;= <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
/// <remarks>
@ -201,9 +202,9 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must not be in a given interval.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The exclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="minimum"/> or &lt; <paramref name="maximum"/>.</exception>
/// <remarks>
@ -224,9 +225,9 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must be in a given interval.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is &lt; <paramref name="minimum"/> or > <paramref name="maximum"/>.</exception>
/// <remarks>
@ -247,9 +248,9 @@ GenerateTextForItems(NumericTypes, type =>
/// <summary>
/// Asserts that the input value must not be in a given interval.
/// </summary>
/// <param name="value">The input <see cref="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see cref="<#=type#>"/> value that is accepted.</param>
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="maximum">The inclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or &lt;= <paramref name="maximum"/>.</exception>
/// <remarks>

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

@ -0,0 +1,818 @@
// 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.
// =====================
// Auto generated file
// =====================
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(Span<T> span, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must be empty, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Span<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(Span<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(Span<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(Span<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(Span<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Span<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Span<T> source, Span<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Span<T> source, Span<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, Span<T> span, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(span.Length)} to be a valid index for the target collection ({typeof(Span<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, Span<T> span, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(span.Length)} to be an invalid index for the target collection ({typeof(Span<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(ReadOnlySpan<T> span, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must be empty, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(ReadOnlySpan<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(ReadOnlySpan<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(span.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlySpan<T> source, Span<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlySpan<T> source, Span<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, ReadOnlySpan<T> span, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(span.Length)} to be a valid index for the target collection ({typeof(ReadOnlySpan<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, ReadOnlySpan<T> span, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(span.Length)} to be an invalid index for the target collection ({typeof(ReadOnlySpan<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(Memory<T> memory, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must be empty, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Memory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(Memory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(Memory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(Memory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(Memory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Memory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Memory<T> source, Memory<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Memory<T> source, Memory<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, Memory<T> memory, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(memory.Length)} to be a valid index for the target collection ({typeof(Memory<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, Memory<T> memory, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(memory.Length)} to be an invalid index for the target collection ({typeof(Memory<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(ReadOnlyMemory<T> memory, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must be empty, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(ReadOnlyMemory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(ReadOnlyMemory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(memory.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlyMemory<T> source, Memory<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlyMemory<T> source, Memory<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, ReadOnlyMemory<T> memory, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(memory.Length)} to be a valid index for the target collection ({typeof(ReadOnlyMemory<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, ReadOnlyMemory<T> memory, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(memory.Length)} to be an invalid index for the target collection ({typeof(ReadOnlyMemory<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(T[] array, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must be empty, had a size of {AssertString(array.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(T[] array, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(array.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(T[] array, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(array.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(T[] array, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size over {size}, had a size of {AssertString(array.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(T[] array, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(array.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(T[] array, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(array.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(T[] array, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(array.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(T[] source, T[] destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(T[] source, T[] destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, T[] array, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(array.Length)} to be a valid index for the target collection ({typeof(T[]).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, T[] array, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(array.Length)} to be an invalid index for the target collection ({typeof(T[]).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(List<T> list, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must be empty, had a size of {AssertString(list.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(List<T> list, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(list.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(List<T> list, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(list.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(List<T> list, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(list.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(List<T> list, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(list.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(List<T> list, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(list.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(List<T> list, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(list.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(List<T> source, List<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(List<T> source, List<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, List<T> list, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(list.Count)} to be a valid index for the target collection ({typeof(List<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, List<T> list, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(list.Count)} to be an invalid index for the target collection ({typeof(List<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(ICollection<T> collection, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must be empty, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ICollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(ICollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(ICollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(ICollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(ICollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ICollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ICollection<T> source, ICollection<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ICollection<T> source, ICollection<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, ICollection<T> collection, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(collection.Count)} to be a valid index for the target collection ({typeof(ICollection<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, ICollection<T> collection, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(collection.Count)} to be an invalid index for the target collection ({typeof(ICollection<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(IReadOnlyCollection<T> collection, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must be empty, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(IReadOnlyCollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(IReadOnlyCollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(collection.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(IReadOnlyCollection<T> source, ICollection<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(IReadOnlyCollection<T> source, ICollection<T> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, IReadOnlyCollection<T> collection, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(collection.Count)} to be a valid index for the target collection ({typeof(IReadOnlyCollection<T>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, IReadOnlyCollection<T> collection, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(collection.Count)} to be an invalid index for the target collection ({typeof(IReadOnlyCollection<T>).ToTypeString()}), was {AssertString(index)}");
}
}
}
}

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

@ -0,0 +1,129 @@
// 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.
<#@include file="TypeInfo.ttinclude" #>
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
<#
GenerateTextForItems(EnumerableTypes, item =>
{
#>
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty<T>(<#=item.Type#> <#=item.Name#>, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must be empty, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(<#=item.Type#> <#=item.Name#>, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(<#=item.Type#> <#=item.Name#>, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(<#=item.Type#> <#=item.Name#>, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(<#=item.Type#> <#=item.Name#>, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(<#=item.Type#> <#=item.Name#>, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(<#=item.Type#> <#=item.Name#>, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(<#=item.Type#> source, <#=item.DestinationType#> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size equal to {AssertString(destination.<#=item.Size#>)} (the destination), had a size of {AssertString(source.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(<#=item.Type#> source, <#=item.DestinationType#> destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.<#=item.Size#>)} (the destination), had a size of {AssertString(source.<#=item.Size#>)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, <#=item.Type#> <#=item.Name#>, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(<#=item.Name#>.<#=item.Size#>)} to be a valid index for the target collection ({typeof(<#=item.Type#>).ToTypeString()}), was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, <#=item.Type#> <#=item.Name#>, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(<#=item.Name#>.<#=item.Size#>)} to be an invalid index for the target collection ({typeof(<#=item.Type#>).ToTypeString()}), was {AssertString(index)}");
}
<#
});
#>
}
}
}

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

@ -81,7 +81,23 @@
/// <summary>
/// Gets the list of available numeric types to generate APIs for
/// </summary>
static readonly IReadOnlyList<string> NumericTypes = new[] { "byte", "sbyte", "short", "ushort", "char", "int", "uint", "float", "long", "ulong", "double", "decimal" };
static readonly IReadOnlyList<(string Name, string Prefix)> NumericTypes = new[]
{
("byte", "cref"),
("sbyte", "cref"),
("short", "cref"),
("ushort", "cref"),
("char", "cref"),
("int", "cref"),
("uint", "cref"),
("float", "cref"),
("long", "cref"),
("ulong", "cref"),
("double", "cref"),
("decimal", "cref"),
("nint", "langword"),
("nuint", "langword")
};
/// <summary>
/// Generates text for a given sequence of items, automatically adding the necessary spacing

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

@ -23,18 +23,18 @@ namespace Microsoft.Toolkit.Diagnostics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsCloseTo(int value, int target, uint delta, string name)
{
// Cast to long before calculating the difference to avoid overflows
// when the values are at the two extremes of the supported range.
// Then cast to double to calculate the absolute value: this allows
// the JIT compiler to use AVX instructions on X64 CPUs instead of
// conditional jumps, which results in more efficient assembly code.
// The IEEE 754 specs guarantees that a 32 bit integer value can
// be stored within a double precision floating point value with
// no loss of precision, so the result will always be correct here.
// The difference is then cast to uint as that's the maximum possible
// value it can have, and comparing two 32 bit integer values
// results in shorter and slightly faster code than using doubles.
if ((uint)Math.Abs((double)((long)value - target)) <= delta)
uint difference;
if (value >= target)
{
difference = (uint)(value - target);
}
else
{
difference = (uint)(target - value);
}
if (difference <= delta)
{
return;
}
@ -53,7 +53,18 @@ namespace Microsoft.Toolkit.Diagnostics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotCloseTo(int value, int target, uint delta, string name)
{
if ((uint)Math.Abs((double)((long)value - target)) > delta)
uint difference;
if (value >= target)
{
difference = (uint)(value - target);
}
else
{
difference = (uint)(target - value);
}
if (difference > delta)
{
return;
}
@ -69,12 +80,21 @@ namespace Microsoft.Toolkit.Diagnostics
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) > <paramref name="delta"/>.</exception>
[MethodImpl(MethodImplOptions.NoInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsCloseTo(long value, long target, ulong delta, string name)
{
// This method and the one below are not inlined because
// using the decimal type results in quite a bit of code.
if ((ulong)Math.Abs((decimal)value - target) <= delta)
ulong difference;
if (value >= target)
{
difference = (ulong)(value - target);
}
else
{
difference = (ulong)(target - value);
}
if (difference <= delta)
{
return;
}
@ -90,10 +110,21 @@ namespace Microsoft.Toolkit.Diagnostics
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) &lt;= <paramref name="delta"/>.</exception>
[MethodImpl(MethodImplOptions.NoInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotCloseTo(long value, long target, ulong delta, string name)
{
if ((ulong)Math.Abs((decimal)value - target) > delta)
ulong difference;
if (value >= target)
{
difference = (ulong)(value - target);
}
else
{
difference = (ulong)(target - value);
}
if (difference > delta)
{
return;
}
@ -176,5 +207,65 @@ namespace Microsoft.Toolkit.Diagnostics
ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name);
}
/// <summary>
/// Asserts that the input value must be within a given distance from a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="target">The target <see langword="nint"/> value to test for.</param>
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) > <paramref name="delta"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsCloseTo(nint value, nint target, nuint delta, string name)
{
nuint difference;
if (value >= target)
{
difference = (nuint)(value - target);
}
else
{
difference = (nuint)(target - value);
}
if (difference <= delta)
{
return;
}
ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name);
}
/// <summary>
/// Asserts that the input value must not be within a given distance from a specified value.
/// </summary>
/// <param name="value">The input <see langword="nint"/> value to test.</param>
/// <param name="target">The target <see langword="nint"/> value to test for.</param>
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
/// <param name="name">The name of the input parameter being tested.</param>
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) &lt;= <paramref name="delta"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsNotCloseTo(nint value, nint target, nuint delta, string name)
{
nuint difference;
if (value >= target)
{
difference = (nuint)(value - target);
}
else
{
difference = (nuint)(target - value);
}
if (difference > delta)
{
return;
}
ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name);
}
}
}

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

@ -0,0 +1,54 @@
// 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.Diagnostics.CodeAnalysis;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotEmpty{T}(Span{T},string)"/> fails.
/// </summary>
/// <typeparam name="T">The item of items in the input <see cref="Span{T}"/> instance.</typeparam>
/// <remarks>This method is needed because <see cref="Span{T}"/> can't be used as a generic type parameter.</remarks>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotEmptyWithSpan<T>(string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must not be empty", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotEmpty{T}(ReadOnlySpan{T},string)"/> fails.
/// </summary>
/// <typeparam name="T">The item of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
/// <remarks>This method is needed because <see cref="ReadOnlySpan{T}"/> can't be used as a generic type parameter.</remarks>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan<T>(string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must not be empty", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotEmpty{T}(T[],string)"/> (or an overload) fails.
/// </summary>
/// <typeparam name="T">The item of items in the input collection.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotEmpty<T>(string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be empty", name);
}
}
}
}

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

@ -0,0 +1,175 @@
// 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.Diagnostics.CodeAnalysis;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsDefault{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of <see langword="struct"/> value type being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsDefault<T>(T value, string name)
where T : struct
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the default value {AssertString(default(T))}, was {AssertString(value)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotDefault{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of <see langword="struct"/> value type being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotDefault<T>(string name)
where T : struct
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the default value {AssertString(default(T))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEqualTo<T>(T value, T target, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be equal to {AssertString(target)}, was {AssertString(value)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotEqualTo<T>(T value, T target, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be equal to {AssertString(target)}, was {AssertString(value)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsBitwiseEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of input values being compared.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForBitwiseEqualTo<T>(T value, T target, string name)
where T : unmanaged
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) is not a bitwise match, was <{value.ToHexString()}> instead of <{target.ToHexString()}>", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsLessThan{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsLessThan<T>(T value, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than {AssertString(maximum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsLessThanOrEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo<T>(T value, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than or equal to {AssertString(maximum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsGreaterThan{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThan<T>(T value, T minimum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than {AssertString(minimum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsGreaterThanOrEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo<T>(T value, T minimum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than or equal to {AssertString(minimum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRange{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRange<T>(T value, T minimum, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRange{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRange<T>(T value, T minimum, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsBetween{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsBetween<T>(T value, T minimum, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotBetween{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotBetween<T>(T value, T minimum, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsBetweenOrEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo<T>(T value, T minimum, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotBetweenOrEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of values being tested.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo<T>(T value, T minimum, T maximum, string name)
{
throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}");
}
}
}
}

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

@ -0,0 +1,112 @@
// 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.Diagnostics.CodeAnalysis;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCloseTo(int,int,uint,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCloseTo(int value, int target, uint delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCloseTo(int,int,uint,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCloseTo(int value, int target, uint delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCloseTo(long,long,ulong,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCloseTo(long value, long target, ulong delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCloseTo(long,long,ulong,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCloseTo(long value, long target, ulong delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCloseTo(float,float,float,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCloseTo(float value, float target, float delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCloseTo(float,float,float,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCloseTo(float value, float target, float delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCloseTo(double,double,double,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCloseTo(double value, double target, double delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCloseTo(double,double,double,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCloseTo(double value, double target, double delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCloseTo(nint,nint,nuint,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCloseTo(nint value, nint target, nuint delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCloseTo(nint,nint,nuint,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCloseTo(nint value, nint target, nuint delta, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}", name);
}
}
}
}

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

@ -0,0 +1,59 @@
// 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.Diagnostics.CodeAnalysis;
using System.IO;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.CanRead"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForCanRead(Stream stream, string name)
{
throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support reading", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.CanWrite"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForCanWrite(Stream stream, string name)
{
throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support writing", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.CanSeek"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForCanSeek(Stream stream, string name)
{
throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support seeking", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsAtStartPosition"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsAtStartPosition(Stream stream, string name)
{
throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) must be at position {AssertString(0)}, was at {AssertString(stream.Position)}", name);
}
}
}
}

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

@ -0,0 +1,183 @@
// 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.Diagnostics.CodeAnalysis;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNullOrEmpty"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNullOrEmpty(string? text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must be null or empty, was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotNullOrEmpty"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotNullOrEmpty(string? text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or empty, was {(text is null ? "null" : "empty")}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNullOrWhitespace"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNullOrWhiteSpace(string? text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must be null or whitespace, was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotNullOrWhitespace"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotNullOrWhiteSpace(string? text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or whitespace, was {(text is null ? "null" : "whitespace")}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsEmpty(string text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must be empty, was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotEmpty"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotEmpty(string text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be empty", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsWhitespace"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsWhiteSpace(string text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must be whitespace, was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotWhitespace"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotWhiteSpace(string text, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be whitespace, was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo(string,int,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo(string text, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size equal to {size}, had a size of {text.Length} and was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeNotEqualTo(string text, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must not have a size equal to {size}, was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThan(string text, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size over {size}, had a size of {text.Length} and was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(string text, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size of at least {size}, had a size of {text.Length} and was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThan(string text, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size less than {size}, had a size of {text.Length} and was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo(string,int,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(string text, int size, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size less than or equal to {size}, had a size of {text.Length} and was {AssertString(text)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo(string,string,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeEqualTo(string source, string destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} (string) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo(string,string,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(string source, string destination, string name)
{
throw new ArgumentException($"The source {AssertString(name)} (string) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor(int,string,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, string text, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(text.Length)} to be a valid index for the target string, was {AssertString(index)}");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor(int,string,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, string text, string name)
{
throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(text.Length)} to be an invalid index for the target string, was {AssertString(index)}");
}
}
}
}

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

@ -0,0 +1,113 @@
// 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.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCompleted"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCompleted(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCompleted"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCompleted(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCompletedSuccessfully"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCompletedSuccessfully(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed successfully, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCompletedSuccessfully"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCompletedSuccessfully(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed successfully, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsFaulted"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsFaulted(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be faulted, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotFaulted"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotFaulted(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be faulted, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsCanceled"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsCanceled(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be canceled, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotCanceled"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotCanceled(Task task, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be canceled, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasStatusEqualTo"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasStatusEqualTo(Task task, TaskStatus status, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must have status {status}, had status {AssertString(task.Status)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasStatusNotEqualTo"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForHasStatusNotEqualTo(Task task, TaskStatus status, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not have status {AssertString(status)}", name);
}
}
}
}

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

@ -0,0 +1,205 @@
// 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.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using Microsoft.Toolkit.Extensions;
namespace Microsoft.Toolkit.Diagnostics
{
/// <summary>
/// Helper methods to verify conditions when running code.
/// </summary>
public static partial class Guard
{
/// <summary>
/// Helper methods to efficiently throw exceptions.
/// </summary>
private static partial class ThrowHelper
{
/// <summary>
/// Returns a formatted representation of the input value.
/// </summary>
/// <param name="obj">The input <see cref="object"/> to format.</param>
/// <returns>A formatted representation of <paramref name="obj"/> to display in error messages.</returns>
[Pure]
private static string AssertString(object? obj)
{
return obj switch
{
string _ => $"\"{obj}\"",
null => "null",
_ => $"<{obj}>"
};
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNull{T}(T,string)"/> (where <typeparamref name="T"/> is <see langword="class"/>) fails.
/// </summary>
/// <typeparam name="T">The type of the input value.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNull<T>(T value, string name)
where T : class
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be null, was {AssertString(value)} ({value.GetType().ToTypeString()})", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNull{T}(T,string)"/> (where <typeparamref name="T"/> is <see langword="struct"/>) fails.
/// </summary>
/// <typeparam name="T">The type of the input value.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNull<T>(T? value, string name)
where T : struct
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T?).ToTypeString()}) must be null, was {AssertString(value)} ({typeof(T).ToTypeString()})", name);
}
/// <summary>
/// Throws an <see cref="ArgumentNullException"/> when <see cref="Guard.IsNotNull{T}(T,string)"/> fails.
/// </summary>
/// <typeparam name="T">The type of the input value.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentNullExceptionForIsNotNull<T>(string name)
{
throw new ArgumentNullException(name, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be not null)");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsOfType{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of the input value.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsOfType<T>(object value, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotOfType{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of the input value.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotOfType<T>(object value, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must not be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsOfType"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsOfType(object value, Type type, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotOfType"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotOfType(object value, Type type, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must not be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsAssignableToType{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type being checked against.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsAssignableToType<T>(object value, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotAssignableToType{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type being checked against.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotAssignableToType<T>(object value, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must not be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsAssignableToType"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsAssignableToType(object value, Type type, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsAssignableToType"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsNotAssignableToType(object value, Type type, string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must not be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsReferenceEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of input value being compared.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsReferenceEqualTo<T>(string name)
where T : class
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the same instance as the target object", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsReferenceNotEqualTo{T}"/> fails.
/// </summary>
/// <typeparam name="T">The type of input value being compared.</typeparam>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsReferenceNotEqualTo<T>(string name)
where T : class
{
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the same instance as the target object", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsTrue(bool,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsTrue(string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsTrue(bool,string,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsTrue(string name, string message)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false: {AssertString(message)}", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsFalse(bool,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsFalse(string name)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true", name);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsFalse(bool,string,string)"/> fails.
/// </summary>
[DoesNotReturn]
public static void ThrowArgumentExceptionForIsFalse(string name, string message)
{
throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true: {AssertString(message)}", name);
}
}
}
}

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

@ -0,0 +1,97 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
<LangVersion>9.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<Title>Windows Community Toolkit Diagnostics .NET Standard</Title>
<Description>
This package includes .NET Standard code only helpers such as:
- Guard: Helper methods to verify conditions when running code.
- ThrowHelper: Helper methods to efficiently throw exceptions.
</Description>
<PackageTags>UWP Toolkit Windows IncrementalLoadingCollection String Array extensions helpers</PackageTags>
</PropertyGroup>
<Choose>
<When Condition=" '$(TargetFramework)' == 'netstandard1.4' ">
<ItemGroup>
<!-- .NET Standard 1.4 doesn't have the Span<T> type, ValueTuple or the [Pure] attribute -->
<PackageReference Include="System.Diagnostics.Contracts" Version="4.3.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
</When>
<When Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<ItemGroup>
<!-- .NET Standard 2.0 doesn't have the Span<T> type -->
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
</When>
<When Condition=" '$(TargetFramework)' == 'netstandard2.1' ">
<PropertyGroup>
<DefineConstants>NETSTANDARD2_1_OR_GREATER</DefineConstants>
</PropertyGroup>
<ItemGroup>
<!-- .NET Standard 2.1 doesn't have the Unsafe type -->
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0" />
</ItemGroup>
</When>
<When Condition=" '$(TargetFramework)' == 'net5.0' ">
<PropertyGroup>
<DefineConstants>NETSTANDARD2_1_OR_GREATER</DefineConstants>
</PropertyGroup>
</When>
</Choose>
<ItemGroup>
<None Update="Generated\Guard.Comparable.Numeric.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Guard.Comparable.Numeric.g.cs</LastGenOutput>
</None>
<None Update="Generated\Guard.Collection.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Guard.Collection.g.cs</LastGenOutput>
</None>
<None Update="Generated\ThrowHelper.Collection.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ThrowHelper.Collection.g.cs</LastGenOutput>
</None>
<None Update="Generated\TypeInfo.ttinclude">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>TypeInfo.g.cs</LastGenOutput>
</None>
</ItemGroup>
<!-- T4 service used by the Guard APIs -->
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="Generated\Guard.Comparable.Numeric.g.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Guard.Comparable.Numeric.tt</DependentUpon>
</Compile>
<Compile Update="Generated\Guard.Collection.g.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Guard.Collection.tt</DependentUpon>
</Compile>
<Compile Update="Generated\ThrowHelper.Collection.g.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>ThrowHelper.Collection.tt</DependentUpon>
</Compile>
<Compile Update="Generated\TypeInfo.g.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>TypeInfo.ttinclude</DependentUpon>
</Compile>
</ItemGroup>
</Project>

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

@ -91,7 +91,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
public static MemoryOwner<T> Empty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new MemoryOwner<T>(0, ArrayPool<T>.Shared, AllocationMode.Default);
get => new(0, ArrayPool<T>.Shared, AllocationMode.Default);
}
/// <summary>
@ -103,7 +103,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> Allocate(int size) => new MemoryOwner<T>(size, ArrayPool<T>.Shared, AllocationMode.Default);
public static MemoryOwner<T> Allocate(int size) => new(size, ArrayPool<T>.Shared, AllocationMode.Default);
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the specified parameters.
@ -115,7 +115,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> Allocate(int size, ArrayPool<T> pool) => new MemoryOwner<T>(size, pool, AllocationMode.Default);
public static MemoryOwner<T> Allocate(int size, ArrayPool<T> pool) => new(size, pool, AllocationMode.Default);
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the specified parameters.
@ -127,7 +127,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> Allocate(int size, AllocationMode mode) => new MemoryOwner<T>(size, ArrayPool<T>.Shared, mode);
public static MemoryOwner<T> Allocate(int size, AllocationMode mode) => new(size, ArrayPool<T>.Shared, mode);
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the specified parameters.
@ -140,7 +140,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> Allocate(int size, ArrayPool<T> pool, AllocationMode mode) => new MemoryOwner<T>(size, pool, mode);
public static MemoryOwner<T> Allocate(int size, ArrayPool<T> pool, AllocationMode mode) => new(size, pool, mode);
/// <summary>
/// Gets the number of items in the current instance

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

@ -80,7 +80,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
public static SpanOwner<T> Empty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new SpanOwner<T>(0, ArrayPool<T>.Shared, AllocationMode.Default);
get => new(0, ArrayPool<T>.Shared, AllocationMode.Default);
}
/// <summary>
@ -92,7 +92,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> Allocate(int size) => new SpanOwner<T>(size, ArrayPool<T>.Shared, AllocationMode.Default);
public static SpanOwner<T> Allocate(int size) => new(size, ArrayPool<T>.Shared, AllocationMode.Default);
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the specified parameters.
@ -104,7 +104,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> Allocate(int size, ArrayPool<T> pool) => new SpanOwner<T>(size, pool, AllocationMode.Default);
public static SpanOwner<T> Allocate(int size, ArrayPool<T> pool) => new(size, pool, AllocationMode.Default);
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the specified parameters.
@ -116,7 +116,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> Allocate(int size, AllocationMode mode) => new SpanOwner<T>(size, ArrayPool<T>.Shared, mode);
public static SpanOwner<T> Allocate(int size, AllocationMode mode) => new(size, ArrayPool<T>.Shared, mode);
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the specified parameters.
@ -129,7 +129,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// <remarks>This method is just a proxy for the <see langword="private"/> constructor, for clarity.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> Allocate(int size, ArrayPool<T> pool, AllocationMode mode) => new SpanOwner<T>(size, pool, mode);
public static SpanOwner<T> Allocate(int size, ArrayPool<T> pool, AllocationMode mode) => new(size, pool, mode);
/// <summary>
/// Gets the number of items in the current instance
@ -183,7 +183,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ArraySegment<T> DangerousGetArray()
{
return new ArraySegment<T>(array!, 0, this.length);
return new(array!, 0, this.length);
}
/// <summary>

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

@ -137,7 +137,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
/// process. Since <see cref="StringPool"/> is thread-safe, the shared instance can be used
/// concurrently by multiple threads without the need for manual synchronization.
/// </remarks>
public static StringPool Shared { get; } = new StringPool();
public static StringPool Shared { get; } = new();
/// <summary>
/// Gets the total number of <see cref="string"/> that can be stored in the current instance.

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

@ -10,6 +10,8 @@ using System.Runtime.InteropServices;
#endif
using Microsoft.Toolkit.HighPerformance.Extensions;
using Microsoft.Toolkit.HighPerformance.Helpers.Internals;
using Microsoft.Toolkit.HighPerformance.Memory.Internals;
#if !SPAN_RUNTIME_SUPPORT
using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
#endif
@ -76,6 +78,32 @@ namespace Microsoft.Toolkit.HighPerformance.Enumerables
this.span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(reference), length);
this.step = step;
}
/// <summary>
/// Creates a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
/// <returns>A <see cref="ReadOnlyRefEnumerable{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static ReadOnlyRefEnumerable<T> DangerousCreate(in T value, int length, int step)
{
if (length < 0)
{
ThrowArgumentOutOfRangeExceptionForLength();
}
if (step < 0)
{
ThrowArgumentOutOfRangeExceptionForStep();
}
OverflowHelper.EnsureIsInNativeIntRange(length, 1, step);
return new ReadOnlyRefEnumerable<T>(in value, length, step);
}
#else
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
@ -360,6 +388,22 @@ namespace Microsoft.Toolkit.HighPerformance.Enumerables
}
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the "length" parameter is invalid.
/// </summary>
private static void ThrowArgumentOutOfRangeExceptionForLength()
{
throw new ArgumentOutOfRangeException("length");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the "step" parameter is invalid.
/// </summary>
private static void ThrowArgumentOutOfRangeExceptionForStep()
{
throw new ArgumentOutOfRangeException("step");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when the target span is too short.
/// </summary>

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

@ -10,7 +10,9 @@ using System.Runtime.InteropServices;
#endif
using Microsoft.Toolkit.HighPerformance.Extensions;
using Microsoft.Toolkit.HighPerformance.Helpers.Internals;
#if !SPAN_RUNTIME_SUPPORT
#if SPAN_RUNTIME_SUPPORT
using Microsoft.Toolkit.HighPerformance.Memory.Internals;
#else
using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
#endif
@ -64,6 +66,32 @@ namespace Microsoft.Toolkit.HighPerformance.Enumerables
Span = MemoryMarshal.CreateSpan(ref reference, length);
Step = step;
}
/// <summary>
/// Creates a new instance of the <see cref="RefEnumerable{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
/// <returns>A <see cref="RefEnumerable{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static RefEnumerable<T> DangerousCreate(ref T value, int length, int step)
{
if (length < 0)
{
ThrowArgumentOutOfRangeExceptionForLength();
}
if (step < 0)
{
ThrowArgumentOutOfRangeExceptionForStep();
}
OverflowHelper.EnsureIsInNativeIntRange(length, 1, step);
return new RefEnumerable<T>(ref value, length, step);
}
#else
/// <summary>
/// Initializes a new instance of the <see cref="RefEnumerable{T}"/> struct.
@ -453,6 +481,22 @@ namespace Microsoft.Toolkit.HighPerformance.Enumerables
}
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the "length" parameter is invalid.
/// </summary>
private static void ThrowArgumentOutOfRangeExceptionForLength()
{
throw new ArgumentOutOfRangeException("length");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the "step" parameter is invalid.
/// </summary>
private static void ThrowArgumentOutOfRangeExceptionForStep()
{
throw new ArgumentOutOfRangeException("step");
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> when the target span is too short.
/// </summary>

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

@ -146,7 +146,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanEnumerable<T> Enumerate<T>(this T[] array)
{
return new SpanEnumerable<T>(array);
return new(array);
}
/// <summary>
@ -172,7 +172,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
public static SpanTokenizer<T> Tokenize<T>(this T[] array, T separator)
where T : IEquatable<T>
{
return new SpanTokenizer<T>(array, separator);
return new(array, separator);
}
/// <summary>

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

@ -11,7 +11,6 @@ using Microsoft.Toolkit.HighPerformance.Buffers.Internals;
#endif
using Microsoft.Toolkit.HighPerformance.Enumerables;
using Microsoft.Toolkit.HighPerformance.Helpers.Internals;
using Microsoft.Toolkit.HighPerformance.Memory;
using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
namespace Microsoft.Toolkit.HighPerformance.Extensions
@ -208,7 +207,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this T[,]? array)
{
return new Span2D<T>(array);
return new(array);
}
/// <summary>
@ -232,7 +231,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this T[,]? array, int row, int column, int height, int width)
{
return new Span2D<T>(array, row, column, height, width);
return new(array, row, column, height, width);
}
/// <summary>
@ -245,7 +244,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this T[,]? array)
{
return new Memory2D<T>(array);
return new(array);
}
/// <summary>
@ -269,7 +268,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this T[,]? array, int row, int column, int height, int width)
{
return new Memory2D<T>(array, row, column, height, width);
return new(array, row, column, height, width);
}
#if SPAN_RUNTIME_SUPPORT

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

@ -10,7 +10,6 @@ using System.Runtime.InteropServices;
using Microsoft.Toolkit.HighPerformance.Buffers.Internals;
#endif
using Microsoft.Toolkit.HighPerformance.Helpers.Internals;
using Microsoft.Toolkit.HighPerformance.Memory;
using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
namespace Microsoft.Toolkit.HighPerformance.Extensions
@ -235,7 +234,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this T[,,] array, int depth)
{
return new Span2D<T>(array, depth);
return new(array, depth);
}
/// <summary>
@ -253,7 +252,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this T[,,] array, int depth)
{
return new Memory2D<T>(array, depth);
return new(array, depth);
}
/// <summary>

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

@ -23,7 +23,14 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe byte ToByte(this bool flag)
{
return *(byte*)&flag;
// Whenever we need to take the address of an argument, we make a local copy first.
// This will be removed by the JIT anyway, but it can help produce better codegen and
// remove unwanted stack spills if the caller is using constant arguments. This is
// because taking the address of an argument can interfere with some of the flow
// analysis executed by the JIT, which can in some cases block constant propagation.
bool copy = flag;
return *(byte*)&copy;
}
/// <summary>
@ -58,7 +65,8 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe int ToBitwiseMask32(this bool flag)
{
byte rangeFlag = *(byte*)&flag;
bool copy = flag;
byte rangeFlag = *(byte*)&copy;
int
negativeFlag = rangeFlag - 1,
mask = ~negativeFlag;
@ -77,7 +85,8 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe long ToBitwiseMask64(this bool flag)
{
byte rangeFlag = *(byte*)&flag;
bool copy = flag;
byte rangeFlag = *(byte*)&copy;
long
negativeFlag = (long)rangeFlag - 1,
mask = ~negativeFlag;

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

@ -7,9 +7,6 @@ using System.Diagnostics.Contracts;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if SPAN_RUNTIME_SUPPORT
using Microsoft.Toolkit.HighPerformance.Memory;
#endif
using MemoryStream = Microsoft.Toolkit.HighPerformance.Streams.MemoryStream;
namespace Microsoft.Toolkit.HighPerformance.Extensions
@ -38,7 +35,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this Memory<T> memory, int height, int width)
{
return new Memory2D<T>(memory, height, width);
return new(memory, height, width);
}
/// <summary>
@ -61,7 +58,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this Memory<T> memory, int offset, int height, int width, int pitch)
{
return new Memory2D<T>(memory, offset, height, width, pitch);
return new(memory, offset, height, width, pitch);
}
#endif

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

@ -10,9 +10,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.Toolkit.HighPerformance.Buffers.Internals;
using Microsoft.Toolkit.HighPerformance.Buffers.Internals.Interfaces;
#if SPAN_RUNTIME_SUPPORT
using Microsoft.Toolkit.HighPerformance.Memory;
#endif
using MemoryStream = Microsoft.Toolkit.HighPerformance.Streams.MemoryStream;
namespace Microsoft.Toolkit.HighPerformance.Extensions
@ -41,7 +38,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlyMemory2D<T> AsMemory2D<T>(this ReadOnlyMemory<T> memory, int height, int width)
{
return new ReadOnlyMemory2D<T>(memory, height, width);
return new(memory, height, width);
}
/// <summary>
@ -64,7 +61,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlyMemory2D<T> AsMemory2D<T>(this ReadOnlyMemory<T> memory, int offset, int height, int width, int pitch)
{
return new ReadOnlyMemory2D<T>(memory, offset, height, width, pitch);
return new(memory, offset, height, width, pitch);
}
#endif

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

@ -8,9 +8,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.Toolkit.HighPerformance.Enumerables;
using Microsoft.Toolkit.HighPerformance.Helpers.Internals;
#if SPAN_RUNTIME_SUPPORT
using Microsoft.Toolkit.HighPerformance.Memory;
#endif
namespace Microsoft.Toolkit.HighPerformance.Extensions
{
@ -186,7 +183,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int height, int width)
{
return new ReadOnlySpan2D<T>(span, height, width);
return new(span, height, width);
}
/// <summary>
@ -209,7 +206,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int offset, int height, int width, int pitch)
{
return new ReadOnlySpan2D<T>(span, offset, height, width, pitch);
return new(span, offset, height, width, pitch);
}
#endif
@ -316,7 +313,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpanEnumerable<T> Enumerate<T>(this ReadOnlySpan<T> span)
{
return new ReadOnlySpanEnumerable<T>(span);
return new(span);
}
/// <summary>
@ -342,7 +339,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
public static ReadOnlySpanTokenizer<T> Tokenize<T>(this ReadOnlySpan<T> span, T separator)
where T : IEquatable<T>
{
return new ReadOnlySpanTokenizer<T>(span, separator);
return new(span, separator);
}
/// <summary>

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

@ -8,9 +8,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.Toolkit.HighPerformance.Enumerables;
using Microsoft.Toolkit.HighPerformance.Helpers.Internals;
#if SPAN_RUNTIME_SUPPORT
using Microsoft.Toolkit.HighPerformance.Memory;
#endif
namespace Microsoft.Toolkit.HighPerformance.Extensions
{
@ -88,7 +85,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this Span<T> span, int height, int width)
{
return new Span2D<T>(span, height, width);
return new(span, height, width);
}
/// <summary>
@ -111,7 +108,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this Span<T> span, int offset, int height, int width, int pitch)
{
return new Span2D<T>(span, offset, height, width, pitch);
return new(span, offset, height, width, pitch);
}
#endif
@ -217,7 +214,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanEnumerable<T> Enumerate<T>(this Span<T> span)
{
return new SpanEnumerable<T>(span);
return new(span);
}
/// <summary>
@ -243,7 +240,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
public static SpanTokenizer<T> Tokenize<T>(this Span<T> span, T separator)
where T : IEquatable<T>
{
return new SpanTokenizer<T>(span, separator);
return new(span, separator);
}
/// <summary>

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

@ -32,7 +32,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe UnsafeLock Enter(SpinLock* spinLock)
{
return new UnsafeLock(spinLock);
return new(spinLock);
}
/// <summary>
@ -97,7 +97,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Lock Enter(ref this SpinLock spinLock)
{
return new Lock(ref spinLock);
return new(ref spinLock);
}
#else
/// <summary>
@ -123,7 +123,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Lock Enter(object owner, ref SpinLock spinLock)
{
return new Lock(owner, ref spinLock);
return new(owner, ref spinLock);
}
#endif

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

@ -121,7 +121,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpanEnumerable<char> Enumerate(this string text)
{
return new ReadOnlySpanEnumerable<char>(text.AsSpan());
return new(text.AsSpan());
}
/// <summary>
@ -145,7 +145,7 @@ namespace Microsoft.Toolkit.HighPerformance.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpanTokenizer<char> Tokenize(this string text, char separator)
{
return new ReadOnlySpanTokenizer<char>(text.AsSpan(), separator);
return new(text.AsSpan(), separator);
}
/// <summary>

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

@ -209,8 +209,9 @@ namespace Microsoft.Toolkit.HighPerformance.Helpers
// and perform an OR with the resulting value of the previous
// operation. This will always guaranteed to work, thanks to the
// initial code clearing that bit before setting it again.
bool copy = flag;
uint
flag32 = *(byte*)&flag,
flag32 = *(byte*)&copy,
shift = flag32 << n,
or = and | shift;
@ -378,8 +379,9 @@ namespace Microsoft.Toolkit.HighPerformance.Helpers
ulong
bit = 1ul << n,
not = ~bit,
and = value & not,
flag64 = *(byte*)&flag,
and = value & not;
bool copy = flag;
ulong flag64 = *(byte*)&copy,
shift = flag64 << n,
or = and | shift;

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

@ -5,7 +5,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.Toolkit.HighPerformance.Memory;
namespace Microsoft.Toolkit.HighPerformance.Helpers
{

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

@ -5,7 +5,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.Toolkit.HighPerformance.Memory;
namespace Microsoft.Toolkit.HighPerformance.Helpers
{

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

@ -19,7 +19,7 @@ using static Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
#pragma warning disable CA2231
namespace Microsoft.Toolkit.HighPerformance.Memory
namespace Microsoft.Toolkit.HighPerformance
{
/// <summary>
/// <see cref="Memory2D{T}"/> represents a 2D region of arbitrary memory. It is to <see cref="Span2D{T}"/>
@ -894,12 +894,12 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// <inheritdoc/>
public override string ToString()
{
return $"Microsoft.Toolkit.HighPerformance.Memory.Memory2D<{typeof(T)}>[{this.height}, {this.width}]";
return $"Microsoft.Toolkit.HighPerformance.Memory2D<{typeof(T)}>[{this.height}, {this.width}]";
}
/// <summary>
/// Defines an implicit conversion of an array to a <see cref="Memory2D{T}"/>
/// </summary>
public static implicit operator Memory2D<T>(T[,]? array) => new Memory2D<T>(array);
public static implicit operator Memory2D<T>(T[,]? array) => new(array);
}
}

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

@ -19,7 +19,7 @@ using static Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
#pragma warning disable CA2231
namespace Microsoft.Toolkit.HighPerformance.Memory
namespace Microsoft.Toolkit.HighPerformance
{
/// <summary>
/// A readonly version of <see cref="Memory2D{T}"/>.
@ -625,14 +625,14 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
ref T r0 = ref memoryManager.GetSpan().DangerousGetReference();
ref T r1 = ref Unsafe.Add(ref r0, this.offset);
return new ReadOnlySpan2D<T>(r1, this.height, this.width, this.pitch);
return new ReadOnlySpan2D<T>(in r1, this.height, this.width, this.pitch);
}
else
{
// This handles both arrays and strings
ref T r0 = ref this.instance.DangerousGetObjectDataReferenceAt<T>(this.offset);
return new ReadOnlySpan2D<T>(r0, this.height, this.width, this.pitch);
return new ReadOnlySpan2D<T>(in r0, this.height, this.width, this.pitch);
}
#else
return new ReadOnlySpan2D<T>(this.instance, this.offset, this.height, this.width, this.pitch);
@ -907,13 +907,13 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// <inheritdoc/>
public override string ToString()
{
return $"Microsoft.Toolkit.HighPerformance.Memory.ReadOnlyMemory2D<{typeof(T)}>[{this.height}, {this.width}]";
return $"Microsoft.Toolkit.HighPerformance.ReadOnlyMemory2D<{typeof(T)}>[{this.height}, {this.width}]";
}
/// <summary>
/// Defines an implicit conversion of an array to a <see cref="ReadOnlyMemory2D{T}"/>
/// </summary>
public static implicit operator ReadOnlyMemory2D<T>(T[,]? array) => new ReadOnlyMemory2D<T>(array);
public static implicit operator ReadOnlyMemory2D<T>(T[,]? array) => new(array);
/// <summary>
/// Defines an implicit conversion of a <see cref="Memory2D{T}"/> to a <see cref="ReadOnlyMemory2D{T}"/>

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

@ -13,7 +13,7 @@ using System.Runtime.InteropServices;
using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
#endif
namespace Microsoft.Toolkit.HighPerformance.Memory
namespace Microsoft.Toolkit.HighPerformance
{
/// <inheritdoc cref="ReadOnlySpan2D{T}"/>
public readonly ref partial struct ReadOnlySpan2D<T>
@ -38,7 +38,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
ref T r1 = ref Unsafe.Add(ref r0, startIndex);
#if SPAN_RUNTIME_SUPPORT
return new ReadOnlyRefEnumerable<T>(r1, Width, 1);
return new ReadOnlyRefEnumerable<T>(in r1, Width, 1);
#else
IntPtr offset = RuntimeHelpers.GetObjectDataOrReferenceByteOffset(this.instance, ref r1);
@ -65,7 +65,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
ref T r1 = ref Unsafe.Add(ref r0, (nint)(uint)column);
#if SPAN_RUNTIME_SUPPORT
return new ReadOnlyRefEnumerable<T>(r1, Height, this.stride);
return new ReadOnlyRefEnumerable<T>(in r1, Height, this.stride);
#else
IntPtr offset = RuntimeHelpers.GetObjectDataOrReferenceByteOffset(this.instance, ref r1);
@ -81,7 +81,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// </returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() => new Enumerator(this);
public Enumerator GetEnumerator() => new(this);
/// <summary>
/// Provides an enumerator for the elements of a <see cref="ReadOnlySpan2D{T}"/> instance.

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

@ -17,7 +17,7 @@ using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.Runti
#pragma warning disable CS0809, CA1065
namespace Microsoft.Toolkit.HighPerformance.Memory
namespace Microsoft.Toolkit.HighPerformance
{
/// <summary>
/// A readonly version of <see cref="Span2D{T}"/>.
@ -478,7 +478,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
return new ReadOnlySpan2D<T>(value, height, width, pitch);
return new ReadOnlySpan2D<T>(in value, height, width, pitch);
}
#endif
@ -837,7 +837,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
#if SPAN_RUNTIME_SUPPORT
ref T r0 = ref this.span.DangerousGetReferenceAt(shift);
return new ReadOnlySpan2D<T>(r0, height, width, pitch);
return new ReadOnlySpan2D<T>(in r0, height, width, pitch);
#else
IntPtr offset = this.offset + (shift * (nint)(uint)Unsafe.SizeOf<T>());
@ -974,7 +974,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// <inheritdoc/>
public override string ToString()
{
return $"Microsoft.Toolkit.HighPerformance.Memory.ReadOnlySpan2D<{typeof(T)}>[{Height}, {this.width}]";
return $"Microsoft.Toolkit.HighPerformance.ReadOnlySpan2D<{typeof(T)}>[{Height}, {this.width}]";
}
/// <summary>
@ -1012,7 +1012,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// Implicily converts a given 2D array into a <see cref="ReadOnlySpan2D{T}"/> instance.
/// </summary>
/// <param name="array">The input 2D array to convert.</param>
public static implicit operator ReadOnlySpan2D<T>(T[,]? array) => new ReadOnlySpan2D<T>(array);
public static implicit operator ReadOnlySpan2D<T>(T[,]? array) => new(array);
/// <summary>
/// Implicily converts a given <see cref="Span2D{T}"/> into a <see cref="ReadOnlySpan2D{T}"/> instance.
@ -1021,7 +1021,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
public static implicit operator ReadOnlySpan2D<T>(Span2D<T> span)
{
#if SPAN_RUNTIME_SUPPORT
return new ReadOnlySpan2D<T>(span.DangerousGetReference(), span.Height, span.Width, span.Stride - span.Width);
return new ReadOnlySpan2D<T>(in span.DangerousGetReference(), span.Height, span.Width, span.Stride - span.Width);
#else
return new ReadOnlySpan2D<T>(span.Instance!, span.Offset, span.Height, span.Width, span.Stride - span.Width);
#endif

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

@ -13,7 +13,7 @@ using System.Runtime.InteropServices;
using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
#endif
namespace Microsoft.Toolkit.HighPerformance.Memory
namespace Microsoft.Toolkit.HighPerformance
{
/// <inheritdoc cref="Span2D{T}"/>
public readonly ref partial struct Span2D<T>
@ -81,7 +81,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// </returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() => new Enumerator(this);
public Enumerator GetEnumerator() => new(this);
/// <summary>
/// Provides an enumerator for the elements of a <see cref="Span2D{T}"/> instance.

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

@ -17,7 +17,7 @@ using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.Runti
#pragma warning disable CS0809, CA1065
namespace Microsoft.Toolkit.HighPerformance.Memory
namespace Microsoft.Toolkit.HighPerformance
{
/// <summary>
/// <see cref="Span2D{T}"/> represents a 2D region of arbitrary memory. Like the <see cref="Span{T}"/> type,
@ -1130,7 +1130,7 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// <inheritdoc/>
public override string ToString()
{
return $"Microsoft.Toolkit.HighPerformance.Memory.Span2D<{typeof(T)}>[{Height}, {this.width}]";
return $"Microsoft.Toolkit.HighPerformance.Span2D<{typeof(T)}>[{Height}, {this.width}]";
}
/// <summary>
@ -1168,6 +1168,6 @@ namespace Microsoft.Toolkit.HighPerformance.Memory
/// Implicily converts a given 2D array into a <see cref="Span2D{T}"/> instance.
/// </summary>
/// <param name="array">The input 2D array to convert.</param>
public static implicit operator Span2D<T>(T[,]? array) => new Span2D<T>(array);
public static implicit operator Span2D<T>(T[,]? array) => new(array);
}
}

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

@ -92,7 +92,7 @@ namespace Microsoft.Toolkit.HighPerformance
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(Ref<T> reference)
{
return new NullableReadOnlyRef<T>(reference.Span);
return new(reference.Span);
}
/// <summary>
@ -102,7 +102,7 @@ namespace Microsoft.Toolkit.HighPerformance
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(ReadOnlyRef<T> reference)
{
return new NullableReadOnlyRef<T>(reference.Span);
return new(reference.Span);
}
/// <summary>
@ -112,7 +112,7 @@ namespace Microsoft.Toolkit.HighPerformance
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(NullableRef<T> reference)
{
return new NullableReadOnlyRef<T>(reference.Span);
return new(reference.Span);
}
/// <summary>

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

@ -96,7 +96,7 @@ namespace Microsoft.Toolkit.HighPerformance
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableRef<T>(Ref<T> reference)
{
return new NullableRef<T>(reference.Span);
return new(reference.Span);
}
/// <summary>

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

@ -42,7 +42,7 @@ namespace Microsoft.Toolkit.HighPerformance
/// <param name="pointer">The pointer to the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ReadOnlyRef(void* pointer)
: this(Unsafe.AsRef<T>(pointer))
: this(in Unsafe.AsRef<T>(pointer))
{
}
@ -62,7 +62,7 @@ namespace Microsoft.Toolkit.HighPerformance
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlyRef<T>(Ref<T> reference)
{
return new ReadOnlyRef<T>(reference.Value);
return new(in reference.Value);
}
#else
/// <summary>
@ -117,7 +117,7 @@ namespace Microsoft.Toolkit.HighPerformance
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlyRef<T>(Ref<T> reference)
{
return new ReadOnlyRef<T>(reference.Owner, reference.Offset);
return new(reference.Owner, reference.Offset);
}
#endif

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

@ -50,7 +50,7 @@ namespace Microsoft.Toolkit.HighPerformance.Streams
public static ArrayOwner Empty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new ArrayOwner(Array.Empty<byte>(), 0, 0);
get => new(Array.Empty<byte>(), 0, 0);
}
/// <inheritdoc/>

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

@ -340,7 +340,7 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
// instance. This will result in no further allocations after the first time this method is called for a given
// generic type. We only pay the cost of the virtual call to the delegate, but this is not performance critical
// code and that overhead would still be much lower than the rest of the method anyway, so that's fine.
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier(), newValue, _ => { }, propertyName);
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, static _ => { }, propertyName);
}
/// <summary>
@ -362,7 +362,7 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
/// </remarks>
protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier, Task? newValue, Action<Task?> callback, [CallerMemberName] string? propertyName = null)
{
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier(), newValue, callback, propertyName);
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
}
/// <summary>
@ -401,7 +401,7 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
/// </remarks>
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, [CallerMemberName] string? propertyName = null)
{
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier<T>(), newValue, _ => { }, propertyName);
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, static _ => { }, propertyName);
}
/// <summary>
@ -424,7 +424,7 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
/// </remarks>
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, Action<Task<T>?> callback, [CallerMemberName] string? propertyName = null)
{
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier<T>(), newValue, callback, propertyName);
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
}
/// <summary>

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

@ -116,7 +116,7 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
/// </remarks>
protected virtual void Broadcast<T>(T oldValue, T newValue, string? propertyName)
{
var message = new PropertyChangedMessage<T>(this, propertyName, oldValue, newValue);
PropertyChangedMessage<T> message = new(this, propertyName, oldValue, newValue);
Messenger.Send(message);
}

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

@ -9,6 +9,8 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Microsoft.Toolkit.Mvvm.ComponentModel
@ -19,15 +21,25 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
/// </summary>
public abstract class ObservableValidator : ObservableObject, INotifyDataErrorInfo
{
/// <summary>
/// The <see cref="ConditionalWeakTable{TKey,TValue}"/> instance used to track compiled delegates to validate entities.
/// </summary>
private static readonly ConditionalWeakTable<Type, Action<object>> EntityValidatorMap = new();
/// <summary>
/// The cached <see cref="PropertyChangedEventArgs"/> for <see cref="HasErrors"/>.
/// </summary>
private static readonly PropertyChangedEventArgs HasErrorsChangedEventArgs = new PropertyChangedEventArgs(nameof(HasErrors));
private static readonly PropertyChangedEventArgs HasErrorsChangedEventArgs = new(nameof(HasErrors));
/// <summary>
/// The <see cref="ValidationContext"/> instance currenty in use.
/// </summary>
private readonly ValidationContext validationContext;
/// <summary>
/// The <see cref="Dictionary{TKey,TValue}"/> instance used to store previous validation results.
/// </summary>
private readonly Dictionary<string, List<ValidationResult>> errors = new Dictionary<string, List<ValidationResult>>();
private readonly Dictionary<string, List<ValidationResult>> errors = new();
/// <summary>
/// Indicates the total number of properties with errors (not total errors).
@ -39,6 +51,59 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
/// <inheritdoc/>
public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;
/// <summary>
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
/// This constructor will create a new <see cref="ValidationContext"/> that will
/// be used to validate all properties, which will reference the current instance
/// and no additional services or validation properties and settings.
/// </summary>
protected ObservableValidator()
{
this.validationContext = new ValidationContext(this);
}
/// <summary>
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
/// This constructor will create a new <see cref="ValidationContext"/> that will
/// be used to validate all properties, which will reference the current instance.
/// </summary>
/// <param name="items">A set of key/value pairs to make available to consumers.</param>
protected ObservableValidator(IDictionary<object, object?> items)
{
this.validationContext = new ValidationContext(this, items);
}
/// <summary>
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
/// This constructor will create a new <see cref="ValidationContext"/> that will
/// be used to validate all properties, which will reference the current instance.
/// </summary>
/// <param name="serviceProvider">An <see cref="IServiceProvider"/> instance to make available during validation.</param>
/// <param name="items">A set of key/value pairs to make available to consumers.</param>
protected ObservableValidator(IServiceProvider serviceProvider, IDictionary<object, object?> items)
{
this.validationContext = new ValidationContext(this, serviceProvider, items);
}
/// <summary>
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
/// This constructor will store the input <see cref="ValidationContext"/> instance,
/// and it will use it to validate all properties for the current viewmodel.
/// </summary>
/// <param name="validationContext">
/// The <see cref="ValidationContext"/> instance to use to validate properties.
/// <para>
/// This instance will be passed to all <see cref="Validator.TryValidateObject(object, ValidationContext, ICollection{ValidationResult})"/>
/// calls executed by the current viewmodel, and its <see cref="ValidationContext.MemberName"/> property will be updated every time
/// before the call is made to set the name of the property being validated. The property name will not be reset after that, so the
/// value of <see cref="ValidationContext.MemberName"/> will always indicate the name of the last property that was validated, if any.
/// </para>
/// </param>
protected ObservableValidator(ValidationContext validationContext)
{
this.validationContext = validationContext;
}
/// <inheritdoc/>
public bool HasErrors => this.totalErrors > 0;
@ -326,18 +391,46 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
SetProperty(oldValue, newValue, comparer, model, callback, propertyName);
}
/// <inheritdoc/>
[Pure]
public IEnumerable GetErrors(string? propertyName)
/// <summary>
/// Clears the validation errors for a specified property or for the entire entity.
/// </summary>
/// <param name="propertyName">
/// The name of the property to clear validation errors for.
/// If a <see langword="null"/> or empty name is used, all entity-level errors will be cleared.
/// </param>
protected void ClearErrors(string? propertyName = null)
{
// Entity-level errors when the target property is null or empty
// Clear entity-level errors when the target property is null or empty
if (string.IsNullOrEmpty(propertyName))
{
return this.GetAllErrors();
ClearAllErrors();
}
else
{
ClearErrorsForProperty(propertyName!);
}
}
/// <inheritdoc cref="INotifyDataErrorInfo.GetErrors(string)"/>
[Pure]
public IEnumerable<ValidationResult> GetErrors(string? propertyName = null)
{
// Get entity-level errors when the target property is null or empty
if (string.IsNullOrEmpty(propertyName))
{
// Local function to gather all the entity-level errors
[Pure]
[MethodImpl(MethodImplOptions.NoInlining)]
IEnumerable<ValidationResult> GetAllErrors()
{
return this.errors.Values.SelectMany(static errors => errors);
}
return GetAllErrors();
}
// Property-level errors, if any
if (this.errors.TryGetValue(propertyName!, out List<ValidationResult> errors))
if (this.errors.TryGetValue(propertyName!, out List<ValidationResult>? errors))
{
return errors;
}
@ -350,24 +443,75 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
return Array.Empty<ValidationResult>();
}
/// <summary>
/// Implements the logic for entity-level errors gathering for <see cref="GetErrors"/>.
/// </summary>
/// <returns>An <see cref="IEnumerable"/> instance with all the errors in <see cref="errors"/>.</returns>
/// <inheritdoc/>
[Pure]
[MethodImpl(MethodImplOptions.NoInlining)]
private IEnumerable GetAllErrors()
IEnumerable INotifyDataErrorInfo.GetErrors(string? propertyName) => GetErrors(propertyName);
/// <summary>
/// Validates all the properties in the current instance and updates all the tracked errors.
/// If any changes are detected, the <see cref="ErrorsChanged"/> event will be raised.
/// </summary>
/// <remarks>
/// Only public instance properties (excluding custom indexers) that have at least one
/// <see cref="ValidationAttribute"/> applied to them will be validated. All other
/// members in the current instance will be ignored. None of the processed properties
/// will be modified - they will only be used to retrieve their values and validate them.
/// </remarks>
protected void ValidateAllProperties()
{
return this.errors.Values.SelectMany(errors => errors);
static Action<object> GetValidationAction(Type type)
{
// MyViewModel inst0 = (MyViewModel)arg0;
ParameterExpression arg0 = Expression.Parameter(typeof(object));
UnaryExpression inst0 = Expression.Convert(arg0, type);
// Get a reference to ValidateProperty(object, string)
MethodInfo validateMethod = typeof(ObservableValidator).GetMethod(nameof(ValidateProperty), BindingFlags.Instance | BindingFlags.NonPublic)!;
// We want a single compiled LINQ expression that validates all properties in the
// actual type of the executing viewmodel at once. We do this by creating a block
// expression with the unrolled invocations of all properties to validate.
// Essentially, the body will contain the following code:
// ===============================================================================
// {
// inst0.ValidateProperty(inst0.Property0, nameof(MyViewModel.Property0));
// inst0.ValidateProperty(inst0.Property1, nameof(MyViewModel.Property1));
// ...
// }
// ===============================================================================
// We also add an explicit object conversion to represent boxing, if a given property
// is a value type. It will just be a no-op if the value is a reference type already.
// Note that this generated code is technically accessing a protected method from
// 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
select Expression.Call(inst0, validateMethod, new Expression[]
{
Expression.Convert(Expression.Call(inst0, getter), typeof(object)),
Expression.Constant(property.Name)
}));
return Expression.Lambda<Action<object>>(body, arg0).Compile();
}
// Get or compute the cached list of properties to validate. Here we're using a static lambda to ensure the
// delegate is cached by the C# compiler, see the related issue at https://github.com/dotnet/roslyn/issues/5835.
EntityValidatorMap.GetValue(GetType(), static t => GetValidationAction(t))(this);
}
/// <summary>
/// Validates a property with a specified name and a given input value.
/// If any changes are detected, the <see cref="ErrorsChanged"/> event will be raised.
/// </summary>
/// <param name="value">The value to test for the specified property.</param>
/// <param name="propertyName">The name of the property to validate.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="propertyName"/> is <see langword="null"/>.</exception>
private void ValidateProperty(object? value, string? propertyName)
protected void ValidateProperty(object? value, [CallerMemberName] string? propertyName = null)
{
if (propertyName is null)
{
@ -380,7 +524,7 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
// If the property isn't present in the dictionary, add it now to avoid allocations.
if (!this.errors.TryGetValue(propertyName!, out List<ValidationResult>? propertyErrors))
{
propertyErrors = new List<ValidationResult>();
propertyErrors = new();
this.errors.Add(propertyName!, propertyErrors);
}
@ -396,10 +540,9 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
}
// Validate the property, by adding new errors to the existing list
bool isValid = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null) { MemberName = propertyName },
propertyErrors);
this.validationContext.MemberName = propertyName;
bool isValid = Validator.TryValidateProperty(value, this.validationContext, propertyErrors);
// Update the shared counter for the number of errors, and raise the
// property changed event if necessary. We decrement the number of total
@ -457,20 +600,19 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
// Add the cached errors list for later use.
if (!this.errors.TryGetValue(propertyName!, out List<ValidationResult>? propertyErrors))
{
propertyErrors = new List<ValidationResult>();
propertyErrors = new();
this.errors.Add(propertyName!, propertyErrors);
}
bool hasErrors = propertyErrors.Count > 0;
List<ValidationResult> localErrors = new List<ValidationResult>();
List<ValidationResult> localErrors = new();
// Validate the property, by adding new errors to the local list
bool isValid = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null) { MemberName = propertyName },
localErrors);
this.validationContext.MemberName = propertyName;
bool isValid = Validator.TryValidateProperty(value, this.validationContext, localErrors);
// We only modify the state if the property is valid and it wasn't so before. In this case, we
// clear the cached list of errors (which is visible to consumers) and raise the necessary events.
@ -493,6 +635,59 @@ namespace Microsoft.Toolkit.Mvvm.ComponentModel
return isValid;
}
/// <summary>
/// Clears all the current errors for the entire entity.
/// </summary>
private void ClearAllErrors()
{
if (this.totalErrors == 0)
{
return;
}
// Clear the errors for all properties with at least one error, and raise the
// ErrorsChanged event for those properties. Other properties will be ignored.
foreach (var propertyInfo in this.errors)
{
bool hasErrors = propertyInfo.Value.Count > 0;
propertyInfo.Value.Clear();
if (hasErrors)
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyInfo.Key));
}
}
this.totalErrors = 0;
OnPropertyChanged(HasErrorsChangedEventArgs);
}
/// <summary>
/// Clears all the current errors for a target property.
/// </summary>
/// <param name="propertyName">The name of the property to clear errors for.</param>
private void ClearErrorsForProperty(string propertyName)
{
if (!this.errors.TryGetValue(propertyName!, out List<ValidationResult>? propertyErrors) ||
propertyErrors.Count == 0)
{
return;
}
propertyErrors.Clear();
this.totalErrors--;
if (this.totalErrors == 0)
{
OnPropertyChanged(HasErrorsChangedEventArgs);
}
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}
#pragma warning disable SA1204
/// <summary>
/// Throws an <see cref="ArgumentNullException"/> when a property name given as input is <see langword="null"/>.

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

@ -47,7 +47,7 @@ namespace Microsoft.Toolkit.Mvvm.DependencyInjection
/// <summary>
/// Gets the default <see cref="Ioc"/> instance.
/// </summary>
public static Ioc Default { get; } = new Ioc();
public static Ioc Default { get; } = new();
/// <summary>
/// The <see cref="IServiceProvider"/> instance to use, if initialized.
@ -134,7 +134,7 @@ namespace Microsoft.Toolkit.Mvvm.DependencyInjection
{
IServiceProvider? oldServices = Interlocked.CompareExchange(ref this.serviceProvider, serviceProvider, null);
if (!(oldServices is null))
if (oldServices is not null)
{
ThrowInvalidOperationExceptionForRepeatedConfiguration();
}

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

@ -22,17 +22,17 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <summary>
/// The cached <see cref="PropertyChangedEventArgs"/> for <see cref="CanBeCanceled"/>.
/// </summary>
internal static readonly PropertyChangedEventArgs CanBeCanceledChangedEventArgs = new PropertyChangedEventArgs(nameof(CanBeCanceled));
internal static readonly PropertyChangedEventArgs CanBeCanceledChangedEventArgs = new(nameof(CanBeCanceled));
/// <summary>
/// The cached <see cref="PropertyChangedEventArgs"/> for <see cref="IsCancellationRequested"/>.
/// </summary>
internal static readonly PropertyChangedEventArgs IsCancellationRequestedChangedEventArgs = new PropertyChangedEventArgs(nameof(IsCancellationRequested));
internal static readonly PropertyChangedEventArgs IsCancellationRequestedChangedEventArgs = new(nameof(IsCancellationRequested));
/// <summary>
/// The cached <see cref="PropertyChangedEventArgs"/> for <see cref="IsRunning"/>.
/// </summary>
internal static readonly PropertyChangedEventArgs IsRunningChangedEventArgs = new PropertyChangedEventArgs(nameof(IsRunning));
internal static readonly PropertyChangedEventArgs IsRunningChangedEventArgs = new(nameof(IsRunning));
/// <summary>
/// The <see cref="Func{TResult}"/> to invoke when <see cref="Execute"/> is used.
@ -122,7 +122,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
}
/// <inheritdoc/>
public bool CanBeCanceled => !(this.cancelableExecute is null) && IsRunning;
public bool CanBeCanceled => this.cancelableExecute is not null && IsRunning;
/// <inheritdoc/>
public bool IsCancellationRequested => this.cancellationTokenSource?.IsCancellationRequested == true;
@ -155,7 +155,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
if (CanExecute(parameter))
{
// Non cancelable command delegate
if (!(this.execute is null))
if (this.execute is not null)
{
return ExecutionTask = this.execute();
}
@ -163,7 +163,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
// Cancel the previous operation, if one is pending
this.cancellationTokenSource?.Cancel();
var cancellationTokenSource = this.cancellationTokenSource = new CancellationTokenSource();
CancellationTokenSource cancellationTokenSource = this.cancellationTokenSource = new();
OnPropertyChanged(IsCancellationRequestedChangedEventArgs);

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

@ -19,17 +19,17 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <summary>
/// The <see cref="Func{TResult}"/> to invoke when <see cref="Execute(T)"/> is used.
/// </summary>
private readonly Func<T, Task>? execute;
private readonly Func<T?, Task>? execute;
/// <summary>
/// The cancelable <see cref="Func{T1,T2,TResult}"/> to invoke when <see cref="Execute(object?)"/> is used.
/// </summary>
private readonly Func<T, CancellationToken, Task>? cancelableExecute;
private readonly Func<T?, CancellationToken, Task>? cancelableExecute;
/// <summary>
/// The optional action to invoke when <see cref="CanExecute(T)"/> is used.
/// </summary>
private readonly Func<T, bool>? canExecute;
private readonly Predicate<T?>? canExecute;
/// <summary>
/// The <see cref="CancellationTokenSource"/> instance to use to cancel <see cref="cancelableExecute"/>.
@ -44,7 +44,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <remarks>See notes in <see cref="RelayCommand{T}(Action{T})"/>.</remarks>
public AsyncRelayCommand(Func<T, Task> execute)
public AsyncRelayCommand(Func<T?, Task> execute)
{
this.execute = execute;
}
@ -54,7 +54,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// </summary>
/// <param name="cancelableExecute">The cancelable execution logic.</param>
/// <remarks>See notes in <see cref="RelayCommand{T}(Action{T})"/>.</remarks>
public AsyncRelayCommand(Func<T, CancellationToken, Task> cancelableExecute)
public AsyncRelayCommand(Func<T?, CancellationToken, Task> cancelableExecute)
{
this.cancelableExecute = cancelableExecute;
}
@ -65,7 +65,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
/// <remarks>See notes in <see cref="RelayCommand{T}(Action{T})"/>.</remarks>
public AsyncRelayCommand(Func<T, Task> execute, Func<T, bool> canExecute)
public AsyncRelayCommand(Func<T?, Task> execute, Predicate<T?> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
@ -77,7 +77,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <param name="cancelableExecute">The cancelable execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
/// <remarks>See notes in <see cref="RelayCommand{T}(Action{T})"/>.</remarks>
public AsyncRelayCommand(Func<T, CancellationToken, Task> cancelableExecute, Func<T, bool> canExecute)
public AsyncRelayCommand(Func<T?, CancellationToken, Task> cancelableExecute, Predicate<T?> canExecute)
{
this.cancelableExecute = cancelableExecute;
this.canExecute = canExecute;
@ -106,7 +106,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
}
/// <inheritdoc/>
public bool CanBeCanceled => !(this.cancelableExecute is null) && IsRunning;
public bool CanBeCanceled => this.cancelableExecute is not null && IsRunning;
/// <inheritdoc/>
public bool IsCancellationRequested => this.cancellationTokenSource?.IsCancellationRequested == true;
@ -122,7 +122,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanExecute(T parameter)
public bool CanExecute(T? parameter)
{
return this.canExecute?.Invoke(parameter) != false;
}
@ -131,19 +131,18 @@ namespace Microsoft.Toolkit.Mvvm.Input
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanExecute(object? parameter)
{
if (typeof(T).IsValueType &&
parameter is null &&
this.canExecute is null)
if (default(T) is not null &&
parameter is null)
{
return true;
return false;
}
return CanExecute((T)parameter!);
return CanExecute((T?)parameter);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute(T parameter)
public void Execute(T? parameter)
{
ExecuteAsync(parameter);
}
@ -151,16 +150,16 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <inheritdoc/>
public void Execute(object? parameter)
{
ExecuteAsync((T)parameter!);
ExecuteAsync((T?)parameter);
}
/// <inheritdoc/>
public Task ExecuteAsync(T parameter)
public Task ExecuteAsync(T? parameter)
{
if (CanExecute(parameter))
{
// Non cancelable command delegate
if (!(this.execute is null))
if (this.execute is not null)
{
return ExecutionTask = this.execute(parameter);
}
@ -168,7 +167,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
// Cancel the previous operation, if one is pending
this.cancellationTokenSource?.Cancel();
var cancellationTokenSource = this.cancellationTokenSource = new CancellationTokenSource();
CancellationTokenSource cancellationTokenSource = this.cancellationTokenSource = new();
OnPropertyChanged(AsyncRelayCommand.IsCancellationRequestedChangedEventArgs);
@ -182,7 +181,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <inheritdoc/>
public Task ExecuteAsync(object? parameter)
{
return ExecuteAsync((T)parameter!);
return ExecuteAsync((T?)parameter);
}
/// <inheritdoc/>

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

@ -18,6 +18,6 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// </summary>
/// <param name="parameter">The input parameter.</param>
/// <returns>The <see cref="Task"/> representing the async operation being executed.</returns>
Task ExecuteAsync(T parameter);
Task ExecuteAsync(T? parameter);
}
}

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

@ -18,13 +18,13 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <param name="parameter">The input parameter.</param>
/// <returns>Whether or not the current command can be executed.</returns>
/// <remarks>Use this overload to avoid boxing, if <typeparamref name="T"/> is a value type.</remarks>
bool CanExecute(T parameter);
bool CanExecute(T? parameter);
/// <summary>
/// Provides a strongly-typed variant of <see cref="ICommand.Execute(object)"/>.
/// </summary>
/// <param name="parameter">The input parameter.</param>
/// <remarks>Use this overload to avoid boxing, if <typeparamref name="T"/> is a value type.</remarks>
void Execute(T parameter);
void Execute(T? parameter);
}
}

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

@ -24,12 +24,12 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <summary>
/// The <see cref="Action"/> to invoke when <see cref="Execute(T)"/> is used.
/// </summary>
private readonly Action<T> execute;
private readonly Action<T?> execute;
/// <summary>
/// The optional action to invoke when <see cref="CanExecute(T)"/> is used.
/// </summary>
private readonly Func<T, bool>? canExecute;
private readonly Predicate<T?>? canExecute;
/// <inheritdoc/>
public event EventHandler? CanExecuteChanged;
@ -43,7 +43,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// nullable <see cref="object"/> parameter, it is recommended that if <typeparamref name="T"/> is a reference type,
/// you should always declare it as nullable, and to always perform checks within <paramref name="execute"/>.
/// </remarks>
public RelayCommand(Action<T> execute)
public RelayCommand(Action<T?> execute)
{
this.execute = execute;
}
@ -54,7 +54,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
/// <remarks>See notes in <see cref="RelayCommand{T}(Action{T})"/>.</remarks>
public RelayCommand(Action<T> execute, Func<T, bool> canExecute)
public RelayCommand(Action<T?> execute, Predicate<T?> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
@ -68,7 +68,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanExecute(T parameter)
public bool CanExecute(T? parameter)
{
return this.canExecute?.Invoke(parameter) != false;
}
@ -76,19 +76,18 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <inheritdoc/>
public bool CanExecute(object? parameter)
{
if (typeof(T).IsValueType &&
parameter is null &&
this.canExecute is null)
if (default(T) is not null &&
parameter is null)
{
return true;
return false;
}
return CanExecute((T)parameter!);
return CanExecute((T?)parameter);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute(T parameter)
public void Execute(T? parameter)
{
if (CanExecute(parameter))
{
@ -99,7 +98,7 @@ namespace Microsoft.Toolkit.Mvvm.Input
/// <inheritdoc/>
public void Execute(object? parameter)
{
Execute((T)parameter!);
Execute((T?)parameter);
}
}
}

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

@ -47,8 +47,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
/// <summary>
/// The <see cref="ConditionalWeakTable{TKey,TValue}"/> instance used to track the preloaded registration actions for each recipient.
/// </summary>
public static readonly ConditionalWeakTable<Type, Action<IMessenger, object, TToken>[]> RegistrationMethods
= new ConditionalWeakTable<Type, Action<IMessenger, object, TToken>[]>();
public static readonly ConditionalWeakTable<Type, Action<IMessenger, object, TToken>[]> RegistrationMethods = new();
}
/// <summary>
@ -139,7 +138,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
// For more info on this, see the related issue at https://github.com/dotnet/roslyn/issues/5835.
Action<IMessenger, object, TToken>[] registrationActions = DiscoveredRecipients<TToken>.RegistrationMethods.GetValue(
recipient.GetType(),
t => LoadRegistrationMethodsForType(t));
static t => LoadRegistrationMethodsForType(t));
foreach (Action<IMessenger, object, TToken> registrationAction in registrationActions)
{
@ -158,7 +157,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
public static void Register<TMessage>(this IMessenger messenger, IRecipient<TMessage> recipient)
where TMessage : class
{
messenger.Register<IRecipient<TMessage>, TMessage, Unit>(recipient, default, (r, m) => r.Receive(m));
messenger.Register<IRecipient<TMessage>, TMessage, Unit>(recipient, default, static (r, m) => r.Receive(m));
}
/// <summary>
@ -175,7 +174,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
where TMessage : class
where TToken : IEquatable<TToken>
{
messenger.Register<IRecipient<TMessage>, TMessage, TToken>(recipient, token, (r, m) => r.Receive(m));
messenger.Register<IRecipient<TMessage>, TMessage, TToken>(recipient, token, static (r, m) => r.Receive(m));
}
/// <summary>

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

@ -334,7 +334,7 @@ namespace Microsoft.Collections.Extensions
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() => new Enumerator(this);
public Enumerator GetEnumerator() => new(this);
/// <summary>
/// Enumerator for <see cref="DictionarySlim{TKey,TValue}"/>.

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

@ -22,13 +22,13 @@ namespace Microsoft.Toolkit.Mvvm.Messaging.Messages
/// operations that can be executed in parallel, or <see cref="Func{T,TResult}"/> instances, which can be used so that multiple
/// asynchronous operations are only started sequentially from <see cref="GetAsyncEnumerator"/> and do not overlap in time.
/// </summary>
private readonly List<(Task<T>?, Func<CancellationToken, Task<T>>?)> responses = new List<(Task<T>?, Func<CancellationToken, Task<T>>?)>();
private readonly List<(Task<T>?, Func<CancellationToken, Task<T>>?)> responses = new();
/// <summary>
/// The <see cref="CancellationTokenSource"/> instance used to link the token passed to
/// <see cref="GetAsyncEnumerator"/> and the one passed to all subscribers to the message.
/// </summary>
private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private readonly CancellationTokenSource cancellationTokenSource = new();
/// <summary>
/// Gets the <see cref="System.Threading.CancellationToken"/> instance that will be linked to the
@ -102,7 +102,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging.Messages
cancellationToken.Register(this.cancellationTokenSource.Cancel);
}
List<T> results = new List<T>(this.responses.Count);
List<T> results = new(this.responses.Count);
await foreach (var response in this.WithCancellation(cancellationToken))
{
@ -129,7 +129,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging.Messages
yield break;
}
if (!(task is null))
if (task is not null)
{
yield return await task.ConfigureAwait(false);
}

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

@ -16,7 +16,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging.Messages
/// <typeparam name="T">The type of request to make.</typeparam>
public class CollectionRequestMessage<T> : IEnumerable<T>
{
private readonly List<T> responses = new List<T>();
private readonly List<T> responses = new();
/// <summary>
/// Gets the message responses.

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

@ -71,7 +71,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
/// so that all the existing handlers can be removed without having to dynamically create
/// the generic types for the containers of the various dictionaries mapping the handlers.
/// </remarks>
private readonly DictionarySlim<Recipient, HashSet<IMapping>> recipientsMap = new DictionarySlim<Recipient, HashSet<IMapping>>();
private readonly DictionarySlim<Recipient, HashSet<IMapping>> recipientsMap = new();
/// <summary>
/// The <see cref="Mapping{TMessage,TToken}"/> instance for types combination.
@ -81,12 +81,12 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
/// Each method relies on <see cref="GetOrAddMapping{TMessage,TToken}"/> to get the type-safe instance
/// of the <see cref="Mapping{TMessage,TToken}"/> class for each pair of generic arguments in use.
/// </remarks>
private readonly DictionarySlim<Type2, IMapping> typesMap = new DictionarySlim<Type2, IMapping>();
private readonly DictionarySlim<Type2, IMapping> typesMap = new();
/// <summary>
/// Gets the default <see cref="StrongReferenceMessenger"/> instance.
/// </summary>
public static StrongReferenceMessenger Default { get; } = new StrongReferenceMessenger();
public static StrongReferenceMessenger Default { get; } = new();
/// <inheritdoc/>
public bool IsRegistered<TMessage, TToken>(object recipient, TToken token)
@ -100,7 +100,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
return false;
}
var key = new Recipient(recipient);
Recipient key = new(recipient);
return mapping!.ContainsKey(key);
}
@ -116,7 +116,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
{
// Get the <TMessage, TToken> registration list for this recipient
Mapping<TMessage, TToken> mapping = GetOrAddMapping<TMessage, TToken>();
var key = new Recipient(recipient);
Recipient key = new(recipient);
ref DictionarySlim<TToken, object>? map = ref mapping.GetOrAddValueRef(key);
map ??= new DictionarySlim<TToken, object>();
@ -124,7 +124,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
// Add the new registration entry
ref object? registeredHandler = ref map.GetOrAddValueRef(token);
if (!(registeredHandler is null))
if (registeredHandler is not null)
{
ThrowInvalidOperationExceptionForDuplicateRegistration();
}
@ -147,7 +147,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
lock (this.recipientsMap)
{
// If the recipient has no registered messages at all, ignore
var key = new Recipient(recipient);
Recipient key = new(recipient);
if (!this.recipientsMap.TryGetValue(key, out HashSet<IMapping>? set))
{
@ -196,7 +196,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
Monitor.Enter(this.recipientsMap, ref lockTaken);
// Get the shared set of mappings for the recipient, if present
var key = new Recipient(recipient);
Recipient key = new(recipient);
if (!this.recipientsMap.TryGetValue(key, out HashSet<IMapping>? set))
{
@ -273,7 +273,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
// Remove references to avoid leaks coming from the shared memory pool.
// We manually create a span and clear it as a small optimization, as
// arrays rented from the pool can be larger than the requested size.
if (!(maps is null))
if (maps is not null)
{
maps.AsSpan(0, i).Clear();
@ -295,7 +295,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
return;
}
var key = new Recipient(recipient);
Recipient key = new(recipient);
if (!mapping!.TryGetValue(key, out DictionarySlim<TToken, object>? dictionary))
{
@ -443,7 +443,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
where TMessage : class
where TToken : IEquatable<TToken>
{
var key = new Type2(typeof(TMessage), typeof(TToken));
Type2 key = new(typeof(TMessage), typeof(TToken));
if (this.typesMap.TryGetValue(key, out IMapping? target))
{
@ -472,7 +472,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
where TMessage : class
where TToken : IEquatable<TToken>
{
var key = new Type2(typeof(TMessage), typeof(TToken));
Type2 key = new(typeof(TMessage), typeof(TToken));
ref IMapping? target = ref this.typesMap.GetOrAddValueRef(key);
target ??= new Mapping<TMessage, TToken>();

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

@ -46,12 +46,12 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
/// <summary>
/// The map of currently registered recipients for all message types.
/// </summary>
private readonly DictionarySlim<Type2, RecipientsTable> recipientsMap = new DictionarySlim<Type2, RecipientsTable>();
private readonly DictionarySlim<Type2, RecipientsTable> recipientsMap = new();
/// <summary>
/// Gets the default <see cref="WeakReferenceMessenger"/> instance.
/// </summary>
public static WeakReferenceMessenger Default { get; } = new WeakReferenceMessenger();
public static WeakReferenceMessenger Default { get; } = new();
/// <inheritdoc/>
public bool IsRegistered<TMessage, TToken>(object recipient, TToken token)
@ -60,14 +60,14 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
{
lock (this.recipientsMap)
{
Type2 type2 = new Type2(typeof(TMessage), typeof(TToken));
Type2 type2 = new(typeof(TMessage), typeof(TToken));
// Get the conditional table associated with the target recipient, for the current pair
// of token and message types. If it exists, check if there is a matching token.
return
this.recipientsMap.TryGetValue(type2, out RecipientsTable? table) &&
table!.TryGetValue(recipient, out IDictionarySlim? mapping) &&
Unsafe.As<DictionarySlim<TToken, object>>(mapping).ContainsKey(token);
Unsafe.As<DictionarySlim<TToken, object>>(mapping)!.ContainsKey(token);
}
}
@ -79,7 +79,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
{
lock (this.recipientsMap)
{
Type2 type2 = new Type2(typeof(TMessage), typeof(TToken));
Type2 type2 = new(typeof(TMessage), typeof(TToken));
// Get the conditional table for the pair of type arguments, or create it if it doesn't exist
ref RecipientsTable? mapping = ref this.recipientsMap.GetOrAddValueRef(type2);
@ -87,12 +87,12 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
mapping ??= new RecipientsTable();
// Get or create the handlers dictionary for the target recipient
var map = Unsafe.As<DictionarySlim<TToken, object>>(mapping.GetValue(recipient, _ => new DictionarySlim<TToken, object>()));
var map = Unsafe.As<DictionarySlim<TToken, object>>(mapping.GetValue(recipient, static _ => new DictionarySlim<TToken, object>()));
// Add the new registration entry
ref object? registeredHandler = ref map.GetOrAddValueRef(token);
if (!(registeredHandler is null))
if (registeredHandler is not null)
{
ThrowInvalidOperationExceptionForDuplicateRegistration();
}
@ -133,9 +133,9 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
while (enumerator.MoveNext())
{
if (enumerator.Key.TToken == typeof(TToken) &&
enumerator.Value.TryGetValue(recipient, out IDictionarySlim mapping))
enumerator.Value.TryGetValue(recipient, out IDictionarySlim? mapping))
{
Unsafe.As<DictionarySlim<TToken, object>>(mapping).TryRemove(token, out _);
Unsafe.As<DictionarySlim<TToken, object>>(mapping)!.TryRemove(token, out _);
}
}
}
@ -148,7 +148,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
{
lock (this.recipientsMap)
{
var type2 = new Type2(typeof(TMessage), typeof(TToken));
Type2 type2 = new(typeof(TMessage), typeof(TToken));
var enumerator = this.recipientsMap.GetEnumerator();
// Traverse all the existing token and message pairs matching the current type
@ -156,9 +156,9 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
while (enumerator.MoveNext())
{
if (enumerator.Key.Equals(type2) &&
enumerator.Value.TryGetValue(recipient, out IDictionarySlim mapping))
enumerator.Value.TryGetValue(recipient, out IDictionarySlim? mapping))
{
Unsafe.As<DictionarySlim<TToken, object>>(mapping).TryRemove(token, out _);
Unsafe.As<DictionarySlim<TToken, object>>(mapping)!.TryRemove(token, out _);
}
}
}
@ -174,7 +174,7 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
lock (this.recipientsMap)
{
Type2 type2 = new Type2(typeof(TMessage), typeof(TToken));
Type2 type2 = new(typeof(TMessage), typeof(TToken));
// Try to get the target table
if (!this.recipientsMap.TryGetValue(type2, out RecipientsTable? table))
@ -302,25 +302,16 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
/// <summary>
/// The underlying <see cref="System.Runtime.CompilerServices.ConditionalWeakTable{TKey,TValue}"/> instance.
/// </summary>
private readonly System.Runtime.CompilerServices.ConditionalWeakTable<TKey, TValue> table;
private readonly System.Runtime.CompilerServices.ConditionalWeakTable<TKey, TValue> table = new();
/// <summary>
/// A supporting linked list to store keys in <see cref="table"/>. This is needed to expose
/// the ability to enumerate existing keys when there is no support for that in the BCL.
/// </summary>
private readonly LinkedList<WeakReference<TKey>> keys;
/// <summary>
/// Initializes a new instance of the <see cref="ConditionalWeakTable{TKey, TValue}"/> class.
/// </summary>
public ConditionalWeakTable()
{
this.table = new System.Runtime.CompilerServices.ConditionalWeakTable<TKey, TValue>();
this.keys = new LinkedList<WeakReference<TKey>>();
}
private readonly LinkedList<WeakReference<TKey>> keys = new();
/// <inheritdoc cref="System.Runtime.CompilerServices.ConditionalWeakTable{TKey,TValue}.TryGetValue"/>
public bool TryGetValue(TKey key, out TValue value)
public bool TryGetValue(TKey key, out TValue? value)
{
return this.table.TryGetValue(key, out value);
}
@ -355,25 +346,92 @@ namespace Microsoft.Toolkit.Mvvm.Messaging
}
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
for (LinkedListNode<WeakReference<TKey>>? node = this.keys.First; !(node is null);)
{
LinkedListNode<WeakReference<TKey>>? next = node.Next;
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() => new(this);
// Get the key and value for the current node
if (node.Value.TryGetTarget(out TKey? target) &&
this.table.TryGetValue(target!, out TValue value))
/// <summary>
/// A custom enumerator that traverses items in a <see cref="ConditionalWeakTable{TKey, TValue}"/> instance.
/// </summary>
public ref struct Enumerator
{
/// <summary>
/// The owner <see cref="ConditionalWeakTable{TKey, TValue}"/> instance for the enumerator.
/// </summary>
private readonly ConditionalWeakTable<TKey, TValue> owner;
/// <summary>
/// The current <see cref="LinkedListNode{T}"/>, if any.
/// </summary>
private LinkedListNode<WeakReference<TKey>>? node;
/// <summary>
/// The current <see cref="KeyValuePair{TKey, TValue}"/> to return.
/// </summary>
private KeyValuePair<TKey, TValue> current;
/// <summary>
/// Indicates whether or not <see cref="MoveNext"/> has been called at least once.
/// </summary>
private bool isFirstMoveNextPending;
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
/// </summary>
/// <param name="owner">The owner <see cref="ConditionalWeakTable{TKey, TValue}"/> instance for the enumerator.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(ConditionalWeakTable<TKey, TValue> owner)
{
this.owner = owner;
this.node = null;
this.current = default;
this.isFirstMoveNextPending = true;
}
/// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
public bool MoveNext()
{
LinkedListNode<WeakReference<TKey>>? node;
if (!isFirstMoveNextPending)
{
yield return new KeyValuePair<TKey, TValue>(target, value);
node = this.node!.Next;
}
else
{
// If the current key has been collected, trim the list
this.keys.Remove(node);
node = this.owner.keys.First;
this.isFirstMoveNextPending = false;
}
node = next;
while (node is not null)
{
// Get the key and value for the current node
if (node.Value.TryGetTarget(out TKey? target) &&
this.owner.table.TryGetValue(target!, out TValue? value))
{
this.node = node;
this.current = new KeyValuePair<TKey, TValue>(target, value);
return true;
}
else
{
// If the current key has been collected, trim the list
this.owner.keys.Remove(node);
}
node = node.Next;
}
return false;
}
/// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
public readonly KeyValuePair<TKey, TValue> Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.current;
}
}
}

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

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<LangVersion>8.0</LangVersion>
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
<LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Title>Windows Community Toolkit MVVM Toolkit</Title>
@ -10,8 +10,11 @@
This package includes a .NET Standard MVVM library with helpers such as:
- ObservableObject: a base class for objects implementing the INotifyPropertyChanged interface.
- ObservableRecipient: a base class for observable objects with support for the IMessenger service.
- ObservableValidator: a base class for objects implementing the INotifyDataErrorInfo interface.
- RelayCommand: a simple delegate command implementing the ICommand interface.
- Messenger: a messaging system to exchange messages through different loosely-coupled objects.
- AsyncRelayCommand: a delegate command supporting asynchronous operations and cancellation.
- WeakReferenceMessenger: a messaging system to exchange messages through different loosely-coupled objects.
- StrongReferenceMessenger: a high-performance messaging system that trades weak references for speed.
- Ioc: a helper class to configure dependency injection service containers.
</Description>
<PackageTags>UWP Toolkit Windows MVVM MVVMToolkit observable Ioc dependency injection services extensions helpers</PackageTags>
@ -19,17 +22,15 @@
<!-- .NET Standard 2.0 doesn't have the Span<T> and IAsyncEnumerable<T> types -->
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="1.1.1" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
<!-- .NET Standard 2.1 doesn't have the Unsafe type -->
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.1' ">
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0" />
</ItemGroup>
</Project>

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

@ -1,22 +1,10 @@
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<!--<TargetFrameworks>netstandard1.4;uap10.0;native;net461;netcoreapp3.1</TargetFrameworks>-->
<!-- Removed 'native' target to unblock CI on VS 16.8, tied to changes breaking workaround for https://github.com/NuGet/Home/issues/5154 -->
<TargetFrameworks>netstandard1.4;uap10.0;net461;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>netstandard1.4;uap10.0.19041;net461;netcoreapp3.1;net5.0;net5.0-windows10.0.17763.0;native</TargetFrameworks>
<DefineConstants>$(DefineConstants);NETFX_CORE</DefineConstants>
<Title>Windows Community Toolkit Notifications</Title>
<Description>
Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense.
Adds Support for adaptive tiles and adaptive/interactive toasts for Windows 10. It is part of the Windows Community Toolkit.
Supports C# and C++ UWP project types.
Also works with C# portable class libraries and non-UWP C# projects like server projects.
This project contains outputs for netstandard1.4, uap10.0 and native for WinRT.
</Description>
<PackageTags>notifications win10 windows 10 tile tiles toast toasts badge xml uwp c# csharp c++</PackageTags>
<ExtrasImplicitPlatformPackageIsPrivate Condition=" '$(TargetFramework)' == 'native' ">true</ExtrasImplicitPlatformPackageIsPrivate>
<DefaultTargetPlatformMinVersion>10240</DefaultTargetPlatformMinVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<NuspecFile>Microsoft.Toolkit.Uwp.Notifications.nuspec</NuspecFile>
</PropertyGroup>
<Choose>
@ -27,16 +15,17 @@
<!--Reference Windows SDK NuGet of correct target platform version-->
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />
</ItemGroup>
<PropertyGroup>
<!--Define the WINDOWS_UWP conditional symbol, since the Windows.Data.Xml and the Windows.UI.Notification namespaces are available-->
<DefineConstants>$(DefineConstants);WINDOWS_UWP;WIN32</DefineConstants>
</PropertyGroup>
</When>
</Choose>
<PropertyGroup Condition="'$(TargetFramework)'=='net461' or '$(TargetFramework)'=='netcoreapp3.1' or '$(TargetFramework)'=='net5.0-windows10.0.17763.0'">
<!--Define the WINDOWS_UWP conditional symbol, since the Windows.Data.Xml and the Windows.UI.Notification namespaces are available-->
<DefineConstants>$(DefineConstants);WINDOWS_UWP;WIN32</DefineConstants>
</PropertyGroup>
<!--NET Core desktop apps also need the Registry NuGet package and System.Reflection.Emit for generating COM class dynamically-->
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp3.1' or '$(TargetFramework)'=='net5.0-windows10.0.17763.0'">
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
@ -46,6 +35,11 @@
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="$(ExtrasUwpMetaPackageVersion)" PrivateAssets="all" IsImplicitlyDefined="true" />
</ItemGroup>
<!-- In order to support .NET Native, we need to include an appropriate .rd.xml for UWP (remove from everything else) -->
<ItemGroup Condition="'$(TargetFramework)' != 'uap10.0.19041' and '$(TargetFramework)' != 'native'">
<EmbeddedResource Remove="Properties\Microsoft.Toolkit.Uwp.Notifications.rd.xml" />
</ItemGroup>
<ItemGroup>
<None Include="Microsoft.Toolkit.Uwp.Notifications.targets" Pack="true" PackagePath="build\native" />
</ItemGroup>
@ -54,6 +48,12 @@
<ItemGroup Condition=" '$(TargetFramework)' != 'native' ">
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0.19041'">
<TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion>
<DefaultTargetPlatformMinVersion>16299</DefaultTargetPlatformMinVersion>
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'native'">
<OutputType>winmdobj</OutputType>
@ -63,8 +63,9 @@
<NugetTargetMoniker Condition="'$(DesignTimeBuild)' == 'true'">native</NugetTargetMoniker>
<NugetTargetMoniker Condition="'$(DesignTimeBuild)' != 'true'">UAP,Version=v10.0</NugetTargetMoniker>
<PackageTargetFallback>uap10.0</PackageTargetFallback>
<TargetPlatformVersion Condition="'$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion Condition="'$(TargetPlatformMinVersion)' == '' ">10.0.10240.0</TargetPlatformMinVersion>
<TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion>
<DefaultTargetPlatformMinVersion>10240</DefaultTargetPlatformMinVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<DefineConstants Condition="'$(DisableImplicitFrameworkDefines)' != 'true'">$(DefineConstants);NETFX_CORE;WINDOWS_UWP;WINRT</DefineConstants>
<CopyLocalLockFileAssemblies Condition="'$(CopyLocalLockFileAssemblies)' == ''">false</CopyLocalLockFileAssemblies>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
@ -76,5 +77,12 @@
<ImplicitFrameworkDefine Condition="'$(DisableImplicitFrameworkDefines)' != 'true'">UAP$(TargetPlatformMinVersion.Replace('.', '_'))</ImplicitFrameworkDefine>
<DisableImplicitFrameworkDefines Condition="'$(DisableImplicitFrameworkDefines)' != 'true'">true</DisableImplicitFrameworkDefines>
</PropertyGroup>
<!--Set the nuspec properties. Dependent on version which isn't updated till after GetBuildVersion. Condition ensures we only set once since this runs multiple times for each target.-->
<Target Name="SetNuspecProperties" AfterTargets="GetBuildVersion">
<PropertyGroup Condition="'$(NuspecProperties)' == ''">
<NuspecProperties>buildOutput=bin\$(Configuration);version=$(Version)</NuspecProperties>
</PropertyGroup>
</Target>
</Project>

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

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Microsoft.Toolkit.Uwp.Notifications</id>
<version>$version$</version>
<title>Windows Community Toolkit Notifications</title>
<authors>Microsoft.Toolkit,dotnetfoundation</authors>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<licenseUrl>https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/license.md</licenseUrl>
<projectUrl>https://github.com/windows-toolkit/WindowsCommunityToolkit</projectUrl>
<iconUrl>https://raw.githubusercontent.com/windows-toolkit/WindowsCommunityToolkit/master/build/nuget.png</iconUrl>
<description>The official way to send toast notifications on Windows 10 via code rather than XML, with the help of IntelliSense. Supports all C# app types, including WPF, UWP, WinForms, and Console, even without packaging your app as MSIX. Also supports C++ UWP apps.
Additionally, generate notification payloads from your ASP.NET web server to send as push notifications, or generate notification payloads from class libraries.
For UWP/MSIX apps, you can also generate tile and badge notifications.</description>
<releaseNotes>https://github.com/windows-toolkit/WindowsCommunityToolkit/releases</releaseNotes>
<copyright>(c) .NET Foundation and Contributors. All rights reserved.</copyright>
<tags>notifications win10 windows 10 tile tiles toast toasts badge xml uwp c# csharp c++ wpf winforms</tags>
<repository type="git" url="https://github.com/windows-toolkit/WindowsCommunityToolkit.git" commit="72205c9add7c3fc1ed63bb77e6fc101e39f1ac33" />
<dependencies>
<group targetFramework=".NETStandard1.4">
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
</group>
<group targetFramework="UAP10.0.16299">
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
</group>
<group targetFramework=".NETCoreApp3.1">
<dependency id="Microsoft.Win32.Registry" version="4.7.0" exclude="Build,Analyzers" />
<dependency id="Microsoft.Windows.SDK.Contracts" version="10.0.19041.1" exclude="Build,Analyzers" />
<dependency id="System.Drawing.Common" version="4.7.0" exclude="Build,Analyzers" />
<dependency id="System.Reflection.Emit" version="4.7.0" exclude="Build,Analyzers" />
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
</group>
<group targetFramework="net5.0">
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
</group>
<group targetFramework="net5.0-windows10.0.17763">
<dependency id="Microsoft.Win32.Registry" version="4.7.0" exclude="Build,Analyzers" />
<dependency id="System.Drawing.Common" version="4.7.0" exclude="Build,Analyzers" />
<dependency id="System.Reflection.Emit" version="4.7.0" exclude="Build,Analyzers" />
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
</group>
<group targetFramework=".NETFramework4.6.1">
<dependency id="Microsoft.NETFramework.ReferenceAssemblies" version="1.0.0" exclude="Build,Analyzers" />
<dependency id="Microsoft.Windows.SDK.Contracts" version="10.0.19041.1" exclude="Build,Analyzers" />
<dependency id="System.ValueTuple" version="4.5.0" exclude="Build,Analyzers" />
</group>
<group targetFramework="native0.0" />
<group targetFramework="UAP10.0.10240" />
</dependencies>
</metadata>
<files>
<file src="Microsoft.Toolkit.Uwp.Notifications.targets" target="build\native\Microsoft.Toolkit.Uwp.Notifications.targets" />
<file src="$buildOutput$\net461\Microsoft.Toolkit.Uwp.Notifications.dll" target="lib\net461\Microsoft.Toolkit.Uwp.Notifications.dll" />
<file src="$buildOutput$\net461\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\net461\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\net461\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\net461\Microsoft.Toolkit.Uwp.Notifications.xml" />
<file src="$buildOutput$\net5.0\Microsoft.Toolkit.Uwp.Notifications.dll" target="lib\net5.0\Microsoft.Toolkit.Uwp.Notifications.dll" />
<file src="$buildOutput$\net5.0\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\net5.0\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\net5.0\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\net5.0\Microsoft.Toolkit.Uwp.Notifications.xml" />
<file src="$buildOutput$\net5.0-windows10.0.17763.0\Microsoft.Toolkit.Uwp.Notifications.dll" target="lib\net5.0-windows10.0.17763\Microsoft.Toolkit.Uwp.Notifications.dll" />
<file src="$buildOutput$\net5.0-windows10.0.17763.0\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\net5.0-windows10.0.17763\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\net5.0-windows10.0.17763.0\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\net5.0-windows10.0.17763\Microsoft.Toolkit.Uwp.Notifications.xml" />
<file src="$buildOutput$\netcoreapp3.1\Microsoft.Toolkit.Uwp.Notifications.dll" target="lib\netcoreapp3.1\Microsoft.Toolkit.Uwp.Notifications.dll" />
<file src="$buildOutput$\netcoreapp3.1\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\netcoreapp3.1\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\netcoreapp3.1\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\netcoreapp3.1\Microsoft.Toolkit.Uwp.Notifications.xml" />
<file src="$buildOutput$\netstandard1.4\Microsoft.Toolkit.Uwp.Notifications.dll" target="lib\netstandard1.4\Microsoft.Toolkit.Uwp.Notifications.dll" />
<file src="$buildOutput$\netstandard1.4\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\netstandard1.4\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\netstandard1.4\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\netstandard1.4\Microsoft.Toolkit.Uwp.Notifications.xml" />
<file src="$buildOutput$\uap10.0.19041\Microsoft.Toolkit.Uwp.Notifications.dll" target="lib\uap10.0.16299\Microsoft.Toolkit.Uwp.Notifications.dll" />
<file src="$buildOutput$\uap10.0.19041\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\uap10.0.16299\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\uap10.0.19041\Microsoft.Toolkit.Uwp.Notifications.pri" target="lib\uap10.0.16299\Microsoft.Toolkit.Uwp.Notifications.pri" />
<file src="$buildOutput$\uap10.0.19041\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\uap10.0.16299\Microsoft.Toolkit.Uwp.Notifications.xml" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\native\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.pri" target="lib\native\Microsoft.Toolkit.Uwp.Notifications.pri" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.winmd" target="lib\native\Microsoft.Toolkit.Uwp.Notifications.winmd" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\native\Microsoft.Toolkit.Uwp.Notifications.xml" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.pdb" target="lib\uap10.0.10240\Microsoft.Toolkit.Uwp.Notifications.pdb" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.pri" target="lib\uap10.0.10240\Microsoft.Toolkit.Uwp.Notifications.pri" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.winmd" target="lib\uap10.0.10240\Microsoft.Toolkit.Uwp.Notifications.winmd" />
<file src="$buildOutput$\native\Microsoft.Toolkit.Uwp.Notifications.xml" target="lib\uap10.0.10240\Microsoft.Toolkit.Uwp.Notifications.xml" />
</files>
</package>

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

@ -0,0 +1,13 @@
<!--
This file enable reflections for Toolkit.Notifications and all of its public/private members,
enabling the library to work in .NET Native even if developers modified their default rd.xml.
See issue https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/3093 for more details.
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="Microsoft.Toolkit.Uwp.Notifications">
<!-- TODO: We can potentially minimize the metadata needed, but further
investigation is needed to fill this in and adequately test this -->
<Assembly Name="Microsoft.Toolkit.Uwp.Notifications" Dynamic="Required All" />
</Library>
</Directives>

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

@ -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,9 +20,6 @@ namespace Microsoft.Toolkit.Uwp.Notifications
{
private const long APPMODEL_ERROR_NO_PACKAGE = 15700L;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);
private static bool? _hasIdentity;
public static bool HasIdentity()
@ -37,10 +34,10 @@ namespace Microsoft.Toolkit.Uwp.Notifications
{
int length = 0;
var sb = new StringBuilder(0);
GetCurrentPackageFullName(ref length, sb);
NativeMethods.GetCurrentPackageFullName(ref length, sb);
sb = new StringBuilder(length);
int error = GetCurrentPackageFullName(ref length, sb);
int error = NativeMethods.GetCurrentPackageFullName(ref length, sb);
_hasIdentity = error != APPMODEL_ERROR_NO_PACKAGE;
}

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

@ -50,7 +50,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
}
// If running as Desktop Bridge
if (DesktopBridgeHelpers.IsRunningAsUwp())
if (DesktopBridgeHelpers.HasIdentity())
{
// Clear the AUMID since Desktop Bridge doesn't use it, and then we're done.
// Desktop Bridge apps are registered with platform through their manifest.
@ -94,7 +94,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
// Big thanks to FrecherxDachs for figuring out the following code which works in .NET Core 3: https://github.com/FrecherxDachs/UwpNotificationNetCoreTest
var uuid = typeof(T).GUID;
uint cookie;
CoRegisterClassObject(
NativeMethods.CoRegisterClassObject(
uuid,
new NotificationActivatorClassFactory<T>(),
CLSCTX_LOCAL_SERVER,
@ -151,14 +151,6 @@ namespace Microsoft.Toolkit.Uwp.Notifications
}
}
[DllImport("ole32.dll")]
private static extern int CoRegisterClassObject(
[MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwClsContext,
uint flags,
out uint lpdwRegister);
/// <summary>
/// Creates a toast notifier. You must have called <see cref="RegisterActivator{T}"/> first (and also <see cref="RegisterAumidAndComServer(string)"/> if you're a classic Win32 app), or this will throw an exception.
/// </summary>
@ -198,7 +190,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
if (!_registeredAumidAndComServer)
{
// Check if Desktop Bridge
if (DesktopBridgeHelpers.IsRunningAsUwp())
if (DesktopBridgeHelpers.HasIdentity())
{
// Implicitly registered, all good!
_registeredAumidAndComServer = true;
@ -223,55 +215,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
/// </summary>
public static bool CanUseHttpImages
{
get { return DesktopBridgeHelpers.IsRunningAsUwp(); }
}
/// <summary>
/// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/tree/master/DesktopBridge.Helpers/Helpers.cs
/// </summary>
private class DesktopBridgeHelpers
{
private const long APPMODEL_ERROR_NO_PACKAGE = 15700L;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);
private static bool? _isRunningAsUwp;
public static bool IsRunningAsUwp()
{
if (_isRunningAsUwp == null)
{
if (IsWindows7OrLower)
{
_isRunningAsUwp = false;
}
else
{
int length = 0;
var sb = new StringBuilder(0);
GetCurrentPackageFullName(ref length, sb);
sb = new StringBuilder(length);
int error = GetCurrentPackageFullName(ref length, sb);
_isRunningAsUwp = error != APPMODEL_ERROR_NO_PACKAGE;
}
}
return _isRunningAsUwp.Value;
}
private static bool IsWindows7OrLower
{
get
{
int versionMajor = Environment.OSVersion.Version.Major;
int versionMinor = Environment.OSVersion.Version.Minor;
double version = versionMajor + ((double)versionMinor / 10);
return version <= 6.1;
}
}
get { return DesktopBridgeHelpers.HasIdentity(); }
}
}
}

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

@ -0,0 +1,32 @@
// 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.
#if WIN32
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Microsoft.Toolkit.Uwp.Notifications
{
internal class NativeMethods
{
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteObject([In] IntPtr hObject);
[DllImport("ole32.dll")]
internal static extern int CoRegisterClassObject(
[MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwClsContext,
uint flags,
out uint lpdwRegister);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);
}
}
#endif

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

@ -5,10 +5,12 @@
#if WIN32
using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
@ -18,6 +20,11 @@ namespace Microsoft.Toolkit.Uwp.Notifications
{
internal class Win32AppInfo
{
/// <summary>
/// If an AUMID is greater than 129 characters, scheduled toast notification APIs will throw an exception.
/// </summary>
private const int AUMID_MAX_LENGTH = 129;
public string Aumid { get; set; }
public string DisplayName { get; set; }
@ -32,6 +39,9 @@ namespace Microsoft.Toolkit.Uwp.Notifications
IApplicationResolver appResolver = (IApplicationResolver)new CAppResolver();
appResolver.GetAppIDForProcess(Convert.ToUInt32(process.Id), out string appId, out _, out _, out _);
// Use app ID (or hashed app ID) as AUMID
string aumid = appId.Length > AUMID_MAX_LENGTH ? HashAppId(appId) : appId;
// Then try to get the shortcut (for display name and icon)
IShellItem shortcutItem = null;
try
@ -74,7 +84,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
{
}
DeleteObject(nativeHBitmap);
NativeMethods.DeleteObject(nativeHBitmap);
}
}
catch
@ -98,12 +108,21 @@ namespace Microsoft.Toolkit.Uwp.Notifications
return new Win32AppInfo()
{
Aumid = appId,
Aumid = aumid,
DisplayName = displayName,
IconPath = iconPath
};
}
private static string HashAppId(string appId)
{
using (SHA1 sha1 = SHA1.Create())
{
byte[] hashedBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(appId));
return string.Join(string.Empty, hashedBytes.Select(b => b.ToString("X2")));
}
}
private static string GetDisplayNameFromCurrentProcess(Process process)
{
// If AssemblyTitle is set, use that
@ -212,10 +231,6 @@ namespace Microsoft.Toolkit.Uwp.Notifications
return false;
}
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteObject([In] IntPtr hObject);
/// <summary>
/// From https://stackoverflow.com/a/41622689/1454643
/// Generates Guid based on String. Key assumption for this algorithm is that name is unique (across where it it's being used)

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

@ -53,14 +53,18 @@ namespace Microsoft.Toolkit.Uwp.Notifications
/// <param name="tag">The tag label of the toast notification to be removed.</param>
public void Remove(string tag)
{
#if WIN32
if (_aumid != null)
{
_history.Remove(tag, string.Empty, _aumid);
_history.Remove(tag, ToastNotificationManagerCompat.DEFAULT_GROUP, _aumid);
}
else
{
_history.Remove(tag);
}
#else
_history.Remove(tag);
#endif
}
/// <summary>

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

@ -26,6 +26,8 @@ namespace Microsoft.Toolkit.Uwp.Notifications
{
#if WIN32
private const string TOAST_ACTIVATED_LAUNCH_ARG = "-ToastActivated";
private const string REG_HAS_SENT_NOTIFICATION = "HasSentNotification";
internal const string DEFAULT_GROUP = "toolkitGroupNull";
private const int CLASS_E_NOAGGREGATION = -2147221232;
private const int E_NOINTERFACE = -2147467262;
@ -37,6 +39,8 @@ namespace Microsoft.Toolkit.Uwp.Notifications
private static bool _registeredOnActivated;
private static List<OnActivated> _onActivated = new List<OnActivated>();
private static bool _hasSentNotification;
/// <summary>
/// Event that is triggered when a notification or notification button is clicked. Subscribe to this event in your app's initial startup code.
/// </summary>
@ -55,7 +59,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
}
catch (Exception ex)
{
_initializeEx = ex;
_initializeEx = new InvalidOperationException("Failed to register notification activator", ex);
}
}
@ -104,7 +108,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
private static string _win32Aumid;
private static string _clsid;
private static Exception _initializeEx;
private static InvalidOperationException _initializeEx;
static ToastNotificationManagerCompat()
{
@ -115,7 +119,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
catch (Exception ex)
{
// We catch the exception so that things like subscribing to the event handler doesn't crash app
_initializeEx = ex;
_initializeEx = new InvalidOperationException("Failed initializing notifications", ex);
}
}
@ -145,7 +149,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
var activatorType = CreateAndRegisterActivator();
// Register via registry
using (var rootKey = Registry.CurrentUser.CreateSubKey(@"Software\Classes\AppUserModelId\" + _win32Aumid))
using (var rootKey = Registry.CurrentUser.CreateSubKey(GetRegistrySubKey()))
{
// If they don't have identity, we need to specify the display assets
if (!DesktopBridgeHelpers.HasIdentity())
@ -168,12 +172,20 @@ namespace Microsoft.Toolkit.Uwp.Notifications
// Background color only appears in the settings page, format is
// hex without leading #, like "FFDDDDDD"
rootKey.SetValue("IconBackgroundColor", "FFDDDDDD");
// Additionally, we need to read whether they've sent a notification before
_hasSentNotification = rootKey.GetValue(REG_HAS_SENT_NOTIFICATION) != null;
}
rootKey.SetValue("CustomActivator", string.Format("{{{0}}}", activatorType.GUID));
}
}
private static string GetRegistrySubKey()
{
return @"Software\Classes\AppUserModelId\" + _win32Aumid;
}
private static Type CreateActivatorType()
{
// https://stackoverflow.com/questions/24069352/c-sharp-typebuilder-generate-class-with-function-dynamically
@ -239,7 +251,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
// Big thanks to FrecherxDachs for figuring out the following code which works in .NET Core 3: https://github.com/FrecherxDachs/UwpNotificationNetCoreTest
var uuid = activatorType.GUID;
CoRegisterClassObject(
NativeMethods.CoRegisterClassObject(
uuid,
new NotificationActivatorClassFactory(activatorType),
CLSCTX_LOCAL_SERVER,
@ -250,12 +262,36 @@ namespace Microsoft.Toolkit.Uwp.Notifications
private static void RegisterComServer(Type activatorType, string exePath)
{
// We register the EXE to start up when the notification is activated
string regString = string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}\\LocalServer32", activatorType.GUID);
var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString);
string regString = string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}", activatorType.GUID);
using (var key = Registry.CurrentUser.CreateSubKey(regString + "\\LocalServer32"))
{
// Include a flag so we know this was a toast activation and should wait for COM to process
// We also wrap EXE path in quotes for extra security
key.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG);
}
// Include a flag so we know this was a toast activation and should wait for COM to process
// We also wrap EXE path in quotes for extra security
key.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG);
if (IsElevated)
{
//// For elevated apps, we need to ensure they'll activate in existing running process by adding
//// some values in local machine
using (var key = Registry.LocalMachine.CreateSubKey(regString))
{
// Same as above, except also including AppId to link to our AppId entry below
using (var localServer32 = key.CreateSubKey("LocalServer32"))
{
localServer32.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG);
}
key.SetValue("AppId", "{" + activatorType.GUID + "}");
}
// This tells COM to match any client, so Action Center will activate our elevated process.
// More info: https://docs.microsoft.com/windows/win32/com/runas
using (var key = Registry.LocalMachine.CreateSubKey(string.Format("SOFTWARE\\Classes\\AppID\\{{{0}}}", activatorType.GUID)))
{
key.SetValue("RunAs", "Interactive User");
}
}
}
/// <summary>
@ -320,20 +356,20 @@ namespace Microsoft.Toolkit.Uwp.Notifications
}
}
[DllImport("ole32.dll")]
private static extern int CoRegisterClassObject(
[MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwClsContext,
uint flags,
out uint lpdwRegister);
private static bool IsElevated
{
get
{
return new System.Security.Principal.WindowsPrincipal(System.Security.Principal.WindowsIdentity.GetCurrent()).IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
}
}
#endif
/// <summary>
/// Creates a toast notifier.
/// </summary>
/// <returns><see cref="ToastNotifier"/></returns>
public static ToastNotifier CreateToastNotifier()
/// <returns><see cref="ToastNotifierCompat"/>An instance of the toast notifier.</returns>
public static ToastNotifierCompat CreateToastNotifier()
{
#if WIN32
if (_initializeEx != null)
@ -343,14 +379,14 @@ namespace Microsoft.Toolkit.Uwp.Notifications
if (DesktopBridgeHelpers.HasIdentity())
{
return ToastNotificationManager.CreateToastNotifier();
return new ToastNotifierCompat(ToastNotificationManager.CreateToastNotifier());
}
else
{
return ToastNotificationManager.CreateToastNotifier(_win32Aumid);
return new ToastNotifierCompat(ToastNotificationManager.CreateToastNotifier(_win32Aumid));
}
#else
return ToastNotificationManager.CreateToastNotifier();
return new ToastNotifierCompat(ToastNotificationManager.CreateToastNotifier());
#endif
}
@ -437,7 +473,7 @@ namespace Microsoft.Toolkit.Uwp.Notifications
// Remove registry key
if (_win32Aumid != null)
{
Registry.CurrentUser.DeleteSubKey(@"Software\Classes\AppUserModelId\" + _win32Aumid);
Registry.CurrentUser.DeleteSubKey(GetRegistrySubKey());
}
}
catch
@ -448,7 +484,32 @@ namespace Microsoft.Toolkit.Uwp.Notifications
{
if (_clsid != null)
{
Registry.CurrentUser.DeleteSubKey(string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}\\LocalServer32", _clsid));
try
{
Registry.CurrentUser.DeleteSubKeyTree(string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}", _clsid));
}
catch
{
}
if (IsElevated)
{
try
{
Registry.LocalMachine.DeleteSubKeyTree(string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}", _clsid));
}
catch
{
}
try
{
Registry.LocalMachine.DeleteSubKeyTree(string.Format("SOFTWARE\\Classes\\AppID\\{{{0}}}", _clsid));
}
catch
{
}
}
}
}
catch
@ -472,6 +533,51 @@ namespace Microsoft.Toolkit.Uwp.Notifications
}
}
#endif
#if WIN32
internal static void SetHasSentToastNotification()
{
// For plain Win32 apps, record that we've sent a notification
if (!_hasSentNotification && !DesktopBridgeHelpers.HasIdentity())
{
_hasSentNotification = true;
try
{
using (var rootKey = Registry.CurrentUser.CreateSubKey(GetRegistrySubKey()))
{
rootKey.SetValue(REG_HAS_SENT_NOTIFICATION, 1);
}
}
catch
{
}
}
}
internal static void PreRegisterIdentityLessApp()
{
// For plain Win32 apps, we first have to have send a toast notification once before using scheduled toasts.
if (!_hasSentNotification && !DesktopBridgeHelpers.HasIdentity())
{
const string tag = "toolkit1stNotif";
// Show the toast
new ToastContentBuilder()
.AddText("New notification")
.Show(toast =>
{
// We'll hide the popup and set the toast to expire in case removing doesn't work
toast.SuppressPopup = true;
toast.Tag = tag;
toast.ExpirationTime = DateTime.Now.AddSeconds(15);
});
// And then remove it
ToastNotificationManagerCompat.History.Remove(tag);
}
}
#endif
}
}

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

@ -0,0 +1,172 @@
// 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.
#if WINDOWS_UWP
using System.Collections.Generic;
using Windows.UI.Notifications;
namespace Microsoft.Toolkit.Uwp.Notifications
{
/// <summary>
/// Allows you to show and schedule toast notifications.
/// </summary>
public sealed class ToastNotifierCompat
{
private ToastNotifier _notifier;
internal ToastNotifierCompat(ToastNotifier notifier)
{
_notifier = notifier;
}
/// <summary>
/// Displays the specified toast notification.
/// </summary>
/// <param name="notification">The object that contains the content of the toast notification to display.</param>
public void Show(ToastNotification notification)
{
#if WIN32
PreprocessToast(notification);
#endif
_notifier.Show(notification);
#if WIN32
ToastNotificationManagerCompat.SetHasSentToastNotification();
#endif
}
/// <summary>
/// Hides the specified toast notification from the screen (moves it into Action Center).
/// </summary>
/// <param name="notification">The object that specifies the toast to hide.</param>
public void Hide(ToastNotification notification)
{
#if WIN32
PreprocessToast(notification);
#endif
_notifier.Hide(notification);
}
/// <summary>
/// Adds a ScheduledToastNotification for later display by Windows.
/// </summary>
/// <param name="scheduledToast">The scheduled toast notification, which includes its content and timing instructions.</param>
public void AddToSchedule(ScheduledToastNotification scheduledToast)
{
#if WIN32
ToastNotificationManagerCompat.PreRegisterIdentityLessApp();
PreprocessScheduledToast(scheduledToast);
#endif
_notifier.AddToSchedule(scheduledToast);
}
/// <summary>
/// Cancels the scheduled display of a specified ScheduledToastNotification.
/// </summary>
/// <param name="scheduledToast">The notification to remove from the schedule.</param>
public void RemoveFromSchedule(ScheduledToastNotification scheduledToast)
{
#if WIN32
PreprocessScheduledToast(scheduledToast);
#endif
_notifier.RemoveFromSchedule(scheduledToast);
}
/// <summary>
/// Gets the collection of ScheduledToastNotification objects that this app has scheduled for display.
/// </summary>
/// <returns>The collection of scheduled toast notifications that the app bound to this notifier has scheduled for timed display.</returns>
public IReadOnlyList<ScheduledToastNotification> GetScheduledToastNotifications()
{
return _notifier.GetScheduledToastNotifications();
}
/// <summary>
/// Updates the existing toast notification that has the specified tag and belongs to the specified notification group.
/// </summary>
/// <param name="data">An object that contains the updated info.</param>
/// <param name="tag">The identifier of the toast notification to update.</param>
/// <param name="group">The ID of the ToastCollection that contains the notification.</param>
/// <returns>A value that indicates the result of the update (failure, success, etc).</returns>
public NotificationUpdateResult Update(NotificationData data, string tag, string group)
{
return _notifier.Update(data, tag, group);
}
/// <summary>
/// Updates the existing toast notification that has the specified tag.
/// </summary>
/// <param name="data">An object that contains the updated info.</param>
/// <param name="tag">The identifier of the toast notification to update.</param>
/// <returns>A value that indicates the result of the update (failure, success, etc).</returns>
public NotificationUpdateResult Update(NotificationData data, string tag)
{
#if WIN32
// For apps that don't have identity...
if (!DesktopBridgeHelpers.HasIdentity())
{
// If group isn't specified, we have to add a group since otherwise can't remove without a group
return Update(data, tag, ToastNotificationManagerCompat.DEFAULT_GROUP);
}
#endif
return _notifier.Update(data, tag);
}
/// <summary>
/// Gets a value that tells you whether there is an app, user, or system block that prevents the display of a toast notification.
/// </summary>
public NotificationSetting Setting
{
get
{
#if WIN32
// Just like scheduled notifications, apps need to have sent a notification
// before checking the setting value works
ToastNotificationManagerCompat.PreRegisterIdentityLessApp();
#endif
return _notifier.Setting;
}
}
#if WIN32
private void PreprocessToast(ToastNotification notification)
{
// For apps that don't have identity...
if (!DesktopBridgeHelpers.HasIdentity())
{
// If tag is specified
if (!string.IsNullOrEmpty(notification.Tag))
{
// If group isn't specified, we have to add a group since otherwise can't remove without a group
notification.Group = ToastNotificationManagerCompat.DEFAULT_GROUP;
}
}
}
private void PreprocessScheduledToast(ScheduledToastNotification notification)
{
// For apps that don't have identity...
if (!DesktopBridgeHelpers.HasIdentity())
{
// If tag is specified
if (!string.IsNullOrEmpty(notification.Tag))
{
// If group isn't specified, we have to add a group since otherwise can't remove without a group
notification.Group = ToastNotificationManagerCompat.DEFAULT_GROUP;
}
}
}
#endif
}
}
#endif

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

@ -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;

Двоичные данные
Microsoft.Toolkit.Uwp.SampleApp/Assets/Llama.mp3 Normal file

Двоичный файл не отображается.

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

@ -416,7 +416,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.Controls
/// <summary>
/// The Local Storage Helper.
/// </summary>
private LocalObjectStorageHelper storage = new LocalObjectStorageHelper();
private LocalObjectStorageHelper storage = new LocalObjectStorageHelper(new SystemSerializer());
/// <summary>
/// DocFX note types and styling info, keyed by identifier.

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

@ -112,9 +112,11 @@
<PackageReference Include="Microsoft.Services.Store.Engagement">
<Version>10.1901.28001</Version>
</PackageReference>
<!-- TODO Reintroduce graph controls
<PackageReference Include="Microsoft.Toolkit.Graph.Controls">
<Version>6.1.0-build.6</Version>
</PackageReference>
-->
<PackageReference Include="Microsoft.UI.Xaml">
<Version>2.4.2</Version>
</PackageReference>
@ -135,6 +137,7 @@
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<Content Include="Assets\BrushAssets\TileTexture.png" />
<Content Include="Assets\BrushAssets\NoiseTexture.png" />
<Content Include="Assets\Llama.mp3" />
<Content Include="Assets\mslogo.png" />
<Content Include="Assets\NotificationAssets\Cloudy-Square.png" />
<Content Include="Assets\NotificationAssets\Cloudy.png" />
@ -269,17 +272,22 @@
<Content Include="Icons\More.png" />
<Content Include="Icons\Notifications.png" />
<Content Include="Icons\Services.png" />
<Content Include="SamplePages\TabbedCommandBar\TabbedCommandBar.png" />
<Content Include="SamplePages\Animations\Effects\FadeBehavior.png" />
<Content Include="SamplePages\ColorPicker\ColorPicker.png" />
<Content Include="SamplePages\TilesBrush\TilesBrush.png" />
<Content Include="SamplePages\Eyedropper\Eyedropper.png" />
<Content Include="SamplePages\OnDevice\OnDevice.png" />
<Content Include="SamplePages\AcrylicBrush\AcrylicBrush.png" />
<Content Include="SamplePages\CanvasPathGeometry\CanvasPathGeometry.png" />
<Content Include="SamplePages\PipelineBrush\PipelineBrush.png" />
<Content Include="SamplePages\RemoteDeviceHelper\RemoteDeviceHelper.png" />
<Content Include="SamplePages\ImageCropper\ImageCropper.png" />
<Content Include="SamplePages\StaggeredLayout\StaggeredLayout.png" />
<!-- TODO Reintroduce graph controls
<Content Include="SamplePages\PeoplePicker\PeoplePicker.png" />
<Content Include="SamplePages\PersonView\PersonView.png" />
-->
<Content Include="SamplePages\TokenizingTextBox\TokenizingTextBox.png" />
<Content Include="SamplePages\UniformGrid\UniformGrid.png" />
<Content Include="SamplePages\AdaptiveGridView\AdaptiveGridView.png" />
@ -291,16 +299,16 @@
<Content Include="SamplePages\BackgroundTaskHelper\BackgroundTaskHelper.png" />
<Content Include="SamplePages\BluetoothLEHelper\BluetoothLEHelper.png" />
<Content Include="SamplePages\BackdropBlurBrush\BackdropBlurBrush.png" />
<Content Include="SamplePages\Blur\BlurBehavior.png" />
<Content Include="SamplePages\CameraPreview\CameraPreview.png" />
<Content Include="SamplePages\CameraHelper\CameraHelper.png" />
<Content Include="SamplePages\Connected Animations\ConnectedAnimations.png" />
<Content Include="SamplePages\DataGrid\DataGrid.png" />
<Content Include="SamplePages\DispatcherQueueHelper\DispatchQueueHelper.png" />
<Content Include="SamplePages\DockPanel\DockPanel.png" />
<!-- TODO Reintroduce graph controls
<Content Include="SamplePages\LoginButton\LoginButton.png" />
-->
<Content Include="SamplePages\FadeHeader\FadeHeaderBehavior.png" />
<Content Include="SamplePages\Fade\FadeBehavior.png" />
<Content Include="SamplePages\FocusTracker\FocusTracker.png" />
<Content Include="SamplePages\BladeView\BladeView.png" />
<Content Include="SamplePages\Carousel\Carousel.png" />
@ -322,29 +330,24 @@
<Content Include="SamplePages\Incremental Loading Collection\icon.png" />
<Content Include="SamplePages\LayoutTransformControl\LayoutTransformControl.png" />
<Content Include="SamplePages\InfiniteCanvas\InfiniteCanvas.png" />
<Content Include="SamplePages\Light\LightBehavior.png" />
<Content Include="SamplePages\LinkedIn Service\LinkedInLogo.png" />
<Content Include="Assets\Helpers.png" />
<Content Include="SamplePages\LiveTile\LiveTile.png" />
<Content Include="SamplePages\MarkdownTextBlock\MarkdownTextBlock.png" />
<Content Include="SamplePages\Loading\Loading.png" />
<Content Include="SamplePages\MasterDetailsView\MasterDetailsView.png" />
<Content Include="SamplePages\MasterDetailsView\OneDriveLogo.png" />
<Content Include="SamplePages\ListDetailsView\ListDetailsView.png" />
<Content Include="SamplePages\ListDetailsView\OneDriveLogo.png" />
<Content Include="SamplePages\Menu\Menu.png" />
<Content Include="SamplePages\Microsoft Translator Service\TranslatorService.png" />
<Content Include="SamplePages\NetworkHelper\NetworkHelper.png" />
<Content Include="SamplePages\Offset\OffsetBehavior.png" />
<Content Include="SamplePages\Mouse\MouseCursor.png" />
<Content Include="SamplePages\OneDrive Service\OneDriveLogo.png" />
<Content Include="SamplePages\RadialGauge\RadialGauge.png" />
<Content Include="SamplePages\RadialGradientBrush\RadialGradientBrush.png" />
<Content Include="SamplePages\RadialProgressBar\RadialProgressBar.png" />
<Content Include="SamplePages\RemoteDevicePicker\RemoteDevicePicker.png" />
<Content Include="SamplePages\ReorderGridAnimation\ReorderGrid.png" />
<Content Include="SamplePages\Rotate\RotateBehavior.png" />
<Content Include="SamplePages\Saturation\SaturationBehavior.png" />
<Content Include="SamplePages\ItemsReorderAnimation\ItemsReorderAnimation.png" />
<Content Include="SamplePages\OrbitView\OrbitView.png" />
<Content Include="SamplePages\Scale\ScaleBehavior.png" />
<Content Include="SamplePages\ScrollViewerExtensions\ScrollViewerExtensionsCode.bind" />
<Content Include="SamplePages\StaggeredPanel\StaggeredPanel.png" />
<Content Include="SamplePages\SystemInformation\SystemInformation.png" />
@ -377,11 +380,7 @@
<Content Include="SamplePages\WeatherLiveTileAndToast\WeatherLiveTileAndToast.png" />
<Content Include="SamplePages\WeatherLiveTileAndToast\WeatherLiveTileAndToastCode.bind" />
<Content Include="SamplePages\ImageEx\ImageExCode.bind" />
<Content Include="SamplePages\Offset\OffsetBehaviorCode.bind" />
<Content Include="SamplePages\Fade\FadeBehaviorCode.bind" />
<Content Include="SamplePages\RadialGauge\RadialGaugeCode.bind" />
<Content Include="SamplePages\Rotate\RotateBehaviorCode.bind" />
<Content Include="SamplePages\Scale\ScaleBehaviorCode.bind" />
<Content Include="Assets\Photos\Photos.json" />
<Content Include="Assets\Photos\OnlinePhotos.json" />
<Content Include="SamplePages\RangeSelector\RangeSelectorCode.bind" />
@ -393,13 +392,7 @@
<Content Include="SamplePages\LiveTile\LiveTileCode.bind" />
<Content Include="SamplePages\Toast\ToastCode.bind" />
<Content Include="SamplePages\RotatorTile\RotatorTileCode.bind" />
<Content Include="SamplePages\Saturation\SaturationBehaviorCode.bind" />
<Content Include="SamplePages\Saturation\SaturationBehaviorXaml.bind" />
<Content Include="SamplePages\Offset\OffsetBehaviorXaml.bind" />
<Content Include="SamplePages\Expander\ExpanderXaml.bind" />
<Content Include="SamplePages\Fade\FadeBehaviorXaml.bind" />
<Content Include="SamplePages\Scale\ScaleBehaviorXaml.bind" />
<Content Include="SamplePages\Rotate\RotateBehaviorXaml.bind" />
<Content Include="SamplePages\BladeView\BladeCode.bind" />
<Content Include="SamplePages\ScrollHeader\ScrollHeaderCode.bind" />
<Content Include="SamplePages\GridSplitter\GridSplitter.bind" />
@ -412,15 +405,13 @@
<Content Include="SamplePages\DropShadowPanel\DropShadowPanelXaml.bind" />
<Content Include="SamplePages\Object Storage\ObjectStorageCode.bind" />
<Content Include="SamplePages\BackgroundTaskHelper\BackgroundTaskHelperCode.bind" />
<Content Include="SamplePages\MasterDetailsView\MasterDetailsView.bind" />
<Content Include="SamplePages\ListDetailsView\ListDetailsView.bind" />
<Content Include="SamplePages\NetworkHelper\NetworkHelperCode.bind" />
<Content Include="SamplePages\PrintHelper\PrintHelperCode.bind" />
<Content Include="SamplePages\SystemInformation\SystemInformationCode.bind" />
<Content Include="SamplePages\Connected Animations\ConnectedAnimationsCode.bind" />
<Content Include="SamplePages\Loading\LoadingCode.bind" />
<Content Include="SamplePages\ReorderGridAnimation\ReorderGrid.bind" />
<Content Include="SamplePages\Light\LightBehaviorCode.bind" />
<Content Include="SamplePages\Light\LightBehaviorXaml.bind" />
<Content Include="SamplePages\ItemsReorderAnimation\ItemsReorderAnimation.bind" />
<Content Include="SamplePages\TextBoxMask\TextBoxMask.bind" />
<Content Include="SamplePages\TileControl\TileControl.bind">
<SubType>Designer</SubType>
@ -429,7 +420,7 @@
<SubType>Designer</SubType>
</Content>
<Content Include="SamplePages\WrapPanel\WrapPanel.bind" />
<Content Include="SamplePages\MasterDetailsView\MasterDetailsViewCode.bind" />
<Content Include="SamplePages\ListDetailsView\ListDetailsViewCode.bind" />
<Content Include="SamplePages\Microsoft Translator Service\MicrosoftTranslatorCode.bind" />
<Content Include="SamplePages\MarkdownTextBlock\MarkdownTextBlock.bind" />
<Content Include="SamplePages\MarkdownTextBlock\InitialContent.md" />
@ -437,8 +428,6 @@
<Content Include="SamplePages\TextBoxRegex\TextBoxRegex.bind" />
<Content Include="SamplePages\RadialProgressBar\RadialProgressBarCode.bind" />
<Content Include="SamplePages\MarkdownTextBlock\MarkdownTextBlockCode.bind" />
<Content Include="SamplePages\Blur\BlurBehaviorCode.bind" />
<Content Include="SamplePages\Blur\BlurBehaviorXaml.bind" />
<Content Include="SamplePages\ViewExtensions\ViewExtensionsCode.bind">
<SubType>Designer</SubType>
</Content>
@ -490,9 +479,11 @@
<SubType>Designer</SubType>
</Content>
<Content Include="SamplePages\CameraPreview\CameraPreviewXaml.bind" />
<!-- TODO Reintroduce graph controls
<Content Include="SamplePages\LoginButton\LoginButtonXaml.bind" />
<Content Include="SamplePages\PeoplePicker\PeoplePickerXaml.bind" />
<Content Include="SamplePages\PersonView\PersonViewXaml.bind" />
-->
<Content Include="SamplePages\GazeInteraction\GazeInteractionXaml.bind">
<SubType>Designer</SubType>
</Content>
@ -507,6 +498,7 @@
<Compile Include="SamplePages\AutoFocusBehavior\AutoFocusBehaviorPage.xaml.cs">
<DependentUpon>AutoFocusBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\CanvasPathGeometry\GeometryStreamReader.cs" />
<Compile Include="SamplePages\ColorPicker\ColorPickerButtonPage.xaml.cs">
<DependentUpon>ColorPickerButtonPage.xaml</DependentUpon>
</Compile>
@ -516,6 +508,9 @@
<Compile Include="SamplePages\EnumValuesExtension\EnumValuesExtensionPage.xaml.cs">
<DependentUpon>EnumValuesExtensionPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\CanvasPathGeometry\CanvasPathGeometryPage.xaml.cs">
<DependentUpon>CanvasPathGeometryPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\FocusBehavior\FocusBehaviorPage.xaml.cs">
<DependentUpon>FocusBehaviorPage.xaml</DependentUpon>
</Compile>
@ -608,6 +603,27 @@
<Content Include="SamplePages\AutoFocusBehavior\AutoFocusBehaviorXaml.bind" />
<Content Include="SamplePages\ColorPicker\ColorPickerXaml.bind" />
<Content Include="SamplePages\ColorPicker\ColorPickerButtonXaml.bind" />
<Content Include="SamplePages\Animations\Effects\FadeBehaviorCode.bind" />
<Content Include="SamplePages\Animations\Effects\FadeBehaviorXaml.bind" />
<Content Include="SamplePages\Animations\Activities\StartAnimationActivity.bind" />
<Content Include="SamplePages\Animations\Activities\InvokeActionsActivity.bind" />
<Content Include="SamplePages\Animations\Behaviors\BlurBehavior.png" />
<Content Include="SamplePages\Animations\Behaviors\BlurBehaviorCode.bind" />
<Content Include="SamplePages\Animations\Behaviors\BlurBehaviorXaml.bind" />
<Content Include="SamplePages\Animations\Behaviors\OffsetBehavior.png" />
<Content Include="SamplePages\Animations\Behaviors\OffsetBehaviorCode.bind" />
<Content Include="SamplePages\Animations\Behaviors\OffsetBehaviorXaml.bind" />
<Content Include="SamplePages\Animations\Behaviors\SaturationBehavior.png" />
<Content Include="SamplePages\Animations\Behaviors\SaturationBehaviorCode.bind" />
<Content Include="SamplePages\Animations\Behaviors\SaturationBehaviorXaml.bind" />
<Content Include="SamplePages\Animations\Behaviors\ScaleBehavior.png" />
<Content Include="SamplePages\Animations\Behaviors\ScaleBehaviorCode.bind" />
<Content Include="SamplePages\Animations\Behaviors\ScaleBehaviorXaml.bind" />
<Content Include="SamplePages\Animations\Behaviors\RotateBehavior.png" />
<Content Include="SamplePages\Animations\Behaviors\RotateBehaviorCode.bind" />
<Content Include="SamplePages\Animations\Behaviors\RotateBehaviorXaml.bind" />
<Content Include="SamplePages\Animations\Effects\EffectAnimations.bind" />
<Content Include="SamplePages\VisualEffectFactory\VisualEffectFactory.bind" />
</ItemGroup>
<ItemGroup>
<Compile Include="App.xaml.cs">
@ -649,12 +665,14 @@
<Compile Include="Pages\SampleController.xaml.cs">
<DependentUpon>SampleController.xaml</DependentUpon>
</Compile>
<!-- TODO Reintroduce graph controls
<Compile Include="SamplePages\PeoplePicker\PeoplePickerPage.xaml.cs">
<DependentUpon>PeoplePickerPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\PersonView\PersonViewPage.xaml.cs">
<DependentUpon>PersonViewPage.xaml</DependentUpon>
</Compile>
-->
<Compile Include="SamplePages\AdvancedCollectionView\AdvancedCollectionViewPage.xaml.cs">
<DependentUpon>AdvancedCollectionViewPage.xaml</DependentUpon>
</Compile>
@ -695,9 +713,11 @@
<Compile Include="SamplePages\BackdropBlurBrush\BackdropBlurBrushPage.xaml.cs">
<DependentUpon>BackdropBlurBrushPage.xaml</DependentUpon>
</Compile>
<!-- TODO Reintroduce graph controls
<Compile Include="SamplePages\LoginButton\LoginButtonPage.xaml.cs">
<DependentUpon>LoginButtonPage.xaml</DependentUpon>
</Compile>
-->
<Compile Include="SamplePages\DataGrid\DataGridPage.xaml.cs">
<DependentUpon>DataGridPage.xaml</DependentUpon>
</Compile>
@ -811,9 +831,6 @@
<Compile Include="SamplePages\BladeView\BladePage.xaml.cs">
<DependentUpon>BladePage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Blur\BlurBehaviorPage.xaml.cs">
<DependentUpon>BlurBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\AlignmentGrid\AlignmentGridPage.xaml.cs">
<DependentUpon>AlignmentGridPage.xaml</DependentUpon>
</Compile>
@ -823,9 +840,6 @@
<Compile Include="SamplePages\Microsoft Translator Service\MicrosoftTranslatorPage.xaml.cs">
<DependentUpon>MicrosoftTranslatorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Saturation\SaturationBehaviorPage.xaml.cs">
<DependentUpon>SaturationBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\TileControl\TileControlPage.xaml.cs">
<DependentUpon>TileControlPage.xaml</DependentUpon>
</Compile>
@ -846,17 +860,14 @@
</Compile>
<Compile Include="SamplePages\Incremental Loading Collection\PeopleSource.cs" />
<Compile Include="SamplePages\Incremental Loading Collection\Person.cs" />
<Compile Include="SamplePages\Light\LightBehaviorPage.xaml.cs">
<DependentUpon>LightBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\LinkedIn Service\LinkedInPage.xaml.cs">
<DependentUpon>LinkedInPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Loading\LoadingPage.xaml.cs">
<DependentUpon>LoadingPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\MasterDetailsView\MasterDetailsViewPage.xaml.cs">
<DependentUpon>MasterDetailsViewPage.xaml</DependentUpon>
<Compile Include="SamplePages\ListDetailsView\ListDetailsViewPage.cs">
<DependentUpon>ListDetailsViewPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\ImageCache\ImageCachePage.xaml.cs">
<DependentUpon>ImageCachePage.xaml</DependentUpon>
@ -864,8 +875,8 @@
<Compile Include="SamplePages\PrintHelper\PrintHelperPage.xaml.cs">
<DependentUpon>PrintHelperPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\ReorderGridAnimation\ReorderGridPage.xaml.cs">
<DependentUpon>ReorderGridPage.xaml</DependentUpon>
<Compile Include="SamplePages\ItemsReorderAnimation\ItemsReorderAnimationPage.xaml.cs">
<DependentUpon>ItemsReorderAnimationPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\RotatorTile\RotatorTilePage.xaml.cs">
<DependentUpon>RotatorTilePage.xaml</DependentUpon>
@ -894,12 +905,6 @@
<Compile Include="SamplePages\Twitter Service\TwitterPage.xaml.cs">
<DependentUpon>TwitterPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Offset\OffsetBehaviorPage.xaml.cs">
<DependentUpon>OffsetBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Fade\FadeBehaviorPage.xaml.cs">
<DependentUpon>FadeBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\ImageEx\ImageExPage.xaml.cs">
<DependentUpon>ImageExPage.xaml</DependentUpon>
</Compile>
@ -913,12 +918,6 @@
<Compile Include="SamplePages\WeatherLiveTileAndToast\WeatherLiveTileAndToastPage.xaml.cs">
<DependentUpon>WeatherLiveTileAndToastPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Rotate\RotateBehaviorPage.xaml.cs">
<DependentUpon>RotateBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Scale\ScaleBehaviorPage.xaml.cs">
<DependentUpon>ScaleBehaviorPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\RadialGauge\RadialGaugePage.xaml.cs">
<DependentUpon>RadialGaugePage.xaml</DependentUpon>
</Compile>
@ -997,6 +996,13 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Content Include="SamplePages\TabbedCommandBar\TabbedCommandBar.bind">
<SubType>Designer</SubType>
</Content>
<Page Include="SamplePages\CanvasPathGeometry\CanvasPathGeometryPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\TilesBrush\TilesBrushPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -1048,6 +1054,7 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<!-- TODO Reintroduce graph controls
<Page Include="SamplePages\PeoplePicker\PeoplePickerPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -1056,6 +1063,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
-->
<Page Include="SamplePages\BackdropGammaTransferBrush\BackdropGammaTransferBrushPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -1140,10 +1148,12 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<!-- TODO Reintroduce graph controls
<Page Include="SamplePages\LoginButton\LoginButtonPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
-->
<Page Include="SamplePages\FocusTracker\FocusTrackerPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -1256,10 +1266,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\Blur\BlurBehaviorPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\AlignmentGrid\AlignmentGridPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -1276,10 +1282,6 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\Saturation\SaturationBehaviorPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\TileControl\TileControlPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -1308,10 +1310,6 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\Light\LightBehaviorPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\LinkedIn Service\LinkedInPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -1320,7 +1318,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\MasterDetailsView\MasterDetailsViewPage.xaml">
<Page Include="SamplePages\ListDetailsView\ListDetailsViewPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -1332,7 +1330,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\ReorderGridAnimation\ReorderGridPage.xaml">
<Page Include="SamplePages\ItemsReorderAnimation\ItemsReorderAnimationPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -1344,14 +1342,6 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\Offset\OffsetBehaviorPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\Fade\FadeBehaviorPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\Object Storage\ObjectStoragePage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -1404,14 +1394,6 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\Rotate\RotateBehaviorPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\Scale\ScaleBehaviorPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\Weibo Service\WeiboPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -1486,10 +1468,18 @@
<Project>{1ae2cb5c-58a0-4f12-8e6f-2cd4aaadb34c}</Project>
<Name>Microsoft.Toolkit.Uwp.Samples.BackgroundTasks</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Behaviors\Microsoft.Toolkit.Uwp.UI.Behaviors.csproj">
<Project>{d4ff799d-0df2-495a-adc9-3bbc4aef8971}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Behaviors</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Controls.DataGrid\Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.csproj">
<Project>{daeb9cec-c817-33b2-74b2-bc379380db72}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Controls.DataGrid</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Controls.Input\Microsoft.Toolkit.Uwp.UI.Controls.Input.csproj">
<Project>{af1be4e9-e2e1-4729-b076-b3725d8e21ee}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Controls.Input</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Controls.Layout\Microsoft.Toolkit.Uwp.UI.Controls.Layout.csproj">
<Project>{cb444381-18ba-4a51-bb32-3a498bcc1e99}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Controls.Layout</Name>
@ -1498,9 +1488,17 @@
<Project>{6fedf199-b052-49dd-8f3e-2a9224998e0f}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Controls.Markdown</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Controls\Microsoft.Toolkit.Uwp.UI.Controls.csproj">
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Controls.Media\Microsoft.Toolkit.Uwp.UI.Controls.Media.csproj">
<Project>{43bd2a36-9e12-4788-80ae-2377e41e6d05}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Controls.Media</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Controls.Primitives\Microsoft.Toolkit.Uwp.UI.Controls.Primitives.csproj">
<Project>{84ab7dc5-95c9-4cf8-a370-d077e9e9ef1a}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Controls.Primitives</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Controls.Core\Microsoft.Toolkit.Uwp.UI.Controls.Core.csproj">
<Project>{e9faabfb-d726-42c1-83c1-cb46a29fea81}</Project>
<Name>Microsoft.Toolkit.Uwp.UI.Controls</Name>
<Name>Microsoft.Toolkit.Uwp.UI.Controls.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Media\Microsoft.Toolkit.Uwp.UI.Media.csproj">
<Project>{75f9ee44-3efa-47bc-aedd-351b9834a0af}</Project>

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

@ -16,8 +16,9 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Toolkit.Graph.Converters;
using Microsoft.Toolkit.Graph.Providers;
// TODO Reintroduce graph controls
// using Microsoft.Toolkit.Graph.Converters;
// using Microsoft.Toolkit.Graph.Providers;
using Microsoft.Toolkit.Uwp.Helpers;
using Microsoft.Toolkit.Uwp.Input.GazeInteraction;
using Microsoft.Toolkit.Uwp.SampleApp.Models;
@ -41,7 +42,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
public static async void EnsureCacheLatest()
{
var settingsStorage = new LocalObjectStorageHelper();
var settingsStorage = new LocalObjectStorageHelper(new SystemSerializer());
var onlineDocsSHA = await GetDocsSHA();
var cacheSHA = settingsStorage.Read<string>(_cacheSHAKey);
@ -628,107 +629,30 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
private static Type LookForTypeByName(string typeName)
{
// First search locally
var result = System.Type.GetType(typeName);
if (result != null)
if (System.Type.GetType(typeName) is Type systemType)
{
return result;
return systemType;
}
// Search in Windows
var proxyType = VerticalAlignment.Center;
var assembly = proxyType.GetType().GetTypeInfo().Assembly;
foreach (var typeInfo in assembly.ExportedTypes)
var targets = new Type[]
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
VerticalAlignment.Center.GetType(), // Windows
StackMode.Replace.GetType(), // Microsoft.Toolkit.Uwp.UI.Controls.Core
// Search in Microsoft.Toolkit.Uwp.UI.Controls
var controlsProxyType = GridSplitter.GridResizeDirection.Auto;
assembly = controlsProxyType.GetType().GetTypeInfo().Assembly;
// TODO Reintroduce graph controls
// typeof(UserToPersonConverter)) // Search in Microsoft.Toolkit.Graph.Controls
EasingType.Default.GetType(), // Microsoft.Toolkit.Uwp.UI.Animations
ImageBlendMode.Multiply.GetType(), // Search in Microsoft.Toolkit.Uwp.UI
Interaction.Enabled.GetType(), // Microsoft.Toolkit.Uwp.Input.GazeInteraction
DataGridGridLinesVisibility.None.GetType(), // Microsoft.Toolkit.Uwp.UI.Controls.DataGrid
GridSplitter.GridResizeDirection.Auto.GetType(), // Microsoft.Toolkit.Uwp.UI.Controls.Layout
typeof(MarkdownTextBlock), // Microsoft.Toolkit.Uwp.UI.Controls.Markdown
BitmapFileFormat.Bmp.GetType(), // Microsoft.Toolkit.Uwp.UI.Controls.Media
StretchChild.Last.GetType() // Microsoft.Toolkit.Uwp.UI.Controls.Primitivs
};
foreach (var typeInfo in assembly.ExportedTypes)
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
// Search in Microsoft.Toolkit.Graph.Controls
var graphControlsProxyType = typeof(UserToPersonConverter);
assembly = graphControlsProxyType.GetTypeInfo().Assembly;
foreach (var typeInfo in assembly.ExportedTypes)
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
// Search in Microsoft.Toolkit.Uwp.UI.Animations
var animationsProxyType = EasingType.Default;
assembly = animationsProxyType.GetType().GetTypeInfo().Assembly;
foreach (var typeInfo in assembly.ExportedTypes)
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
// Search in Microsoft.Toolkit.Uwp.UI
var uiProxyType = ImageBlendMode.Multiply;
assembly = uiProxyType.GetType().GetTypeInfo().Assembly;
foreach (var typeInfo in assembly.ExportedTypes)
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
// Search in Microsoft.Toolkit.Uwp.Input.GazeInteraction
var gazeType = Interaction.Enabled;
assembly = gazeType.GetType().GetTypeInfo().Assembly;
foreach (var typeInfo in assembly.ExportedTypes)
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
// Search in Microsoft.Toolkit.Uwp.UI.Controls.DataGrid
var dataGridProxyType = DataGridGridLinesVisibility.None;
assembly = dataGridProxyType.GetType().GetTypeInfo().Assembly;
foreach (var typeInfo in assembly.ExportedTypes)
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
// Search in Microsoft.Toolkit.Uwp.UI.Controls.Markdown
var markdownTextBlockType = typeof(MarkdownTextBlock);
assembly = markdownTextBlockType.GetTypeInfo().Assembly;
foreach (var typeInfo in assembly.ExportedTypes)
{
if (typeInfo.Name == typeName)
{
return typeInfo;
}
}
return null;
return targets.SelectMany(t => t.Assembly.ExportedTypes)
.FirstOrDefault(t => t.Name == typeName);
}
private static async Task<string> GetDocsSHA()

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

@ -21,7 +21,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private static LinkedList<Sample> _recentSamples;
private static RoamingObjectStorageHelper _roamingObjectStorageHelper = new RoamingObjectStorageHelper();
private static LocalObjectStorageHelper _localObjectStorageHelper = new LocalObjectStorageHelper(new SystemSerializer());
public static async Task<SampleCategory> GetCategoryBySample(Sample sample)
{
@ -98,7 +98,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
if (_recentSamples == null)
{
_recentSamples = new LinkedList<Sample>();
var savedSamples = _roamingObjectStorageHelper.Read<string>(_recentSamplesStorageKey);
var savedSamples = _localObjectStorageHelper.Read<string>(_recentSamplesStorageKey);
if (savedSamples != null)
{
@ -144,7 +144,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
}
var str = string.Join(";", _recentSamples.Take(10).Select(s => s.Name).ToArray());
_roamingObjectStorageHelper.Save<string>(_recentSamplesStorageKey, str);
_localObjectStorageHelper.Save<string>(_recentSamplesStorageKey, str);
}
}
}

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

@ -1,158 +1,176 @@
<Page x:Class="Microsoft.Toolkit.Uwp.SampleApp.Pages.About"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:extensions="using:Microsoft.Toolkit.Uwp.UI.Extensions"
xmlns:sampleapp="using:Microsoft.Toolkit.Uwp.SampleApp"
xmlns:local="using:Microsoft.Toolkit.Uwp.SampleApp.Pages"
xmlns:animations="using:Microsoft.Toolkit.Uwp.UI.Animations"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:extensions="using:Microsoft.Toolkit.Uwp.UI.Extensions"
xmlns:local="using:Microsoft.Toolkit.Uwp.SampleApp.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sampleapp="using:Microsoft.Toolkit.Uwp.SampleApp"
Loaded="Page_Loaded"
mc:Ignorable="d">
<Page.Resources>
<animations:AnimationCollection x:Key="ImplicitOffset">
<animations:OffsetAnimation Duration="0:0:0.3"></animations:OffsetAnimation>
</animations:AnimationCollection>
<animations:ImplicitAnimationSet x:Key="ImplicitOffset">
<animations:OffsetAnimation Duration="0:0:0.3" />
</animations:ImplicitAnimationSet>
<Style TargetType="ContentPresenter" x:Key="ItemsContainerStyle">
<Setter Property="animations:Implicit.Animations" Value="{StaticResource ImplicitOffset}"></Setter>
<Style x:Key="ItemsContainerStyle"
TargetType="ContentPresenter">
<Setter Property="animations:Implicit.Animations" Value="{StaticResource ImplicitOffset}" />
</Style>
<DataTemplate x:DataType="sampleapp:Sample" x:Key="RecentSampleTemplate">
<DataTemplate x:Key="RecentSampleTemplate"
x:DataType="sampleapp:Sample">
<HyperlinkButton Width="267"
HorizontalContentAlignment="Left"
Style="{StaticResource AboutHyperlinkButtonStyle}"
Click="RecentSample_Click">
<TextBlock Text="{x:Bind Name}"></TextBlock>
Click="RecentSample_Click"
Style="{StaticResource AboutHyperlinkButtonStyle}">
<TextBlock Text="{x:Bind Name}" />
</HyperlinkButton>
</DataTemplate>
<DataTemplate x:DataType="sampleapp:Sample" x:Key="NewSampleTemplate">
<HyperlinkButton Width="267" HorizontalContentAlignment="Left" Style="{StaticResource AboutHyperlinkButtonStyle}" Click="NewSample_Click">
<TextBlock Text="{x:Bind Name}"></TextBlock>
<DataTemplate x:Key="NewSampleTemplate"
x:DataType="sampleapp:Sample">
<HyperlinkButton Width="267"
HorizontalContentAlignment="Left"
Click="NewSample_Click"
Style="{StaticResource AboutHyperlinkButtonStyle}">
<TextBlock Text="{x:Bind Name}" />
</HyperlinkButton>
</DataTemplate>
<DataTemplate x:DataType="sampleapp:GitHubRelease" x:Key="ReleaseNoteTemplate">
<HyperlinkButton HorizontalAlignment="Left"
<DataTemplate x:Key="ReleaseNoteTemplate"
x:DataType="sampleapp:GitHubRelease">
<HyperlinkButton Width="208"
HorizontalAlignment="Left"
HorizontalContentAlignment="Stretch"
NavigateUri="{x:Bind Url}"
Width="208"
Click="ReleaseNotes_Click"
NavigateUri="{x:Bind Url}"
Style="{StaticResource AboutHyperlinkButtonStyle}">
<Grid>
<TextBlock Text="{x:Bind FullName}"></TextBlock>
<TextBlock Text="{x:Bind FullName}" />
<TextBlock HorizontalAlignment="Right"
Opacity="0.5"
Text="{x:Bind Published.ToString('MMM d', {x:Null})}"></TextBlock>
Text="{x:Bind Published.ToString('MMM d', {x:Null})}" />
</Grid>
</HyperlinkButton>
</DataTemplate>
<DataTemplate x:DataType="sampleapp:LandingPageLink" x:Key="LinkTemplate">
<HyperlinkButton Style="{StaticResource AboutHyperlinkButtonStyle}"
<DataTemplate x:Key="LinkTemplate"
x:DataType="sampleapp:LandingPageLink">
<HyperlinkButton Click="Link_Clicked"
NavigateUri="{x:Bind Url}"
Click="Link_Clicked">
<TextBlock Text="{x:Bind Title}"></TextBlock>
Style="{StaticResource AboutHyperlinkButtonStyle}">
<TextBlock Text="{x:Bind Title}" />
</HyperlinkButton>
</DataTemplate>
<ItemsPanelTemplate x:Key="ItemsWrapGridHorizontalTemplate">
<controls:WrapPanel Orientation="Horizontal"></controls:WrapPanel>
<controls:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Page.Resources>
<Grid x:Name="Root" Visibility="Collapsed" extensions:VisualExtensions.NormalizedCenterPoint="0.5">
<Grid x:Name="Root"
extensions:VisualExtensions.NormalizedCenterPoint="0.5"
Visibility="Collapsed">
<controls:DropShadowPanel x:Name="DropShadow"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Color="Black"
BlurRadius="30"
ShadowOpacity="0">
ShadowOpacity="0"
Color="Black">
<Grid x:Name="RootGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="664"></ColumnDefinition>
<ColumnDefinition Width="336"></ColumnDefinition>
<ColumnDefinition Width="664" />
<ColumnDefinition Width="336" />
</Grid.ColumnDefinitions>
<Border Grid.Column="1"
x:Name="RightBorder"
Background="{ThemeResource Background-AboutPage-SidePane}"
extensions:VisualExtensions.NormalizedCenterPoint="0, 0.5, 0">
<Border x:Name="RightBorder"
Grid.Column="1"
extensions:VisualExtensions.NormalizedCenterPoint="0, 0.5"
Background="{ThemeResource Background-AboutPage-SidePane}">
<animations:Implicit.ShowAnimations>
<animations:ScaleAnimation From="0, 1, 0" To="1" Duration="0:0:0.3"></animations:ScaleAnimation>
<animations:ScaleAnimation From="0, 1, 0"
To="1"
Duration="0:0:0.3" />
</animations:Implicit.ShowAnimations>
<animations:Implicit.HideAnimations>
<animations:ScaleAnimation From="1" To="0, 1, 0" Duration="0:0:0.3"></animations:ScaleAnimation>
<animations:ScaleAnimation From="1"
To="0, 1, 0"
Duration="0:0:0.3" />
</animations:Implicit.HideAnimations>
</Border>
<Border Background="{ThemeResource Background-AboutPage-Main}"></Border>
<Border Background="{ThemeResource Background-AboutPage-Main}" />
<Border Background="{ThemeResource Border-AboutPage-Vertical}" Width="1" HorizontalAlignment="Right"></Border>
<Border Width="1"
HorizontalAlignment="Right"
Background="{ThemeResource Border-AboutPage-Vertical}" />
<ScrollViewer x:Name="Scroller" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto">
<Grid x:Name="InnerGrid" HorizontalAlignment="Center" animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<ScrollViewer x:Name="Scroller"
Grid.ColumnSpan="2"
VerticalScrollBarVisibility="Auto">
<Grid x:Name="InnerGrid"
HorizontalAlignment="Center"
animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="64"></ColumnDefinition>
<ColumnDefinition Width="536"></ColumnDefinition>
<ColumnDefinition Width="64"></ColumnDefinition>
<ColumnDefinition Width="64"></ColumnDefinition>
<ColumnDefinition Width="208"></ColumnDefinition>
<ColumnDefinition Width="64"></ColumnDefinition>
<ColumnDefinition Width="64" />
<ColumnDefinition Width="536" />
<ColumnDefinition Width="64" />
<ColumnDefinition Width="64" />
<ColumnDefinition Width="208" />
<ColumnDefinition Width="64" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="84"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="36"></RowDefinition>
<RowDefinition Height="84" />
<RowDefinition Height="Auto" />
<RowDefinition Height="50" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="36" />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="1"
Grid.Column="1">
<TextBlock
FontSize="36"
FontFamily="Segoe UI"
FontWeight="Bold"
Text="Get Started" />
<StackPanel Grid.Row="1"
Grid.Column="1">
<TextBlock FontFamily="Segoe UI"
FontSize="36"
FontWeight="Bold"
Text="Get Started" />
<TextBlock
TextWrapping="Wrap"
FontSize="14"
Margin="0,20,0,0"
Foreground="{ThemeResource Brush-Link-Normal}"
Text="The Windows Community Toolkit is a collection of helper functions, custom controls, and app services. It simplifies and demonstrates common developer patterns when building experiences for Windows 10." />
<TextBlock Margin="0,20,0,0"
FontSize="14"
Foreground="{ThemeResource Brush-Link-Normal}"
Text="The Windows Community Toolkit is a collection of helper functions, custom controls, and app services. It simplifies and demonstrates common developer patterns when building experiences for Windows 10."
TextWrapping="Wrap" />
</StackPanel>
<Grid Grid.Row="3" Grid.Column="1" animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<Grid Grid.Row="3"
Grid.Column="1"
animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<StackPanel>
<TextBlock Style="{StaticResource AboutPageHeader}">Recent Activity</TextBlock>
<Grid Margin="0,16,0,0">
<TextBlock Text="None"
Opacity="0.5"
FontFamily="Segoe UI"
FontSize="12"
Visibility="{x:Bind local:About.VisibleIfCollectionEmpty(RecentSamples), Mode=OneWay}"></TextBlock>
<TextBlock FontFamily="Segoe UI"
FontSize="12"
Opacity="0.5"
Text="None"
Visibility="{x:Bind local:About.VisibleIfCollectionEmpty(RecentSamples), Mode=OneWay}" />
<ItemsControl x:Name="RecentSamplesItemsControl"
ItemsPanel="{StaticResource ItemsWrapGridHorizontalTemplate}"
ItemsSource="{x:Bind RecentSamples, Mode=OneWay}"
ItemContainerStyle="{StaticResource ItemsContainerStyle}"
ItemTemplate="{StaticResource RecentSampleTemplate}"
ItemContainerStyle="{StaticResource ItemsContainerStyle}">
</ItemsControl>
ItemsPanel="{StaticResource ItemsWrapGridHorizontalTemplate}"
ItemsSource="{x:Bind RecentSamples, Mode=OneWay}" />
</Grid>
</StackPanel>
</Grid>
@ -161,36 +179,49 @@
Grid.Row="3"
Grid.RowSpan="3"
Grid.Column="4"
ItemsPanel="{StaticResource ItemsWrapGridHorizontalTemplate}"
animations:Implicit.Animations="{StaticResource ImplicitOffset}">
animations:Implicit.Animations="{StaticResource ImplicitOffset}"
ItemsPanel="{StaticResource ItemsWrapGridHorizontalTemplate}">
<StackPanel x:Name="WhatNewPanel" Margin="0,0,0,48" animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<TextBlock Style="{StaticResource AboutPageHeader}" Text="{x:Bind LandingPageLinks.NewSectionTitle, Mode=OneWay}" />
<ItemsControl x:Name="WhatNewItemsControl" Margin="0,16,0,0" ItemsSource="{x:Bind NewSamples, Mode=OneWay}" ItemTemplate="{StaticResource NewSampleTemplate}"></ItemsControl>
<StackPanel x:Name="WhatNewPanel"
Margin="0,0,0,48"
animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<TextBlock Style="{StaticResource AboutPageHeader}"
Text="{x:Bind LandingPageLinks.NewSectionTitle, Mode=OneWay}" />
<ItemsControl x:Name="WhatNewItemsControl"
Margin="0,16,0,0"
ItemTemplate="{StaticResource NewSampleTemplate}"
ItemsSource="{x:Bind NewSamples, Mode=OneWay}" />
</StackPanel>
<StackPanel x:Name="ReleaseNotesPanel" animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<StackPanel x:Name="ReleaseNotesPanel"
animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<TextBlock Style="{StaticResource AboutPageHeader}">Release Notes</TextBlock>
<ItemsControl Margin="0,16,0,0" ItemsSource="{x:Bind GitHubReleases, Mode=OneWay}" ItemTemplate="{StaticResource ReleaseNoteTemplate}"></ItemsControl>
<ItemsControl Margin="0,16,0,0"
ItemTemplate="{StaticResource ReleaseNoteTemplate}"
ItemsSource="{x:Bind GitHubReleases, Mode=OneWay}" />
</StackPanel>
</ItemsControl>
<ItemsControl x:Name="ResourcesSection"
Grid.Row="5"
Grid.Column="1"
ItemsSource="{x:Bind LandingPageLinks.Resources, Mode=OneWay}"
animations:Implicit.Animations="{StaticResource ImplicitOffset}"
ItemsPanel="{StaticResource ItemsWrapGridHorizontalTemplate}"
animations:Implicit.Animations="{StaticResource ImplicitOffset}">
ItemsSource="{x:Bind LandingPageLinks.Resources, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="sampleapp:LandingPageResource">
<StackPanel MinWidth="267" Margin="0,0,0,48" animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<TextBlock Style="{StaticResource AboutPageHeader}" Text="{x:Bind Title}" />
<ItemsControl
ItemsSource="{x:Bind Links}"
Margin="0,16,0,0">
<StackPanel MinWidth="267"
Margin="0,0,0,48"
animations:Implicit.Animations="{StaticResource ImplicitOffset}">
<TextBlock Style="{StaticResource AboutPageHeader}"
Text="{x:Bind Title}" />
<ItemsControl Margin="0,16,0,0"
ItemsSource="{x:Bind Links}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="sampleapp:LandingPageLink">
<HyperlinkButton Style="{StaticResource AboutHyperlinkButtonStyle}" NavigateUri="{x:Bind Url}" Click="Link_Clicked">
<HyperlinkButton Click="Link_Clicked"
NavigateUri="{x:Bind Url}"
Style="{StaticResource AboutHyperlinkButtonStyle}">
<TextBlock Text="{x:Bind Title}" />
</HyperlinkButton>
</DataTemplate>
@ -204,18 +235,25 @@
<Border x:Name="Separator"
Grid.Row="4"
Grid.Column="4"
BorderThickness="0,1,0,0"
BorderBrush="{ThemeResource Border-AboutPage-Horizontal}"
Margin="0,48"
animations:Implicit.Animations="{StaticResource ImplicitOffset}"></Border>
animations:Implicit.Animations="{StaticResource ImplicitOffset}"
BorderBrush="{ThemeResource Border-AboutPage-Horizontal}"
BorderThickness="0,1,0,0" />
<Border Grid.Row="4"
Grid.Column="1"
BorderThickness="0,1,0,0"
BorderBrush="{ThemeResource Border-AboutPage-Horizontal}"
Margin="0,48"
animations:Implicit.Animations="{StaticResource ImplicitOffset}"></Border>
animations:Implicit.Animations="{StaticResource ImplicitOffset}"
BorderBrush="{ThemeResource Border-AboutPage-Horizontal}"
BorderThickness="0,1,0,0" />
<HyperlinkButton animations:Implicit.Animations="{StaticResource ImplicitOffset}" x:Name="PrivacyButton" Grid.Row="9" Grid.Column="4" VerticalAlignment="Bottom" HorizontalAlignment="Center" Style="{StaticResource AboutHyperlinkButtonStyle}" NavigateUri="https://go.microsoft.com/fwlink/?LinkId=521839">
<HyperlinkButton x:Name="PrivacyButton"
Grid.Row="9"
Grid.Column="4"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
animations:Implicit.Animations="{StaticResource ImplicitOffset}"
NavigateUri="https://go.microsoft.com/fwlink/?LinkId=521839"
Style="{StaticResource AboutHyperlinkButtonStyle}">
<TextBlock>Privacy statement</TextBlock>
</HyperlinkButton>
</Grid>
@ -224,12 +262,20 @@
</controls:DropShadowPanel>
<animations:Implicit.ShowAnimations>
<animations:OpacityAnimation From="0" To="1" Duration="0:0:0.5"></animations:OpacityAnimation>
<animations:ScaleAnimation From="0.9" To="1" Duration="0:0:0.5"></animations:ScaleAnimation>
<animations:OpacityAnimation From="0"
To="1"
Duration="0:0:0.5" />
<animations:ScaleAnimation From="0.9"
To="1"
Duration="0:0:0.5" />
</animations:Implicit.ShowAnimations>
<animations:Implicit.HideAnimations>
<animations:OpacityAnimation From="1" To="0" Duration="0:0:0.2"></animations:OpacityAnimation>
<animations:ScaleAnimation To="0.9" From="1" Duration="0:0:0.2"></animations:ScaleAnimation>
<animations:OpacityAnimation From="1"
To="0"
Duration="0:0:0.2" />
<animations:ScaleAnimation From="1"
To="0.9"
Duration="0:0:0.2" />
</animations:Implicit.HideAnimations>
<VisualStateManager.VisualStateGroups>
@ -267,7 +313,7 @@
<Setter Target="WhatNewItemsControl.MinHeight" Value="0" />
<Setter Target="RecentSamplesItemsControl.MinHeight" Value="0" />
<Setter Target="RightBorder.Visibility" Value="Collapsed"></Setter>
<Setter Target="RightBorder.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="WideState">
@ -303,7 +349,7 @@
<Setter Target="WhatNewItemsControl.MinHeight" Value="130" />
<Setter Target="RecentSamplesItemsControl.MinHeight" Value="130" />
<Setter Target="RightBorder.Visibility" Value="Visible"></Setter>
<Setter Target="RightBorder.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>

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

@ -151,8 +151,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.Pages
From = 0,
To = 1,
Duration = TimeSpan.FromMilliseconds(300),
Delay = TimeSpan.FromMilliseconds(counter++ * delay),
SetInitialValueBeforeDelay = true
Delay = TimeSpan.FromMilliseconds(counter++ * delay)
});
}
}

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

@ -0,0 +1,54 @@
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
xmlns:mediaactions="using:Microsoft.Xaml.Interactions.Media"
xmlns:ani="using:Microsoft.Toolkit.Uwp.UI.Animations"
xmlns:behaviors="using:Microsoft.Toolkit.Uwp.UI.Behaviors"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
mc:Ignorable="d">
<Button Background="Gray" Width="200" Height="200" HorizontalAlignment="Center" VerticalAlignment="Center">
<ani:Explicit.Animations>
<ani:AnimationSet x:Name="MoveAnimation" IsSequential="True">
<ani:StartAnimationActivity Animation="{Binding ElementName=FadeOutAnimation}"/>
<ani:InvokeActionsActivity>
<interactions:ChangePropertyAction TargetObject="{Binding ElementName=MyText}" PropertyName="Foreground" Value="Purple"/>
<mediaactions:PlaySoundAction Source="Assets/Llama.mp3"/>
</ani:InvokeActionsActivity>
<ani:StartAnimationActivity Delay="0:0:2" Animation="{Binding ElementName=FadeInAnimation}"/>
</ani:AnimationSet>
</ani:Explicit.Animations>
<TextBlock x:Name="MyText" Text="🦙 Text">
<ani:Explicit.Animations>
<ani:AnimationSet x:Name="FadeOutAnimation">
<ani:OpacityAnimation From="1"
To="0"
Duration="0:0:1"
Delay="0"
EasingType="Linear"
EasingMode="EaseOut"/>
</ani:AnimationSet>
<ani:AnimationSet x:Name="FadeInAnimation">
<ani:OpacityAnimation From="0"
To="1"
Duration="0:0:1"
Delay="0"
EasingType="Linear"
EasingMode="EaseOut"/>
</ani:AnimationSet>
</ani:Explicit.Animations>
</TextBlock>
<interactivity:Interaction.Behaviors>
<interactions:EventTriggerBehavior EventName="Click">
<interactions:ChangePropertyAction TargetObject="{Binding ElementName=MyText}" PropertyName="Foreground" Value="White"/>
<behaviors:StartAnimationAction Animation="{Binding ElementName=MoveAnimation}"/>
</interactions:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</Button>
</Page>

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

@ -0,0 +1,50 @@
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
xmlns:ani="using:Microsoft.Toolkit.Uwp.UI.Animations"
xmlns:behaviors="using:Microsoft.Toolkit.Uwp.UI.Behaviors"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
mc:Ignorable="d">
<Button Background="Gray" Width="200" Height="200" HorizontalAlignment="Center" VerticalAlignment="Center">
<ani:Explicit.Animations>
<ani:AnimationSet x:Name="MoveAnimation" IsSequential="True">
<ani:TranslationAnimation Duration="0:0:3" To="0,32,0" From="0,0,0" />
<ani:StartAnimationActivity Delay="0:0:3" Animation="{Binding ElementName=FadeOutAnimation}"/>
<ani:StartAnimationActivity Delay="0:0:3" Animation="{Binding ElementName=FadeInAnimation}"/>
<ani:TranslationAnimation Duration="0:0:1" To="0,0,0" From="0,32,0" />
</ani:AnimationSet>
</ani:Explicit.Animations>
<Image Source="ms-appx:///Assets/ToolkitLogo.png" Height="100" Width="100">
<ani:Explicit.Animations>
<ani:AnimationSet x:Name="FadeOutAnimation">
<ani:OpacityAnimation From="1"
To="0"
Duration="0:0:1"
Delay="0"
EasingType="Linear"
EasingMode="EaseOut"/>
</ani:AnimationSet>
<ani:AnimationSet x:Name="FadeInAnimation">
<ani:OpacityAnimation From="0"
To="1"
Duration="0:0:1"
Delay="0"
EasingType="Linear"
EasingMode="EaseOut"/>
</ani:AnimationSet>
</ani:Explicit.Animations>
</Image>
<interactivity:Interaction.Behaviors>
<interactions:EventTriggerBehavior EventName="Click">
<behaviors:StartAnimationAction Animation="{Binding ElementName=MoveAnimation}"/>
</interactions:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</Button>
</Page>

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

До

Ширина:  |  Высота:  |  Размер: 4.4 KiB

После

Ширина:  |  Высота:  |  Размер: 4.4 KiB

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

@ -0,0 +1,14 @@
// XAML UIElement
<Image x:Name="ToolkitLogo" Source="ms-appx:///Assets/Square150x150Logo.png" Height="100" Width="100" >
// C# - Blur can be applied to any UIElement. In this case it is an image called ToolkitLogo.
using Microsoft.Toolkit.Uwp.UI.Animations;
// Create and attacha a sprite visual with an animatable blur effect
var sprite = await PipelineBuilder
.FromBackdrop()
.Blur(0, out EffectAnimation<float> blurAnimation)
.AttachAsync(ToolkitLogo, ToolkitLogo);
// Start the animation on the applied brush
blurAnimation(sprite.Brush, 32, TimeSpan.FromSeconds(3));

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше