Merge branch 'main' into winui

# Conflicts:
#	CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs
#	CommunityToolkit.WinUI.UI.Controls.Primitives/ConstrainedBox/ConstrainedBox.Properties.cs
#	CommunityToolkit.WinUI.UI.Controls.Primitives/ConstrainedBox/ConstrainedBox.cs
#	Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
#	UITests/UITests.Tests.Shared/Controls/GridSplitterTest.cs
#	UITests/UITests.Tests.Shared/Controls/RichSuggestBoxTest.cs
#	UITests/UITests.Tests.Shared/UITestBase.cs
#	UITests/UITests.Tests.TAEF/UITests.App.dependencies.Debug.txt
#	UITests/UITests.Tests.TAEF/UITests.App.dependencies.Release.txt
#	Windows Community Toolkit.sln
#	build/Windows.Toolkit.WinUI.Controls.targets
This commit is contained in:
Alexandre Zollinger Chohfi 2021-09-17 11:57:10 -07:00
Родитель 323e006837 7816189147
Коммит 5c5c487205
30 изменённых файлов: 463 добавлений и 81 удалений

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

@ -443,7 +443,7 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.DebuggerNonUserCode")))),
AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage")))))
.AddAttributeLists(validationAttributes.Select(static a => AttributeList(SingletonSeparatedList(a))).ToArray())
.WithLeadingTrivia(leadingTrivia)
.WithLeadingTrivia(leadingTrivia.Where(static trivia => !trivia.IsKind(SyntaxKind.RegionDirectiveTrivia) && !trivia.IsKind(SyntaxKind.EndRegionDirectiveTrivia)))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
@ -459,7 +459,7 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
/// <param name="fieldSymbol">The input <see cref="IFieldSymbol"/> instance to process.</param>
/// <returns>The generated property name for <paramref name="fieldSymbol"/>.</returns>
[Pure]
private static string GetGeneratedPropertyName(IFieldSymbol fieldSymbol)
public static string GetGeneratedPropertyName(IFieldSymbol fieldSymbol)
{
string propertyName = fieldSymbol.Name;

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

@ -16,6 +16,8 @@ using Microsoft.CodeAnalysis.Text;
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
#pragma warning disable SA1008
namespace CommunityToolkit.Mvvm.SourceGenerators
{
/// <summary>
@ -46,8 +48,10 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, null));
}
// Get the symbol for the ValidationAttribute type
INamedTypeSymbol validationSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.DataAnnotations.ValidationAttribute")!;
// Get the symbol for the required attributes
INamedTypeSymbol
validationSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.DataAnnotations.ValidationAttribute")!,
observablePropertySymbol = context.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservablePropertyAttribute")!;
// Prepare the attributes to add to the first class declaration
AttributeListSyntax[] classAttributes = new[]
@ -145,14 +149,14 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
Parameter(Identifier("obj")).WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword))))
.WithBody(Block(
LocalDeclarationStatement(
VariableDeclaration(IdentifierName("var")) // Cannot Token(SyntaxKind.VarKeyword) here (throws an ArgumentException)
VariableDeclaration(IdentifierName("var")) // Cannot use Token(SyntaxKind.VarKeyword) here (throws an ArgumentException)
.AddVariables(
VariableDeclarator(Identifier("instance"))
.WithInitializer(EqualsValueClause(
CastExpression(
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
IdentifierName("obj")))))))
.AddStatements(EnumerateValidationStatements(classSymbol, validationSymbol).ToArray())),
.AddStatements(EnumerateValidationStatements(classSymbol, validationSymbol, observablePropertySymbol).ToArray())),
ReturnStatement(IdentifierName("ValidateAllProperties")))))))
.NormalizeWhitespace()
.ToFullString();
@ -166,28 +170,47 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
}
/// <summary>
/// Gets a sequence of statements to validate declared properties.
/// Gets a sequence of statements to validate declared properties (including generated ones).
/// </summary>
/// <param name="classSymbol">The input <see cref="INamedTypeSymbol"/> instance to process.</param>
/// <param name="validationSymbol">The type symbol for the <c>ValidationAttribute</c> type.</param>
/// <param name="observablePropertySymbol">The type symbol for the <c>ObservablePropertyAttribute</c> type.</param>
/// <returns>The sequence of <see cref="StatementSyntax"/> instances to validate declared properties.</returns>
[Pure]
private static IEnumerable<StatementSyntax> EnumerateValidationStatements(INamedTypeSymbol classSymbol, INamedTypeSymbol validationSymbol)
private static IEnumerable<StatementSyntax> EnumerateValidationStatements(INamedTypeSymbol classSymbol, INamedTypeSymbol validationSymbol, INamedTypeSymbol observablePropertySymbol)
{
foreach (var propertySymbol in classSymbol.GetMembers().OfType<IPropertySymbol>())
foreach (var memberSymbol in classSymbol.GetMembers())
{
if (propertySymbol.IsIndexer)
if (memberSymbol is not (IPropertySymbol { IsIndexer: false } or IFieldSymbol))
{
continue;
}
ImmutableArray<AttributeData> attributes = propertySymbol.GetAttributes();
ImmutableArray<AttributeData> attributes = memberSymbol.GetAttributes();
// Also include fields that are annotated with [ObservableProperty]. This is necessary because
// all generators run in an undefined order and looking at the same original compilation, so the
// current one wouldn't be able to see generated properties from other generators directly.
if (memberSymbol is IFieldSymbol &&
!attributes.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, observablePropertySymbol)))
{
continue;
}
// Skip the current member if there are no validation attributes applied to it
if (!attributes.Any(a => a.AttributeClass?.InheritsFrom(validationSymbol) == true))
{
continue;
}
// Get the target property name either directly or matching the generated one
string propertyName = memberSymbol switch
{
IPropertySymbol propertySymbol => propertySymbol.Name,
IFieldSymbol fieldSymbol => ObservablePropertyGenerator.GetGeneratedPropertyName(fieldSymbol),
_ => throw new InvalidOperationException("Invalid symbol type")
};
// This enumerator produces a sequence of statements as follows:
//
// __ObservableValidatorHelper.ValidateProperty(instance, instance.<PROPERTY_0>, nameof(instance.<PROPERTY_0>));
@ -207,14 +230,14 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("instance"),
IdentifierName(propertySymbol.Name))),
IdentifierName(propertyName))),
Argument(
InvocationExpression(IdentifierName("nameof"))
.AddArgumentListArguments(Argument(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("instance"),
IdentifierName(propertySymbol.Name)))))));
IdentifierName(propertyName)))))));
}
}
}

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

