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

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

@ -16,6 +16,8 @@ using Microsoft.CodeAnalysis.Text;
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors; using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
#pragma warning disable SA1008
namespace CommunityToolkit.Mvvm.SourceGenerators namespace CommunityToolkit.Mvvm.SourceGenerators
{ {
/// <summary> /// <summary>
@ -46,8 +48,10 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, null)); context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, null));
} }
// Get the symbol for the ValidationAttribute type // Get the symbol for the required attributes
INamedTypeSymbol validationSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.DataAnnotations.ValidationAttribute")!; 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 // Prepare the attributes to add to the first class declaration
AttributeListSyntax[] classAttributes = new[] AttributeListSyntax[] classAttributes = new[]
@ -145,14 +149,14 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
Parameter(Identifier("obj")).WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword)))) Parameter(Identifier("obj")).WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword))))
.WithBody(Block( .WithBody(Block(
LocalDeclarationStatement( 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( .AddVariables(
VariableDeclarator(Identifier("instance")) VariableDeclarator(Identifier("instance"))
.WithInitializer(EqualsValueClause( .WithInitializer(EqualsValueClause(
CastExpression( CastExpression(
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)), IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
IdentifierName("obj"))))))) IdentifierName("obj")))))))
.AddStatements(EnumerateValidationStatements(classSymbol, validationSymbol).ToArray())), .AddStatements(EnumerateValidationStatements(classSymbol, validationSymbol, observablePropertySymbol).ToArray())),
ReturnStatement(IdentifierName("ValidateAllProperties"))))))) ReturnStatement(IdentifierName("ValidateAllProperties")))))))
.NormalizeWhitespace() .NormalizeWhitespace()
.ToFullString(); .ToFullString();
@ -166,28 +170,47 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
} }
/// <summary> /// <summary>
/// Gets a sequence of statements to validate declared properties. /// Gets a sequence of statements to validate declared properties (including generated ones).
/// </summary> /// </summary>
/// <param name="classSymbol">The input <see cref="INamedTypeSymbol"/> instance to process.</param> /// <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="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> /// <returns>The sequence of <see cref="StatementSyntax"/> instances to validate declared properties.</returns>
[Pure] [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; 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)) if (!attributes.Any(a => a.AttributeClass?.InheritsFrom(validationSymbol) == true))
{ {
continue; 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: // This enumerator produces a sequence of statements as follows:
// //
// __ObservableValidatorHelper.ValidateProperty(instance, instance.<PROPERTY_0>, nameof(instance.<PROPERTY_0>)); // __ObservableValidatorHelper.ValidateProperty(instance, instance.<PROPERTY_0>, nameof(instance.<PROPERTY_0>));
@ -207,14 +230,14 @@ namespace CommunityToolkit.Mvvm.SourceGenerators
MemberAccessExpression( MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("instance"), IdentifierName("instance"),
IdentifierName(propertySymbol.Name))), IdentifierName(propertyName))),
Argument( Argument(
InvocationExpression(IdentifierName("nameof")) InvocationExpression(IdentifierName("nameof"))
.AddArgumentListArguments(Argument( .AddArgumentListArguments(Argument(
MemberAccessExpression( MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("instance"), IdentifierName("instance"),
IdentifierName(propertySymbol.Name))))))); IdentifierName(propertyName)))))));
} }
} }
} }

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

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

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

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

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

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

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

@ -9,15 +9,16 @@
<Title>Windows Community Toolkit - UI Behaviors</Title> <Title>Windows Community Toolkit - UI Behaviors</Title>
<Description> <Description>
This library provides UI behaviors built on the XAML behaviors SDK. It is a part of the Windows Community Toolkit. This library provides UI behaviors built on the XAML behaviors SDK. It is a part of the Windows Community Toolkit.
Behaviors: - Animation: Various helpers for integration with the Toolkit's Animation package.
- BehaviorBase: Helper for building Behaviors
- AutoFocusBehevior: Sets focus to the associated control. - AutoFocusBehevior: Sets focus to the associated control.
- FocusBehavior: Sets focus to a specified control. - AutoSelectBehavior: Selects a TextBox's text automatically.
- ViewportBehavior: Listening for element to enter or exit the ScrollViewer viewport
- FadeHeaderBehavior, QuickReturnHeaderBehavior, StickyHeaderBehavior: Helpers for ListViewBase Header Behavior - 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> </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> </PropertyGroup>
<ItemGroup> <ItemGroup>

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

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

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

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

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

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

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

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

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