@ -110,6 +110,7 @@
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="40" />
<Setter Property="Padding" Value="4" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="HighContrastAdjustment" Value="None" />
<Setter Property="Template">
@ -264,7 +265,7 @@
VerticalAlignment="Center"
Visibility="{Binding ShowDismissButton, ElementName=ExampleCustomInAppNotification}">
<Button.RenderTransform>
<TranslateTransform x:Name="DismissButtonTransform" X="25" Y="-5"/>
<TranslateTransform x:Name="DismissButtonTransform" X="20" Y="1"/>
</Button.RenderTransform>
</Button>
</Grid>

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

@ -89,7 +89,9 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
private AdvancedCollectionView _acv;
private AdvancedCollectionView _acvEmail;
private ObservableCollection<SampleEmailDataType> _selectedEmails;
public ObservableCollection<SampleDataType> SelectedTokens { get; set; }
public ObservableCollection<SampleEmailDataType> SelectedEmails { get; set; }
public TokenizingTextBoxPage()
{
@ -111,7 +113,10 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
public void OnXamlRendered(FrameworkElement control)
{
_selectedEmails = new ObservableCollection<SampleEmailDataType>();
SelectedTokens = new();
SelectedEmails = new();
control.DataContext = this;
if (_ttb != null)
{
@ -149,7 +154,6 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
{
_ttbEmail = ttbEmail;
_ttbEmail.ItemsSource = _selectedEmails;
_ttbEmail.ItemClick += EmailTokenItemClick;
_ttbEmail.TokenItemAdding += EmailTokenItemAdding;
_ttbEmail.TokenItemAdded += EmailTokenItemAdded;

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

@ -37,6 +37,7 @@
</TextBlock>
<controls:TokenizingTextBox
x:Name="TokenBox"
ItemsSource="{Binding SelectedTokens}"
PlaceholderText="Add Actions"
QueryIcon="{ui:SymbolIconSource Symbol=Setting}"
MaxHeight="104"
@ -65,7 +66,7 @@
<Run>Current Edit: </Run>
<Run Text="{Binding Text, ElementName=TokenBox}"/>
</TextBlock>
<ItemsControl ItemsSource="{Binding ItemsSource, ElementName=TokenBox}"/>
<ItemsControl ItemsSource="{Binding SelectedTokens}"/>
</StackPanel>
<StackPanel Grid.Row="1">
@ -73,6 +74,7 @@
Margin="0,0,0,4"/>
<controls:TokenizingTextBox
x:Name="TokenBoxEmail"
ItemsSource="{Binding SelectedEmails}"
PlaceholderText="Select Names"
MaxHeight="104"
HorizontalAlignment="Stretch"

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

@ -9,15 +9,16 @@
<Title>Windows Community Toolkit - UI Behaviors</Title>
<Description>
This library provides UI behaviors built on the XAML behaviors SDK. It is a part of the Windows Community Toolkit.
Behaviors:
- BehaviorBase: Helper for building Behaviors
- Animation: Various helpers for integration with the Toolkit's Animation package.
- AutoFocusBehevior: Sets focus to the associated control.
- FocusBehavior: Sets focus to a specified control.
- ViewportBehavior: Listening for element to enter or exit the ScrollViewer viewport
- AutoSelectBehavior: Selects a TextBox's text automatically.
- FadeHeaderBehavior, QuickReturnHeaderBehavior, StickyHeaderBehavior: Helpers for ListViewBase Header Behavior
- FocusBehavior: Sets focus to a specified control.
- KeyDownTriggerBehavior: Trigger behaviors when a key is pressed.
- ViewportBehavior: Listening for element to enter or exit the ScrollViewer viewport
</Description>
<PackageTags>UI;XAML;Behaviors;Interactivity;Interaction;Focus;Header;Viewport</PackageTags>
<PackageTags>UI;XAML;Behaviors;Interactivity;Interaction;Focus;Header;Viewport;Selection;Focus;KeyDown;Triggers;Viewport</PackageTags>
</PropertyGroup>
<ItemGroup>

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

@ -16,6 +16,7 @@
- ImageEx: Images are downloaded asynchronously showing a load indicator and can be stored in a local cache.
- InAppNotification: Show local notifications in your application.
- Loading: Helps to show content with animation to the user while the app is doing some calculation.
- MetadataControl: Control for organizing text based categories with a separator, supports commands.
- RadialProgressBar: Displays progress as a circle getting filled.
- RotatorTile: Rotates through a set of items one-by-one like a live-tile.
- TabbedCommandBar: A command bar that organizes features of an application into a series of tabs.
@ -29,6 +30,7 @@
Image;Ex ;ImageEx ;
In;App;Notification;InAppNotification;InApp ;
Loading ;
Metadata;Tags;
Radial;Progress;Bar;RadialProgressBar;ProgressBar ;
Rotator;Tile ;RotatorTile ;
Tabbed;Command;Bar ;TabbedCommandBar ;CommandBar ;

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

@ -43,6 +43,7 @@
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
<Setter Property="Width" Value="{StaticResource SystemControlMSEdgeNotificationDismissButtonSize}" />
<Setter Property="Height" Value="{StaticResource SystemControlMSEdgeNotificationDismissButtonSize}" />
<Setter Property="Padding" Value="4" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="HighContrastAdjustment" Value="None" />
<Setter Property="Template">
@ -150,9 +151,10 @@
FontFamily="Segoe MDL2 Assets"
FontSize="12"
VerticalAlignment="Top"
Padding="4"
Style="{StaticResource DismissTextBlockButtonStyle}">
<Button.RenderTransform>
<TranslateTransform x:Name="DismissButtonTransform" X="25" Y="-5"/>
<TranslateTransform x:Name="DismissButtonTransform" X="20" Y="1"/>
</Button.RenderTransform>
</Button>
</Grid>

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

@ -15,6 +15,7 @@
- RadialGauge: Displays a value within a range, using a needle on a circular face.
- RangeSelector: "Double slider" control for range values.
- RemoteDevicePicker: Remote Device Picker Control for Project Rome.
- RichSuggestBox: RichEditBox which supports at mentioning or tags.
- TokenizingTextBox: An AutoSuggestBox like control which places entered input into easily removed containers for contacts or tags.
</Description>
<PackageTags>
@ -23,6 +24,7 @@
Radial;Gauge ;RadialGauge ;
Range;Selector ;RangeSelector ;
Remote;Device;Picker;RemoteDevicePicker;DevicePicker;RemoteDevice;
RichEditBox;RichSuggestBox;Suggestions;Mentions;Tags;
Tokenizing;Text;Box ;TokenizingTextBox ;TextBox ;
</PackageTags>
</PropertyGroup>

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

@ -163,6 +163,7 @@ namespace CommunityToolkit.WinUI.UI.Controls
OnSelectionChanged(new SelectionChangedEventArgs(new List<object> { e.OldValue }, new List<object> { e.NewValue }));
UpdateView(true);
SetFocus(ViewState);
}
private void OnLoaded(object sender, RoutedEventArgs e)
@ -413,7 +414,7 @@ namespace CommunityToolkit.WinUI.UI.Controls
/// </summary>
private void FocusItemList()
{
if (GetTemplateChild("PartMainList") is Control list)
if (GetTemplateChild(PartMainList) is Control list)
{
list.Focus(FocusState.Programmatic);
}

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

@ -12,6 +12,7 @@
Controls:
- AdaptiveGridView: Presents items in an evenly-spaced set of columns to fill the total available space.
- ConstrainedBox: Constrain child element by aspect ratio, scale, or multiple.
- DockPanel: Define areas where you can arrange child elements either horizontally or vertically, relative to each other.
- StaggeredLayout: Layout of items in a column approach where an item will be added to whichever column has used the least amount of space.
- StaggeredPanel: Layout of items in a column approach where an item will be added to whichever column has used the least amount of space.
@ -23,6 +24,7 @@
<PackageTags>
Controls;XAML;UI;
Adaptive;Grid;View;AdaptiveGridView;GridView ;AdaptiveGrid ;
Constrained;Box;ConstrainedBox;AspectRatio;Aspect;Scale;Multiple;
Dock;Panel ;DockPanel ;
Staggered;Layout ;StaggeredLayout ;
Staggered;Panel ;StaggeredPanel ;

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

@ -2,7 +2,7 @@
// 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.Globalization;
namespace CommunityToolkit.WinUI.UI.Controls
{
@ -75,11 +75,14 @@ namespace CommunityToolkit.WinUI.UI.Controls
if (ratio.Length == 2)
{
return new AspectRatio(Convert.ToDouble(ratio[0]), Convert.ToDouble(ratio[1]));
double width = double.Parse(ratio[0], NumberStyles.Float, CultureInfo.InvariantCulture);
double height = double.Parse(ratio[1], NumberStyles.Float, CultureInfo.InvariantCulture);
return new AspectRatio(width, height);
}
else if (ratio.Length == 1)
{
return new AspectRatio(Convert.ToDouble(ratio[0]));
return new AspectRatio(double.Parse(ratio[0], NumberStyles.Float, CultureInfo.InvariantCulture));
}
return new AspectRatio(1);

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

@ -2,14 +2,7 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation;
namespace CommunityToolkit.WinUI.UI.Controls
{

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

@ -3,10 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation;

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

@ -7,7 +7,26 @@
<PropertyGroup>
<Title>Windows Community Toolkit - UI Media</Title>
<Description>
This library provides UI brushes. It is a part of the Windows Community Toolkit.
This library provides UI effects which rely on Win2D. It is a part of the Windows Community Toolkit.
AttachedCardShadow: Provides an easy-to-use, simple, and performant rounded-rectangle shadow effect.
Effects:
- AcrylicEffect: A custom acrylic effect that can be inserted into a pipeline.
- BackdropEffect: A backdrop effect that can sample from a specified source.
- BlendEffect: A blend effect that merges the current pipeline with an input one.
- BlurEffect: A gaussian blur effect.
- ImageEffect: An effect which displays an image loaded as a Win2D surface.
- ShadeEffect: An effect that overlays a color layer over the current pipeline, with a specified intensity.
- SolidColorEffect: An effect that renders a standard 8bit SDR color on the available surface.
- TileEffect: An effect that loads an image and replicates it to cover all the available surface area.
- ExposureEffect, GrayscaleEffect, HueRotationEffect and more, mapping to Win2D effects.
Geometry:
- CanvasPathGeometry: A class that parses Win2d Path Mini Language and converts it to CanvasGeometry, CanvasBrush, CanvasStroke, CanvasStrokeStyle or Color.
Helpers:
- SurfaceLoader: A class that can load and draw images and other objects to Win2D surfaces and brushes.
Media:
- AcrylicBrush: A custom Brush that that implements an acrylic effect with full control over all parameters.
@ -22,26 +41,9 @@
- RadialGradientBrush: This GradientBrush defines its Gradient as an interpolation within an Ellipse.
- TilesBrush: A Brush that displays a tiled image, wrapping at the edges and endlessly repeating.
Effects:
- AcrylicEffect: A custom acrylic effect that can be inserted into a pipeline.
- BackdropEffect: A backdrop effect that can sample from a specified source.
- BlendEffect: A blend effect that merges the current pipeline with an input one.
- BlurEffect: A gaussian blur effect.
- ImageEffect: An effect which displays an image loaded as a Win2D surface.
- ShadeEffect: An effect that overlays a color layer over the current pipeline, with a specified intensity.
- SolidColorEffect: An effect that renders a standard 8bit SDR color on the available surface.
- TileEffect: An effect that loads an image and replicates it to cover all the available surface area.
- ExposureEffect, GrayscaleEffect, HueRotationEffect and more, mapping to Win2D effects.
Helpers:
- SurfaceLoader: A class that can load and draw images and other objects to Win2D surfaces and brushes.
PipelineBuilder: A class that allows to build custom effects pipelines and create CompositionBrush instances from them.
Geometry:
- CanvasPathGeometry: A class that parses Win2d Path Mini Language and converts it to CanvasGeometry, CanvasBrush, CanvasStroke, CanvasStrokeStyle or Color.
PipelineBuilder: A class that allows to build custom effects pipelines and create CompositionBrush instances from them.
</Description>
<PackageTags>UI;XAML;Acrylic;Brushes;Blur;Effects;Canvas;Geometry</PackageTags>
<PackageTags>UI;XAML;Acrylic;Brushes;Blur;Effects;Canvas;Geometry;Shadow;Shadows;Animation</PackageTags>
</PropertyGroup>
<ItemGroup>

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

@ -9,7 +9,7 @@
<PropertyGroup>
<Title>Windows Community Toolkit - UI</Title>
<Description>
This library provides UI components, such as XAML extensions, helpers, converters and more. It is a part of the Windows Community Toolkit.
This library provides various common UI helpers. It is a part of the Windows Community Toolkit.
AdvancedCollectionView: It's a collection view implementation that support filtering, sorting and incremental loading. It's meant to be used in a viewmodel.
@ -19,6 +19,7 @@
Extensions:
- ApplicationViewExtensions: Provides attached properties for interacting with the ApplicationView on a window (app view).
- AttachedDropShadow: Provides a composition based shadow effect which supports masking.
- FrameworkElementExtensions: Provides attached dependency properties for the FrameworkElement.
- ListViewExtensions: Provides attached dependency properties for the ListViewBase
- LogicalTree: Defines a collection of extensions methods for UI.
@ -42,8 +43,10 @@
- BindableValueHolder: Holds the value. Can be used to change several objects' properties at a time.
- DependencyPropertyWatcher: Used to Track Changes of a Dependency Property
- ThemeListener: Class which listens for changes to Application Theme or High Contrast Modes and Signals an Event when they occur.
Triggers: Various Visual State Triggers to help trigger VisualStates in a wide variety of scenarios.
</Description>
<PackageTags>UI;XAML;ApplicationView;FrameworkElement;SurfaceDial;Matrix;Mouse;TextBoxMask;TitleBar;VisualTree;Converters;Extensions;Helpers</PackageTags>
<PackageTags>UI;XAML;ApplicationView;FrameworkElement;ListView;SurfaceDial;Matrix;Mouse;TextBoxMask;TitleBar;VisualTree;Converters;Extensions;Helpers</PackageTags>
</PropertyGroup>
<ItemGroup>

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

@ -6,8 +6,8 @@
<PropertyGroup>
<Title>Windows Community Toolkit - Common (UWP)</Title>
<Description>This package includes code only helpers such as Colors conversion tool, Storage file handling, a Stream helper class, etc.</Description>
<PackageTags>Storage;File;Folder;Color;Conversion;Stream;Helpers;Extensions</PackageTags>
<Description>This package includes code only helpers such as Color conversion tool, Storage file handling, a Stream helper class, SystemInformation helpers, etc.</Description>
<PackageTags>Storage;File;Folder;Color;Conversion;Stream;Helpers;Extensions;System;Information</PackageTags>
</PropertyGroup>
<ItemGroup>

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

@ -111,7 +111,7 @@
<!-- Only the Layout package have a dependency on WinUI -->
<ItemGroup Condition="$(CurrentProject) == 'UWPBaselineWinUI' or $(CurrentProject) == 'CommunityToolkit.WinUI.UI.Controls.Layout'">
<PackageReference Include="Microsoft.UI.Xaml">
<Version>2.6.2</Version>
<Version>2.7.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(CurrentProject)' != '' and '$(CurrentProject)' != 'UWPBaseline' and '$(CurrentProject)' != 'UWPBaselineWinUI' and '$(NuGetPackageVersion)' != 'To Fill In With Local Version Number'">

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

@ -7,7 +7,6 @@ using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;

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

@ -152,6 +152,10 @@
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>5.0.0</Version>
</PackageReference>
<!-- For warnings ILT0010, ILT0005, ILT0003 -->
<PackageReference Include="System.Xml.XPath.XmlDocument">
<Version>4.0.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\CommunityToolkit.HighPerformance\CommunityToolkit.HighPerformance.csproj">

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

@ -8,6 +8,8 @@ using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using Microsoft.VisualStudio.TestTools.UnitTesting;
#pragma warning disable SA1124
namespace UnitTests.Mvvm
{
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1601", Justification = "Type only used for testing")]
@ -78,6 +80,8 @@ namespace UnitTests.Mvvm
Counter += 1;
}
#region Test region
/// <summary>
/// This is multi line with also other stuff below
/// </summary>
@ -100,6 +104,8 @@ namespace UnitTests.Mvvm
Counter += count;
}
#endregion
[ICommand]
private async Task DelayAndIncrementCounterWithValueAndTokenAsync(int count, CancellationToken token)
{

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

@ -7,10 +7,13 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
#pragma warning disable SA1124
#nullable enable
namespace UnitTests.Mvvm
@ -58,6 +61,86 @@ namespace UnitTests.Mvvm
Assert.AreEqual(changed.Item2, 42);
}
// See https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4225
[TestCategory("Mvvm")]
[TestMethod]
public void Test_ObservablePropertyAttributeWithinRegion_Events()
{
var model = new SampleModel();
(PropertyChangingEventArgs, int) changing = default;
(PropertyChangedEventArgs, int) changed = default;
model.PropertyChanging += (s, e) =>
{
Assert.IsNull(changing.Item1);
Assert.IsNull(changed.Item1);
Assert.AreSame(model, s);
Assert.IsNotNull(s);
Assert.IsNotNull(e);
changing = (e, model.Counter);
};
model.PropertyChanged += (s, e) =>
{
Assert.IsNotNull(changing.Item1);
Assert.IsNull(changed.Item1);
Assert.AreSame(model, s);
Assert.IsNotNull(s);
Assert.IsNotNull(e);
changed = (e, model.Counter);
};
model.Counter = 42;
Assert.AreEqual(changing.Item1?.PropertyName, nameof(SampleModel.Counter));
Assert.AreEqual(changing.Item2, 0);
Assert.AreEqual(changed.Item1?.PropertyName, nameof(SampleModel.Counter));
Assert.AreEqual(changed.Item2, 42);
}
// See https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4225
[TestCategory("Mvvm")]
[TestMethod]
public void Test_ObservablePropertyAttributeRightBelowRegion_Events()
{
var model = new SampleModel();
(PropertyChangingEventArgs, string?) changing = default;
(PropertyChangedEventArgs, string?) changed = default;
model.PropertyChanging += (s, e) =>
{
Assert.IsNull(changing.Item1);
Assert.IsNull(changed.Item1);
Assert.AreSame(model, s);
Assert.IsNotNull(s);
Assert.IsNotNull(e);
changing = (e, model.Name);
};
model.PropertyChanged += (s, e) =>
{
Assert.IsNotNull(changing.Item1);
Assert.IsNull(changed.Item1);
Assert.AreSame(model, s);
Assert.IsNotNull(s);
Assert.IsNotNull(e);
changed = (e, model.Name);
};
model.Name = "Bob";
Assert.AreEqual(changing.Item1?.PropertyName, nameof(SampleModel.Name));
Assert.AreEqual(changing.Item2, null);
Assert.AreEqual(changed.Item1?.PropertyName, nameof(SampleModel.Name));
Assert.AreEqual(changed.Item2, "Bob");
}
[TestCategory("Mvvm")]
[TestMethod]
public void Test_AlsoNotifyChangeForAttribute_Events()
@ -155,6 +238,36 @@ namespace UnitTests.Mvvm
CollectionAssert.AreEqual(new[] { nameof(model.Value) }, propertyNames);
}
// See https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4184
[TestCategory("Mvvm")]
[TestMethod]
public void Test_GeneratedPropertiesWithValidationAttributesOverFields()
{
var model = new ViewModelWithValidatableGeneratedProperties();
List<string?> propertyNames = new();
model.PropertyChanged += (s, e) => propertyNames.Add(e.PropertyName);
// Assign these fields directly to bypass the validation that is executed in the generated setters.
// We only need those generated properties to be there to check whether they are correctly detected.
model.first = "A";
model.last = "This is a very long name that exceeds the maximum length of 60 for this property";
Assert.IsFalse(model.HasErrors);
model.RunValidation();
Assert.IsTrue(model.HasErrors);
ValidationResult[] validationErrors = model.GetErrors().ToArray();
Assert.AreEqual(validationErrors.Length, 2);
CollectionAssert.AreEqual(new[] { nameof(ViewModelWithValidatableGeneratedProperties.First) }, validationErrors[0].MemberNames.ToArray());
CollectionAssert.AreEqual(new[] { nameof(ViewModelWithValidatableGeneratedProperties.Last) }, validationErrors[1].MemberNames.ToArray());
}
public partial class SampleModel : ObservableObject
{
/// <summary>
@ -162,6 +275,16 @@ namespace UnitTests.Mvvm
/// </summary>
[ObservableProperty]
private int data;
#region More properties
[ObservableProperty]
private int counter;
#endregion
[ObservableProperty]
private string? name;
}
[INotifyPropertyChanged]
@ -238,7 +361,7 @@ namespace UnitTests.Mvvm
public partial class ModelWithValueProperty : ObservableObject
{
[ObservableProperty]
private string value;
private string? value;
}
public partial class ModelWithValuePropertyWithValidation : ObservableValidator
@ -246,7 +369,26 @@ namespace UnitTests.Mvvm
[ObservableProperty]
[Required]
[MinLength(5)]
private string value;
private string? value;
}
public partial class ViewModelWithValidatableGeneratedProperties : ObservableValidator
{
[Required]
[MinLength(2)]
[MaxLength(60)]
[Display(Name = "FirstName")]
[ObservableProperty]
public string first = "Bob";
[Display(Name = "LastName")]
[Required]
[MinLength(2)]
[MaxLength(60)]
[ObservableProperty]
public string last = "Jones";
public void RunValidation() => ValidateAllProperties();
}
}
}

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

@ -16,6 +16,9 @@ namespace UnitTests.Notifications.UWP
/// </summary>
public sealed partial class App : Application
{
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// </summary>
public App()
{
InitializeComponent();

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

@ -1,7 +1,17 @@
[*.{cs,vb}]
# SA1601: Partial elements should be documented
# Analyzer Configurations for Unit Test sources
# C# Source Files
[*.cs]
# A C# partial element is missing a documentation header.
dotnet_diagnostic.SA1601.severity = none
# The Parameter has no matching param tag in the XML comment.
dotnet_diagnostic.CS1573.severity = none
# Missing XML comment for publicly visible type or member.
dotnet_diagnostic.CS1591.severity = none
dotnet_diagnostic.CS1712.severity = none
# The Type parameter has no matching typeparam tag in the XML comment.
dotnet_diagnostic.CS1712.severity = none

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

@ -2,14 +2,11 @@
// 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.Linq;
using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp;
using Microsoft.Toolkit.Uwp.UI;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;

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

@ -2,14 +2,12 @@
// 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.Linq;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp;
using Microsoft.Toolkit.Uwp.UI;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;
@ -92,5 +90,76 @@ namespace UnitTests.UWP.UI.Controls
Assert.AreEqual(200, child.ActualHeight, 0.01, "Actual height does not meet expected value of 200");
});
}
[TestCategory("ConstrainedBox")]
[TestMethod]
public void Test_ConstrainedBox_AspectRatioParsing_WidthAndHeight()
{
CultureInfo currentCulture = CultureInfo.CurrentCulture;
try
{
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
AspectRatio ratio = AspectRatio.ConvertToAspectRatio("1.666:1.2");
Assert.AreEqual(ratio.Width, 1.666);
Assert.AreEqual(ratio.Height, 1.2);
// Explicit tests for other culture infos, see https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4252
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("it-IT");
ratio = AspectRatio.ConvertToAspectRatio("1.666:1.2");
Assert.AreEqual(ratio.Width, 1.666);
Assert.AreEqual(ratio.Height, 1.2);
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR");
ratio = AspectRatio.ConvertToAspectRatio("1.666:1.2");
Assert.AreEqual(ratio.Width, 1.666);
Assert.AreEqual(ratio.Height, 1.2);
}
finally
{
CultureInfo.CurrentCulture = currentCulture;
}
}
[TestCategory("ConstrainedBox")]
[TestMethod]
public void Test_ConstrainedBox_AspectRatioParsing_Ratio()
{
CultureInfo currentCulture = CultureInfo.CurrentCulture;
try
{
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
AspectRatio ratio = AspectRatio.ConvertToAspectRatio("1.666");
Assert.AreEqual(ratio.Width, 1.666);
Assert.AreEqual(ratio.Height, 1);
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("it-IT");
ratio = AspectRatio.ConvertToAspectRatio("1.666");
Assert.AreEqual(ratio.Width, 1.666);
Assert.AreEqual(ratio.Height, 1);
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR");
ratio = AspectRatio.ConvertToAspectRatio("1.666");
Assert.AreEqual(ratio.Width, 1.666);
Assert.AreEqual(ratio.Height, 1);
}
finally
{
CultureInfo.CurrentCulture = currentCulture;
}
}
}
}

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