@ -12,6 +12,7 @@
Controls: Controls:
- AdaptiveGridView: Presents items in an evenly-spaced set of columns to fill the total available space. - 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. - 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. - 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. - 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> <PackageTags>
Controls;XAML;UI; Controls;XAML;UI;
Adaptive;Grid;View;AdaptiveGridView;GridView ;AdaptiveGrid ; Adaptive;Grid;View;AdaptiveGridView;GridView ;AdaptiveGrid ;
Constrained;Box;ConstrainedBox;AspectRatio;Aspect;Scale;Multiple;
Dock;Panel ;DockPanel ; Dock;Panel ;DockPanel ;
Staggered;Layout ;StaggeredLayout ; Staggered;Layout ;StaggeredLayout ;
Staggered;Panel ;StaggeredPanel ; Staggered;Panel ;StaggeredPanel ;

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

@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System.Globalization;
namespace CommunityToolkit.WinUI.UI.Controls namespace CommunityToolkit.WinUI.UI.Controls
{ {
@ -75,11 +75,14 @@ namespace CommunityToolkit.WinUI.UI.Controls
if (ratio.Length == 2) 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) 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); return new AspectRatio(1);

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

@ -2,14 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // 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;
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation;
namespace CommunityToolkit.WinUI.UI.Controls namespace CommunityToolkit.WinUI.UI.Controls
{ {

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

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

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

@ -7,7 +7,26 @@
<PropertyGroup> <PropertyGroup>
<Title>Windows Community Toolkit - UI Media</Title> <Title>Windows Community Toolkit - UI Media</Title>
<Description> <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: Media:
- AcrylicBrush: A custom Brush that that implements an acrylic effect with full control over all parameters. - 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. - 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. - TilesBrush: A Brush that displays a tiled image, wrapping at the edges and endlessly repeating.
Effects: PipelineBuilder: A class that allows to build custom effects pipelines and create CompositionBrush instances from them.
- 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.
</Description> </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> </PropertyGroup>
<ItemGroup> <ItemGroup>

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

@ -9,7 +9,7 @@
<PropertyGroup> <PropertyGroup>
<Title>Windows Community Toolkit - UI</Title> <Title>Windows Community Toolkit - UI</Title>
<Description> <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. 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: Extensions:
- ApplicationViewExtensions: Provides attached properties for interacting with the ApplicationView on a window (app view). - 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. - FrameworkElementExtensions: Provides attached dependency properties for the FrameworkElement.
- ListViewExtensions: Provides attached dependency properties for the ListViewBase - ListViewExtensions: Provides attached dependency properties for the ListViewBase
- LogicalTree: Defines a collection of extensions methods for UI. - 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. - BindableValueHolder: Holds the value. Can be used to change several objects' properties at a time.
- DependencyPropertyWatcher: Used to Track Changes of a Dependency Property - 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. - 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> </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> </PropertyGroup>
<ItemGroup> <ItemGroup>

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

@ -6,8 +6,8 @@
<PropertyGroup> <PropertyGroup>
<Title>Windows Community Toolkit - Common (UWP)</Title> <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> <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</PackageTags> <PackageTags>Storage;File;Folder;Color;Conversion;Stream;Helpers;Extensions;System;Information</PackageTags>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

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

@ -111,7 +111,7 @@
<!-- Only the Layout package have a dependency on WinUI --> <!-- Only the Layout package have a dependency on WinUI -->
<ItemGroup Condition="$(CurrentProject) == 'UWPBaselineWinUI' or $(CurrentProject) == 'CommunityToolkit.WinUI.UI.Controls.Layout'"> <ItemGroup Condition="$(CurrentProject) == 'UWPBaselineWinUI' or $(CurrentProject) == 'CommunityToolkit.WinUI.UI.Controls.Layout'">
<PackageReference Include="Microsoft.UI.Xaml"> <PackageReference Include="Microsoft.UI.Xaml">
<Version>2.6.2</Version> <Version>2.7.0</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(CurrentProject)' != '' and '$(CurrentProject)' != 'UWPBaseline' and '$(CurrentProject)' != 'UWPBaselineWinUI' and '$(NuGetPackageVersion)' != 'To Fill In With Local Version Number'"> <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.Linq;
using System.Net.Http; using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core; using Grpc.Core;
using Grpc.Net.Client; using Grpc.Net.Client;

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

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

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

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

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

@ -7,10 +7,13 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection; using System.Reflection;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
#pragma warning disable SA1124
#nullable enable #nullable enable
namespace UnitTests.Mvvm namespace UnitTests.Mvvm
@ -58,6 +61,86 @@ namespace UnitTests.Mvvm
Assert.AreEqual(changed.Item2, 42); 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")] [TestCategory("Mvvm")]
[TestMethod] [TestMethod]
public void Test_AlsoNotifyChangeForAttribute_Events() public void Test_AlsoNotifyChangeForAttribute_Events()
@ -155,6 +238,36 @@ namespace UnitTests.Mvvm
CollectionAssert.AreEqual(new[] { nameof(model.Value) }, propertyNames); 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 public partial class SampleModel : ObservableObject
{ {
/// <summary> /// <summary>
@ -162,6 +275,16 @@ namespace UnitTests.Mvvm
/// </summary> /// </summary>
[ObservableProperty] [ObservableProperty]
private int data; private int data;
#region More properties
[ObservableProperty]
private int counter;
#endregion
[ObservableProperty]
private string? name;
} }
[INotifyPropertyChanged] [INotifyPropertyChanged]
@ -238,7 +361,7 @@ namespace UnitTests.Mvvm
public partial class ModelWithValueProperty : ObservableObject public partial class ModelWithValueProperty : ObservableObject
{ {
[ObservableProperty] [ObservableProperty]
private string value; private string? value;
} }
public partial class ModelWithValuePropertyWithValidation : ObservableValidator public partial class ModelWithValuePropertyWithValidation : ObservableValidator
@ -246,7 +369,26 @@ namespace UnitTests.Mvvm
[ObservableProperty] [ObservableProperty]
[Required] [Required]
[MinLength(5)] [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> /// </summary>
public sealed partial class App : Application public sealed partial class App : Application
{ {
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// </summary>
public App() public App()
{ {
InitializeComponent(); 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 dotnet_diagnostic.SA1601.severity = none
# The Parameter has no matching param tag in the XML comment.
dotnet_diagnostic.CS1573.severity = none dotnet_diagnostic.CS1573.severity = none
# Missing XML comment for publicly visible type or member.
dotnet_diagnostic.CS1591.severity = none 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. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp; using Microsoft.Toolkit.Uwp;
using Microsoft.Toolkit.Uwp.UI; using Microsoft.Toolkit.Uwp.UI;
using Microsoft.Toolkit.Uwp.UI.Controls; using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup; using Windows.UI.Xaml.Markup;

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

@ -2,14 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Linq; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp; using Microsoft.Toolkit.Uwp;
using Microsoft.Toolkit.Uwp.UI; using Microsoft.Toolkit.Uwp.UI;
using Microsoft.Toolkit.Uwp.UI.Controls; using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup; 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"); 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> <Version>6.2.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.UI.Xaml"> <PackageReference Include="Microsoft.UI.Xaml">
<Version>2.6.2</Version> <Version>2.7.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="MSTest.TestAdapter"> <PackageReference Include="MSTest.TestAdapter">
<Version>2.2.5</Version> <Version>2.2.5</Version>
@ -138,6 +138,7 @@
<Compile Include="UI\Controls\Test_ConstrainedBox.Multiple.cs" /> <Compile Include="UI\Controls\Test_ConstrainedBox.Multiple.cs" />
<Compile Include="UI\Controls\Test_ConstrainedBox.Combined.cs" /> <Compile Include="UI\Controls\Test_ConstrainedBox.Combined.cs" />
<Compile Include="UI\Controls\Test_ImageEx.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_RadialGauge.cs" />
<Compile Include="UI\Controls\Test_RichSuggestBox.cs" /> <Compile Include="UI\Controls\Test_RichSuggestBox.cs" />
<Compile Include="UI\Controls\Test_TextToolbar_Localization.cs" /> <Compile Include="UI\Controls\Test_TextToolbar_Localization.cs" />

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

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

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

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