@ -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 CommunityToolkit.WinUI;
using CommunityToolkit.WinUI.UI;
using CommunityToolkit.WinUI.UI.Controls;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Markup;
namespace UnitTests.UWP.UI.Controls
{
[TestClass]
public class Test_ListDetailsView_UI : VisualUITestBase
{
private const string SampleXaml = @"<controls:ListDetailsView
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
xmlns:controls=""using:Microsoft.Toolkit.Uwp.UI.Controls""
NoSelectionContent=""No item selected"" >
<controls:ListDetailsView.ItemTemplate>
<DataTemplate>
<TextBlock Text=""Item"" />
</DataTemplate>
</controls:ListDetailsView.ItemTemplate>
<controls:ListDetailsView.DetailsTemplate>
<DataTemplate>
<TextBox Text=""{Binding}"" />
</DataTemplate>
</controls:ListDetailsView.DetailsTemplate>
</controls:ListDetailsView>";
[TestCategory("ListDetailsView")]
[TestMethod]
public async Task Test_LoseFocusOnNoSelection()
{
await App.DispatcherQueue.EnqueueAsync(async () =>
{
var listDetailsView = XamlReader.Load(SampleXaml) as ListDetailsView;
listDetailsView.ItemsSource = new ObservableCollection<string>
{
"First",
};
listDetailsView.SelectedIndex = 0;
await SetTestContentAsync(listDetailsView);
var firsttb = listDetailsView.FindDescendant<TextBox>();
await App.DispatcherQueue.EnqueueAsync(() => firsttb.Focus(FocusState.Programmatic));
Assert.AreEqual(firsttb, FocusManager.GetFocusedElement(), "TextBox didn't get focus");
var tcs = new TaskCompletionSource<bool>();
firsttb.LostFocus += (s, e) => tcs.SetResult(true);
listDetailsView.SelectedIndex = -1;
await Task.WhenAny(tcs.Task, Task.Delay(2000));
Assert.IsTrue(tcs.Task.IsCompleted);
Assert.IsTrue(tcs.Task.Result, "TextBox in the first item should have lost focus.");
});
}
[TestCategory("ListDetailsView")]
[TestMethod]
public async Task Test_LoseFocusOnSelectOther()
{
await App.DispatcherQueue.EnqueueAsync(async () =>
{
var listDetailsView = XamlReader.Load(SampleXaml) as ListDetailsView;
listDetailsView.ItemsSource = new ObservableCollection<string>
{
"First",
"Second",
};
listDetailsView.SelectedIndex = 0;
await SetTestContentAsync(listDetailsView);
var firsttb = listDetailsView.FindDescendant<TextBox>();
await App.DispatcherQueue.EnqueueAsync(() => firsttb.Focus(FocusState.Programmatic));
Assert.AreEqual(firsttb, FocusManager.GetFocusedElement(), "TextBox didn't get focus");
var tcs = new TaskCompletionSource<bool>();
firsttb.LostFocus += (s, e) => tcs.SetResult(true);
listDetailsView.SelectedIndex = 1;
await Task.WhenAny(tcs.Task, Task.Delay(2000));
Assert.IsTrue(tcs.Task.IsCompleted);
Assert.IsTrue(tcs.Task.Result, "TextBox in the first item should have lost focus.");
});
}
}
}

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

@ -27,7 +27,7 @@
<Version>6.2.12</Version>
</PackageReference>
<PackageReference Include="Microsoft.UI.Xaml">
<Version>2.6.2</Version>
<Version>2.7.0</Version>
</PackageReference>
<PackageReference Include="MSTest.TestAdapter">
<Version>2.2.5</Version>
@ -138,6 +138,7 @@
<Compile Include="UI\Controls\Test_ConstrainedBox.Multiple.cs" />
<Compile Include="UI\Controls\Test_ConstrainedBox.Combined.cs" />
<Compile Include="UI\Controls\Test_ImageEx.cs" />
<Compile Include="UI\Controls\Test_ListDetailsView_UI.cs" />
<Compile Include="UI\Controls\Test_RadialGauge.cs" />
<Compile Include="UI\Controls\Test_RichSuggestBox.cs" />
<Compile Include="UI\Controls\Test_TextToolbar_Localization.cs" />

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

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31521.260
# Visual Studio Version 16
VisualStudioVersion = 16.0.31605.320
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9AD30620-667D-433C-9961-8D885EE7B762}"
EndProject
@ -54,9 +54,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
settings.xamlstyler = settings.xamlstyler
build\Windows.Toolkit.Common.props = build\Windows.Toolkit.Common.props
build\Windows.Toolkit.Common.targets = build\Windows.Toolkit.Common.targets
build\Windows.Toolkit.VisualStudio.Design.props = build\Windows.Toolkit.VisualStudio.Design.props
build\Windows.Toolkit.WinUI.Build.targets = build\Windows.Toolkit.WinUI.Build.targets
build\Windows.Toolkit.WinUI.Controls.targets = build\Windows.Toolkit.WinUI.Controls.targets
build\Windows.Toolkit.VisualStudio.Design.props = build\Windows.Toolkit.VisualStudio.Design.props
build\Windows.Toolkit.VisualStudio.Design.targets = build\Windows.Toolkit.VisualStudio.Design.targets
build\Windows.Toolkit.Workarounds.Xaml.targets = build\Windows.Toolkit.Workarounds.Xaml.targets
EndProjectSection
EndProject

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

@ -15,6 +15,7 @@
<ItemGroup Condition="$(IsPackable)">
<None Include="$(BuildToolsDirectory)nuget.png" Pack="true" PackagePath="\Icon.png" />
<None Include="$(RepositoryDirectory)License.md" Pack="true" PackagePath="\" />
<None Include="$(RepositoryDirectory)ThirdPartyNotices.txt" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>