diff --git a/src/.vsconfig_buildtools b/src/.vsconfig_buildtools index da5ccf978f..1b09e7cd2e 100644 --- a/src/.vsconfig_buildtools +++ b/src/.vsconfig_buildtools @@ -25,6 +25,7 @@ "Microsoft.VisualStudio.ComponentGroup.UWP.VC.BuildTools", "Microsoft.VisualStudio.Workload.MSBuildTools", "Microsoft.VisualStudio.Workload.ManagedDesktopBuildTools", + "Microsoft.VisualStudio.Workload.Universal", "Microsoft.VisualStudio.Workload.UniversalBuildTools", "Microsoft.VisualStudio.Workload.VCTools", "Microsoft.VisualStudio.Component.VC.Runtimes.ARM64EC.Spectre", diff --git a/src/Packages.props b/src/Packages.props index 62ca7e87a1..657871cf52 100644 --- a/src/Packages.props +++ b/src/Packages.props @@ -37,5 +37,7 @@ + + diff --git a/src/UpdateMockWinAppSDKPackage.csproj b/src/UpdateMockWinAppSDKPackage.csproj index b4cfb638fc..57766e5b74 100644 --- a/src/UpdateMockWinAppSDKPackage.csproj +++ b/src/UpdateMockWinAppSDKPackage.csproj @@ -34,6 +34,7 @@ + diff --git a/src/controls/CleanupMSBuildProcesses.csproj b/src/controls/CleanupMSBuildProcesses.csproj index 54855f930b..87f8f5a332 100644 --- a/src/controls/CleanupMSBuildProcesses.csproj +++ b/src/controls/CleanupMSBuildProcesses.csproj @@ -32,7 +32,7 @@ - + diff --git a/src/controls/HybridCRT.props b/src/controls/HybridCRT.props index f2d81da329..02ec1a275c 100644 --- a/src/controls/HybridCRT.props +++ b/src/controls/HybridCRT.props @@ -6,21 +6,7 @@ false - - - - MultiThreadedDebug - - - - %(IgnoreSpecificDefaultLibraries);libucrtd.lib - %(AdditionalOptions) /defaultlib:ucrtd.lib - - - + MultiThreaded diff --git a/src/controls/MUXControls.sln b/src/controls/MUXControls.sln index 0c08a0cfc8..9586c2fe12 100644 --- a/src/controls/MUXControls.sln +++ b/src/controls/MUXControls.sln @@ -653,6 +653,7 @@ EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "MapControl_TestUI", "dev\MapControl\TestUI\MapControl_TestUI.shproj", "{8C2F2FA6-5639-4C01-84D0-06E037824689}" EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "MapControl_InteractionTests", "dev\MapControl\InteractionTests\MapControl_InteractionTests.shproj", "{189F0B87-4CA1-4F77-8195-FC6DC714157A}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DesktopAcrylicBackdrop", "DesktopAcrylicBackdrop", "{0BEED10A-70BC-4103-8BC8-84D83A14EF75}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MicaBackdrop", "MicaBackdrop", "{AAEE68EF-8CB5-40D2-8BC8-9A00FB0A1B6A}" @@ -693,737 +694,465 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SelectorBar_TestUI", "dev\S EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SelectorBar_APITests", "dev\SelectorBar\APITests\SelectorBar_APITests.shproj", "{F778ACAE-150F-4D7D-83C1-5BF2E1ACB399}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TabViewTearOutApp", "test\TabViewTearOutApp\TabViewTearOutApp.vcxproj", "{86317243-45A8-4770-A4B2-768F721E5F9B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug_test|Any CPU = Debug_test|Any CPU Debug_test|ARM64 = Debug_test|ARM64 - Debug_test|Win32 = Debug_test|Win32 Debug_test|x64 = Debug_test|x64 Debug_test|x86 = Debug_test|x86 - Debug|Any CPU = Debug|Any CPU Debug|ARM64 = Debug|ARM64 - Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU Release|ARM64 = Release|ARM64 - Release|Win32 = Release|Win32 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|Any CPU.Build.0 = Debug|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|Win32.Build.0 = Debug|Win32 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|x64.ActiveCfg = Debug|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|x64.Build.0 = Debug|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|x86.ActiveCfg = Debug|Win32 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug_test|x86.Build.0 = Debug|Win32 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|Any CPU.ActiveCfg = Debug|x64 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|Any CPU.Build.0 = Debug|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|ARM64.Build.0 = Debug|ARM64 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|Win32.ActiveCfg = Debug|Win32 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|Win32.Build.0 = Debug|Win32 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|x64.ActiveCfg = Debug|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|x64.Build.0 = Debug|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|x86.ActiveCfg = Debug|Win32 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Debug|x86.Build.0 = Debug|Win32 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|Any CPU.ActiveCfg = Release|x64 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|Any CPU.Build.0 = Release|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|ARM64.ActiveCfg = Release|ARM64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|ARM64.Build.0 = Release|ARM64 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|Win32.ActiveCfg = Release|Win32 - {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|Win32.Build.0 = Release|Win32 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|x64.ActiveCfg = Release|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|x64.Build.0 = Release|x64 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|x86.ActiveCfg = Release|Win32 {AD0C90B0-4845-4D4B-88F1-86F653F8171B}.Release|x86.Build.0 = Release|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|Any CPU.Build.0 = Debug|x64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|Any CPU.Deploy.0 = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|ARM64.Build.0 = Debug|ARM64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|ARM64.Deploy.0 = Debug|ARM64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|Win32.Build.0 = Debug|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|Win32.Deploy.0 = Debug|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|x64.ActiveCfg = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|x64.Build.0 = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|x64.Deploy.0 = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|x86.ActiveCfg = Debug|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|x86.Build.0 = Debug|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug_test|x86.Deploy.0 = Debug|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|Any CPU.ActiveCfg = Debug|x64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|Any CPU.Build.0 = Debug|x64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|Any CPU.Deploy.0 = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|ARM64.ActiveCfg = Debug|ARM64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|ARM64.Build.0 = Debug|ARM64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|ARM64.Deploy.0 = Debug|ARM64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|Win32.ActiveCfg = Debug|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|Win32.Build.0 = Debug|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|Win32.Deploy.0 = Debug|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|x64.ActiveCfg = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|x64.Build.0 = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|x64.Deploy.0 = Debug|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|x86.ActiveCfg = Debug|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|x86.Build.0 = Debug|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Debug|x86.Deploy.0 = Debug|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|Any CPU.ActiveCfg = Release|x64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|Any CPU.Build.0 = Release|x64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|Any CPU.Deploy.0 = Release|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|ARM64.ActiveCfg = Release|ARM64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|ARM64.Build.0 = Release|ARM64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|ARM64.Deploy.0 = Release|ARM64 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|Win32.ActiveCfg = Release|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|Win32.Build.0 = Release|Win32 - {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|Win32.Deploy.0 = Release|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|x64.ActiveCfg = Release|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|x64.Build.0 = Release|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|x64.Deploy.0 = Release|x64 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|x86.ActiveCfg = Release|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|x86.Build.0 = Release|Win32 {92081F61-98BB-4105-A90F-B6D524B4F5C9}.Release|x86.Deploy.0 = Release|Win32 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|Any CPU.ActiveCfg = Debug_test|Any CPU - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|Any CPU.Build.0 = Debug_test|Any CPU {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|ARM64.ActiveCfg = Debug_test|ARM64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|ARM64.Build.0 = Debug_test|ARM64 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|Win32.ActiveCfg = Debug_test|Win32 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|Win32.Build.0 = Debug_test|Win32 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|x64.ActiveCfg = Debug_test|x64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|x64.Build.0 = Debug_test|x64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|x86.ActiveCfg = Debug_test|Win32 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug_test|x86.Build.0 = Debug_test|Win32 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|Any CPU.Build.0 = Debug|Any CPU {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|ARM64.ActiveCfg = Debug|ARM64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|ARM64.Build.0 = Debug|ARM64 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|Win32.ActiveCfg = Debug|Win32 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|Win32.Build.0 = Debug|Win32 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|x64.ActiveCfg = Debug|x64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|x64.Build.0 = Debug|x64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|x86.ActiveCfg = Debug|Win32 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Debug|x86.Build.0 = Debug|Win32 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|Any CPU.Build.0 = Release|Any CPU {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|ARM64.ActiveCfg = Release|ARM64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|ARM64.Build.0 = Release|ARM64 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|Win32.ActiveCfg = Release|Win32 - {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|Win32.Build.0 = Release|Win32 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|x64.ActiveCfg = Release|x64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|x64.Build.0 = Release|x64 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|x86.ActiveCfg = Release|Win32 {9638BF0D-2AA8-4642-A9F1-790BF7FBECF2}.Release|x86.Build.0 = Release|Win32 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|Any CPU.Build.0 = Debug|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|Win32.Build.0 = Debug|Win32 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|x64.ActiveCfg = Debug|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|x64.Build.0 = Debug|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|x86.ActiveCfg = Debug|Win32 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug_test|x86.Build.0 = Debug|Win32 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|Any CPU.ActiveCfg = Debug|x64 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|Any CPU.Build.0 = Debug|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|ARM64.ActiveCfg = Debug|ARM64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|ARM64.Build.0 = Debug|ARM64 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|Win32.ActiveCfg = Debug|Win32 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|Win32.Build.0 = Debug|Win32 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|x64.ActiveCfg = Debug|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|x64.Build.0 = Debug|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|x86.ActiveCfg = Debug|Win32 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Debug|x86.Build.0 = Debug|Win32 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|Any CPU.ActiveCfg = Release|x64 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|Any CPU.Build.0 = Release|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|ARM64.ActiveCfg = Release|ARM64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|ARM64.Build.0 = Release|ARM64 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|Win32.ActiveCfg = Release|Win32 - {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|Win32.Build.0 = Release|Win32 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|x64.ActiveCfg = Release|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|x64.Build.0 = Release|x64 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|x86.ActiveCfg = Release|Win32 {DE10DFE2-5EA3-452A-B055-FC60E330AFBB}.Release|x86.Build.0 = Release|Win32 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|Any CPU.Build.0 = Debug|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|Win32.Build.0 = Debug|Win32 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|x64.ActiveCfg = Debug|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|x64.Build.0 = Debug|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|x86.ActiveCfg = Debug|Win32 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug_test|x86.Build.0 = Debug|Win32 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|Any CPU.ActiveCfg = Debug|x64 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|Any CPU.Build.0 = Debug|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|ARM64.Build.0 = Debug|ARM64 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|Win32.ActiveCfg = Debug|Win32 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|Win32.Build.0 = Debug|Win32 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|x64.ActiveCfg = Debug|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|x64.Build.0 = Debug|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|x86.ActiveCfg = Debug|Win32 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Debug|x86.Build.0 = Debug|Win32 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|Any CPU.ActiveCfg = Release|x64 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|Any CPU.Build.0 = Release|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|ARM64.ActiveCfg = Release|ARM64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|ARM64.Build.0 = Release|ARM64 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|Win32.ActiveCfg = Release|Win32 - {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|Win32.Build.0 = Release|Win32 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|x64.ActiveCfg = Release|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|x64.Build.0 = Release|x64 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|x86.ActiveCfg = Release|Win32 {A1EB01C3-AC8B-45A8-97C8-C459B77ED690}.Release|x86.Build.0 = Release|Win32 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|Any CPU.Build.0 = Debug|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|Win32.Build.0 = Debug|Win32 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|x64.ActiveCfg = Debug|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|x64.Build.0 = Debug|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|x86.ActiveCfg = Debug|Win32 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug_test|x86.Build.0 = Debug|Win32 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|Any CPU.ActiveCfg = Debug|x64 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|Any CPU.Build.0 = Debug|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|ARM64.Build.0 = Debug|ARM64 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|Win32.ActiveCfg = Debug|Win32 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|Win32.Build.0 = Debug|Win32 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|x64.ActiveCfg = Debug|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|x64.Build.0 = Debug|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|x86.ActiveCfg = Debug|Win32 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Debug|x86.Build.0 = Debug|Win32 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|Any CPU.ActiveCfg = Release|x64 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|Any CPU.Build.0 = Release|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|ARM64.ActiveCfg = Release|ARM64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|ARM64.Build.0 = Release|ARM64 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|Win32.ActiveCfg = Release|Win32 - {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|Win32.Build.0 = Release|Win32 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|x64.ActiveCfg = Release|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|x64.Build.0 = Release|x64 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|x86.ActiveCfg = Release|Win32 {F24B3ECB-BD87-4626-B17C-D8CC3E253F32}.Release|x86.Build.0 = Release|Win32 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|Any CPU.Build.0 = Debug|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|Win32.Build.0 = Debug|Win32 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|x64.ActiveCfg = Debug|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|x64.Build.0 = Debug|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|x86.ActiveCfg = Debug|Win32 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug_test|x86.Build.0 = Debug|Win32 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|Any CPU.ActiveCfg = Debug|x64 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|Any CPU.Build.0 = Debug|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|ARM64.Build.0 = Debug|ARM64 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|Win32.ActiveCfg = Debug|Win32 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|Win32.Build.0 = Debug|Win32 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|x64.ActiveCfg = Debug|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|x64.Build.0 = Debug|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|x86.ActiveCfg = Debug|Win32 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Debug|x86.Build.0 = Debug|Win32 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|Any CPU.ActiveCfg = Release|x64 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|Any CPU.Build.0 = Release|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|ARM64.ActiveCfg = Release|ARM64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|ARM64.Build.0 = Release|ARM64 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|Win32.ActiveCfg = Release|Win32 - {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|Win32.Build.0 = Release|Win32 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|x64.ActiveCfg = Release|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|x64.Build.0 = Release|x64 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|x86.ActiveCfg = Release|Win32 {F021A52A-6162-4E8D-B109-847EE5362DF9}.Release|x86.Build.0 = Release|Win32 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|Any CPU.Build.0 = Debug|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|Win32.Build.0 = Debug|Win32 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|x64.ActiveCfg = Debug|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|x64.Build.0 = Debug|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|x86.ActiveCfg = Debug|Win32 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug_test|x86.Build.0 = Debug|Win32 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|Any CPU.ActiveCfg = Debug|x64 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|Any CPU.Build.0 = Debug|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|ARM64.ActiveCfg = Debug|ARM64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|ARM64.Build.0 = Debug|ARM64 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|Win32.ActiveCfg = Debug|Win32 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|Win32.Build.0 = Debug|Win32 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|x64.ActiveCfg = Debug|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|x64.Build.0 = Debug|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|x86.ActiveCfg = Debug|Win32 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Debug|x86.Build.0 = Debug|Win32 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|Any CPU.ActiveCfg = Release|x64 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|Any CPU.Build.0 = Release|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|ARM64.ActiveCfg = Release|ARM64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|ARM64.Build.0 = Release|ARM64 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|Win32.ActiveCfg = Release|Win32 - {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|Win32.Build.0 = Release|Win32 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|x64.ActiveCfg = Release|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|x64.Build.0 = Release|x64 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|x86.ActiveCfg = Release|Win32 {5876E568-B204-4219-8C08-9E8124EDAB9C}.Release|x86.Build.0 = Release|Win32 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|Any CPU.Build.0 = Debug|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|Win32.Build.0 = Debug|Win32 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|x64.ActiveCfg = Debug|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|x64.Build.0 = Debug|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|x86.ActiveCfg = Debug|Win32 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug_test|x86.Build.0 = Debug|Win32 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|Any CPU.ActiveCfg = Debug|x64 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|Any CPU.Build.0 = Debug|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|ARM64.ActiveCfg = Debug|ARM64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|ARM64.Build.0 = Debug|ARM64 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|Win32.ActiveCfg = Debug|Win32 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|Win32.Build.0 = Debug|Win32 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|x64.ActiveCfg = Debug|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|x64.Build.0 = Debug|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|x86.ActiveCfg = Debug|Win32 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Debug|x86.Build.0 = Debug|Win32 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|Any CPU.ActiveCfg = Release|x64 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|Any CPU.Build.0 = Release|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|ARM64.ActiveCfg = Release|ARM64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|ARM64.Build.0 = Release|ARM64 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|Win32.ActiveCfg = Release|Win32 - {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|Win32.Build.0 = Release|Win32 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|x64.ActiveCfg = Release|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|x64.Build.0 = Release|x64 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|x86.ActiveCfg = Release|Win32 {84D22D7D-5FD0-4CCF-B8D2-C34506C6BA66}.Release|x86.Build.0 = Release|Win32 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|Any CPU.Build.0 = Debug|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|Win32.Build.0 = Debug|Win32 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|x64.ActiveCfg = Debug|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|x64.Build.0 = Debug|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|x86.ActiveCfg = Debug|Win32 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug_test|x86.Build.0 = Debug|Win32 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|Any CPU.ActiveCfg = Debug|x64 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|Any CPU.Build.0 = Debug|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|ARM64.ActiveCfg = Debug|ARM64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|ARM64.Build.0 = Debug|ARM64 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|Win32.ActiveCfg = Debug|Win32 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|Win32.Build.0 = Debug|Win32 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|x64.ActiveCfg = Debug|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|x64.Build.0 = Debug|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|x86.ActiveCfg = Debug|Win32 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Debug|x86.Build.0 = Debug|Win32 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|Any CPU.ActiveCfg = Release|x64 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|Any CPU.Build.0 = Release|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|ARM64.ActiveCfg = Release|ARM64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|ARM64.Build.0 = Release|ARM64 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|Win32.ActiveCfg = Release|Win32 - {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|Win32.Build.0 = Release|Win32 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|x64.ActiveCfg = Release|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|x64.Build.0 = Release|x64 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|x86.ActiveCfg = Release|Win32 {52B2ED64-1CFC-401B-8C5B-6D1E1DEADF98}.Release|x86.Build.0 = Release|Win32 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|Any CPU.Build.0 = Debug|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|Win32.Build.0 = Debug|Win32 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|x64.ActiveCfg = Debug|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|x64.Build.0 = Debug|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|x86.ActiveCfg = Debug|Win32 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug_test|x86.Build.0 = Debug|Win32 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|Any CPU.ActiveCfg = Debug|x64 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|Any CPU.Build.0 = Debug|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|ARM64.ActiveCfg = Debug|ARM64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|ARM64.Build.0 = Debug|ARM64 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|Win32.ActiveCfg = Debug|Win32 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|Win32.Build.0 = Debug|Win32 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|x64.ActiveCfg = Debug|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|x64.Build.0 = Debug|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|x86.ActiveCfg = Debug|Win32 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Debug|x86.Build.0 = Debug|Win32 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|Any CPU.ActiveCfg = Release|x64 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|Any CPU.Build.0 = Release|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|ARM64.ActiveCfg = Release|ARM64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|ARM64.Build.0 = Release|ARM64 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|Win32.ActiveCfg = Release|Win32 - {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|Win32.Build.0 = Release|Win32 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|x64.ActiveCfg = Release|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|x64.Build.0 = Release|x64 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|x86.ActiveCfg = Release|Win32 {D638A8EF-3A48-45F2-913C-88B29FED03CB}.Release|x86.Build.0 = Release|Win32 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|Any CPU.ActiveCfg = Debug_test|Any CPU - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|Any CPU.Build.0 = Debug_test|Any CPU {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|ARM64.ActiveCfg = Debug_test|ARM64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|ARM64.Build.0 = Debug_test|ARM64 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|Win32.ActiveCfg = Debug_test|Win32 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|Win32.Build.0 = Debug_test|Win32 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|x64.ActiveCfg = Debug_test|x64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|x64.Build.0 = Debug_test|x64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|x86.ActiveCfg = Debug_test|x86 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug_test|x86.Build.0 = Debug_test|x86 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|ARM64.ActiveCfg = Debug|ARM64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|ARM64.Build.0 = Debug|ARM64 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|Win32.ActiveCfg = Debug|Win32 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|Win32.Build.0 = Debug|Win32 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|x64.ActiveCfg = Debug|x64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|x64.Build.0 = Debug|x64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|x86.ActiveCfg = Debug|x86 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Debug|x86.Build.0 = Debug|x86 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|Any CPU.Build.0 = Release|Any CPU {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|ARM64.ActiveCfg = Release|ARM64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|ARM64.Build.0 = Release|ARM64 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|Win32.ActiveCfg = Release|Win32 - {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|Win32.Build.0 = Release|Win32 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|x64.ActiveCfg = Release|x64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|x64.Build.0 = Release|x64 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|x86.ActiveCfg = Release|x86 {1CEEC8E3-419A-4304-841C-08A334B9E4FF}.Release|x86.Build.0 = Release|x86 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|Any CPU.Build.0 = Debug|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|Win32.Build.0 = Debug|Win32 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|x64.ActiveCfg = Debug|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|x64.Build.0 = Debug|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|x86.ActiveCfg = Debug|Win32 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug_test|x86.Build.0 = Debug|Win32 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|Any CPU.ActiveCfg = Debug|x64 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|Any CPU.Build.0 = Debug|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|ARM64.ActiveCfg = Debug|ARM64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|ARM64.Build.0 = Debug|ARM64 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|Win32.ActiveCfg = Debug|Win32 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|Win32.Build.0 = Debug|Win32 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|x64.ActiveCfg = Debug|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|x64.Build.0 = Debug|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|x86.ActiveCfg = Debug|Win32 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Debug|x86.Build.0 = Debug|Win32 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|Any CPU.ActiveCfg = Release|x64 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|Any CPU.Build.0 = Release|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|ARM64.ActiveCfg = Release|ARM64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|ARM64.Build.0 = Release|ARM64 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|Win32.ActiveCfg = Release|Win32 - {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|Win32.Build.0 = Release|Win32 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|x64.ActiveCfg = Release|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|x64.Build.0 = Release|x64 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|x86.ActiveCfg = Release|Win32 {4A1CB0BC-5A0F-488D-AD8F-FA3642D18DB8}.Release|x86.Build.0 = Release|Win32 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|Any CPU.Build.0 = Debug|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|Win32.Build.0 = Debug|Win32 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|x64.ActiveCfg = Debug|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|x64.Build.0 = Debug|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|x86.ActiveCfg = Debug|Win32 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug_test|x86.Build.0 = Debug|Win32 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|Any CPU.ActiveCfg = Debug|x64 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|Any CPU.Build.0 = Debug|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|ARM64.ActiveCfg = Debug|ARM64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|ARM64.Build.0 = Debug|ARM64 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|Win32.ActiveCfg = Debug|Win32 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|Win32.Build.0 = Debug|Win32 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|x64.ActiveCfg = Debug|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|x64.Build.0 = Debug|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|x86.ActiveCfg = Debug|Win32 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Debug|x86.Build.0 = Debug|Win32 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|Any CPU.ActiveCfg = Release|x64 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|Any CPU.Build.0 = Release|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|ARM64.ActiveCfg = Release|ARM64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|ARM64.Build.0 = Release|ARM64 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|Win32.ActiveCfg = Release|Win32 - {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|Win32.Build.0 = Release|Win32 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|x64.ActiveCfg = Release|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|x64.Build.0 = Release|x64 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|x86.ActiveCfg = Release|Win32 {25CF9F3C-2B8C-438B-92AD-0FE7CC47C30E}.Release|x86.Build.0 = Release|Win32 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|Any CPU.Build.0 = Debug|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|Win32.ActiveCfg = Debug|x86 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|Win32.Build.0 = Debug|x86 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|x64.ActiveCfg = Debug|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|x64.Build.0 = Debug|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|x86.ActiveCfg = Debug|x86 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug_test|x86.Build.0 = Debug|x86 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|Any CPU.ActiveCfg = Debug|x64 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|Any CPU.Build.0 = Debug|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|ARM64.Build.0 = Debug|ARM64 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|Win32.ActiveCfg = Debug|x86 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|Win32.Build.0 = Debug|x86 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|x64.ActiveCfg = Debug|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|x64.Build.0 = Debug|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|x86.ActiveCfg = Debug|x86 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Debug|x86.Build.0 = Debug|x86 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|Any CPU.ActiveCfg = Release|x64 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|Any CPU.Build.0 = Release|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|ARM64.ActiveCfg = Release|ARM64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|ARM64.Build.0 = Release|ARM64 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|Win32.ActiveCfg = Release|x86 - {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|Win32.Build.0 = Release|x86 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|x64.ActiveCfg = Release|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|x64.Build.0 = Release|x64 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|x86.ActiveCfg = Release|x86 {1D6EDD7D-D380-444D-B233-3C718ABB382D}.Release|x86.Build.0 = Release|x86 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|Any CPU.Build.0 = Debug|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|Win32.ActiveCfg = Debug|x86 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|Win32.Build.0 = Debug|x86 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|x64.ActiveCfg = Debug|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|x64.Build.0 = Debug|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|x86.ActiveCfg = Debug|x86 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug_test|x86.Build.0 = Debug|x86 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|Any CPU.ActiveCfg = Debug|x64 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|Any CPU.Build.0 = Debug|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|ARM64.ActiveCfg = Debug|ARM64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|ARM64.Build.0 = Debug|ARM64 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|Win32.ActiveCfg = Debug|x86 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|Win32.Build.0 = Debug|x86 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|x64.ActiveCfg = Debug|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|x64.Build.0 = Debug|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|x86.ActiveCfg = Debug|x86 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Debug|x86.Build.0 = Debug|x86 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|Any CPU.ActiveCfg = Release|x64 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|Any CPU.Build.0 = Release|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|ARM64.ActiveCfg = Release|ARM64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|ARM64.Build.0 = Release|ARM64 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|Win32.ActiveCfg = Release|x86 - {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|Win32.Build.0 = Release|x86 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|x64.ActiveCfg = Release|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|x64.Build.0 = Release|x64 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|x86.ActiveCfg = Release|x86 {4D8C5D1B-F982-44A1-B744-DD0E51651BF2}.Release|x86.Build.0 = Release|x86 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|Any CPU.Build.0 = Debug|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|Win32.ActiveCfg = Debug|x86 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|Win32.Build.0 = Debug|x86 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|x64.ActiveCfg = Debug|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|x64.Build.0 = Debug|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|x86.ActiveCfg = Debug|x86 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug_test|x86.Build.0 = Debug|x86 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|Any CPU.ActiveCfg = Debug|x64 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|Any CPU.Build.0 = Debug|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|ARM64.ActiveCfg = Debug|ARM64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|ARM64.Build.0 = Debug|ARM64 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|Win32.ActiveCfg = Debug|x86 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|Win32.Build.0 = Debug|x86 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|x64.ActiveCfg = Debug|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|x64.Build.0 = Debug|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|x86.ActiveCfg = Debug|x86 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Debug|x86.Build.0 = Debug|x86 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|Any CPU.ActiveCfg = Release|x64 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|Any CPU.Build.0 = Release|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|ARM64.ActiveCfg = Release|ARM64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|ARM64.Build.0 = Release|ARM64 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|Win32.ActiveCfg = Release|x86 - {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|Win32.Build.0 = Release|x86 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|x64.ActiveCfg = Release|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|x64.Build.0 = Release|x64 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|x86.ActiveCfg = Release|x86 {4E6F8103-9E20-40DD-8FE0-1E73964BB800}.Release|x86.Build.0 = Release|x86 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|Any CPU.ActiveCfg = Debug|x64 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|Any CPU.Build.0 = Debug|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|Win32.ActiveCfg = Debug|x86 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|Win32.Build.0 = Debug|x86 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|x64.ActiveCfg = Debug|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|x64.Build.0 = Debug|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|x86.ActiveCfg = Debug|x86 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug_test|x86.Build.0 = Debug|x86 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|Any CPU.ActiveCfg = Debug|x64 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|Any CPU.Build.0 = Debug|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|ARM64.ActiveCfg = Debug|ARM64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|ARM64.Build.0 = Debug|ARM64 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|Win32.ActiveCfg = Debug|x86 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|Win32.Build.0 = Debug|x86 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|x64.ActiveCfg = Debug|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|x64.Build.0 = Debug|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|x86.ActiveCfg = Debug|x86 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Debug|x86.Build.0 = Debug|x86 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|Any CPU.ActiveCfg = Release|x64 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|Any CPU.Build.0 = Release|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|ARM64.ActiveCfg = Release|ARM64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|ARM64.Build.0 = Release|ARM64 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|Win32.ActiveCfg = Release|x86 - {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|Win32.Build.0 = Release|x86 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|x64.ActiveCfg = Release|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|x64.Build.0 = Release|x64 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|x86.ActiveCfg = Release|x86 {52DDC946-7073-4130-8454-80E84AD3CF5A}.Release|x86.Build.0 = Release|x86 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|Any CPU.ActiveCfg = Debug_test|Any CPU - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|Any CPU.Build.0 = Debug_test|Any CPU {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|ARM64.ActiveCfg = Debug_test|ARM64 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|Win32.ActiveCfg = Debug_test|Win32 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|Win32.Build.0 = Debug_test|Win32 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|Win32.Deploy.0 = Debug_test|Win32 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|x64.ActiveCfg = Debug_test|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|x64.Build.0 = Debug_test|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|x64.Deploy.0 = Debug_test|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|x86.ActiveCfg = Debug_test|x86 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|x86.Build.0 = Debug_test|x86 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug_test|x86.Deploy.0 = Debug_test|x86 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|Any CPU.Deploy.0 = Debug|Any CPU {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|Win32.ActiveCfg = Debug|Win32 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|Win32.Build.0 = Debug|Win32 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|Win32.Deploy.0 = Debug|Win32 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|x64.ActiveCfg = Debug|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|x64.Build.0 = Debug|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|x64.Deploy.0 = Debug|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|x86.ActiveCfg = Debug|x86 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|x86.Build.0 = Debug|x86 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Debug|x86.Deploy.0 = Debug|x86 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|Any CPU.Build.0 = Release|Any CPU {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|ARM64.ActiveCfg = Release|ARM64 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|Win32.ActiveCfg = Release|Win32 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|Win32.Build.0 = Release|Win32 - {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|Win32.Deploy.0 = Release|Win32 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|x64.ActiveCfg = Release|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|x64.Build.0 = Release|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|x64.Deploy.0 = Release|x64 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|x86.ActiveCfg = Release|x86 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|x86.Build.0 = Release|x86 {FCC396F5-26DD-4CA3-981E-C7BC9FEA4546}.Release|x86.Deploy.0 = Release|x86 - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|Any CPU.ActiveCfg = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|Any CPU.Build.0 = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|ARM64.ActiveCfg = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|ARM64.Build.0 = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|Win32.ActiveCfg = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|Win32.Build.0 = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|x64.ActiveCfg = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|x64.Build.0 = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|x86.ActiveCfg = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug_test|x86.Build.0 = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|Any CPU.Build.0 = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|ARM64.ActiveCfg = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|ARM64.Build.0 = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|Win32.ActiveCfg = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|Win32.Build.0 = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|x64.ActiveCfg = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|x64.Build.0 = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|x86.ActiveCfg = Debug|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Debug|x86.Build.0 = Debug|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|Any CPU.ActiveCfg = Release|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|Any CPU.Build.0 = Release|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|ARM64.ActiveCfg = Release|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|ARM64.Build.0 = Release|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|Win32.ActiveCfg = Release|Any CPU - {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|Win32.Build.0 = Release|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|x64.ActiveCfg = Release|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|x64.Build.0 = Release|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|x86.ActiveCfg = Release|Any CPU {10F93BC6-DE0F-4B8D-A4C0-7A807935FD96}.Release|x86.Build.0 = Release|Any CPU - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|Any CPU.ActiveCfg = Debug|Any CPU - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|Any CPU.Build.0 = Debug|Any CPU {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|Win32.Build.0 = Debug|Win32 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|x64.ActiveCfg = Debug|x64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|x64.Build.0 = Debug|x64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|x86.ActiveCfg = Debug|Win32 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug_test|x86.Build.0 = Debug|Win32 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|Any CPU.Build.0 = Debug|Any CPU {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|ARM64.ActiveCfg = Debug|ARM64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|ARM64.Build.0 = Debug|ARM64 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|Win32.ActiveCfg = Debug|Win32 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|Win32.Build.0 = Debug|Win32 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|x64.ActiveCfg = Debug|x64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|x64.Build.0 = Debug|x64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|x86.ActiveCfg = Debug|Win32 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Debug|x86.Build.0 = Debug|Win32 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|Any CPU.Build.0 = Release|Any CPU {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|ARM64.ActiveCfg = Release|ARM64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|ARM64.Build.0 = Release|ARM64 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|Win32.ActiveCfg = Release|Win32 - {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|Win32.Build.0 = Release|Win32 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|x64.ActiveCfg = Release|x64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|x64.Build.0 = Release|x64 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|x86.ActiveCfg = Release|Win32 {2F1F8DCD-98F2-4C02-97BA-15105E933057}.Release|x86.Build.0 = Release|Win32 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|Any CPU.ActiveCfg = Debug|Any CPU - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|Any CPU.Build.0 = Debug|Any CPU {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|Win32.ActiveCfg = Debug|Win32 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|Win32.Build.0 = Debug|Win32 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|x64.ActiveCfg = Debug|x64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|x64.Build.0 = Debug|x64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|x86.ActiveCfg = Debug|x86 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug_test|x86.Build.0 = Debug|x86 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|Any CPU.Build.0 = Debug|Any CPU {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|ARM64.ActiveCfg = Debug|ARM64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|ARM64.Build.0 = Debug|ARM64 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|Win32.ActiveCfg = Debug|Win32 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|Win32.Build.0 = Debug|Win32 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|x64.ActiveCfg = Debug|x64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|x64.Build.0 = Debug|x64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|x86.ActiveCfg = Debug|x86 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Debug|x86.Build.0 = Debug|x86 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|Any CPU.Build.0 = Release|Any CPU {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|ARM64.ActiveCfg = Release|ARM64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|ARM64.Build.0 = Release|ARM64 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|Win32.ActiveCfg = Release|x86 - {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|Win32.Build.0 = Release|x86 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|x64.ActiveCfg = Release|x64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|x64.Build.0 = Release|x64 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|x86.ActiveCfg = Release|x86 {70429938-E9C3-415D-9CA2-61FB08ED001F}.Release|x86.Build.0 = Release|x86 - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|Any CPU.ActiveCfg = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|Any CPU.Build.0 = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|ARM64.ActiveCfg = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|ARM64.Build.0 = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|Win32.ActiveCfg = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|Win32.Build.0 = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|x64.ActiveCfg = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|x64.Build.0 = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|x86.ActiveCfg = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug_test|x86.Build.0 = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|Any CPU.Build.0 = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|ARM64.ActiveCfg = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|ARM64.Build.0 = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|Win32.ActiveCfg = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|Win32.Build.0 = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|x64.ActiveCfg = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|x64.Build.0 = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|x86.ActiveCfg = Debug|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Debug|x86.Build.0 = Debug|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|Any CPU.Build.0 = Release|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|ARM64.ActiveCfg = Release|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|ARM64.Build.0 = Release|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|Win32.ActiveCfg = Release|Any CPU - {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|Win32.Build.0 = Release|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|x64.ActiveCfg = Release|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|x64.Build.0 = Release|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|x86.ActiveCfg = Release|Any CPU {DCDF77D5-B709-4052-B0D3-DD68BC9D3D5D}.Release|x86.Build.0 = Release|Any CPU + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug_test|ARM64.Build.0 = Debug|ARM64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug_test|x64.ActiveCfg = Debug|x64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug_test|x64.Build.0 = Debug|x64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug_test|x86.ActiveCfg = Debug|Win32 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug_test|x86.Build.0 = Debug|Win32 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug|ARM64.Build.0 = Debug|ARM64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug|x64.ActiveCfg = Debug|x64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug|x64.Build.0 = Debug|x64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug|x86.ActiveCfg = Debug|Win32 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Debug|x86.Build.0 = Debug|Win32 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Release|ARM64.ActiveCfg = Release|ARM64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Release|ARM64.Build.0 = Release|ARM64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Release|x64.ActiveCfg = Release|x64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Release|x64.Build.0 = Release|x64 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Release|x86.ActiveCfg = Release|Win32 + {86317243-45A8-4770-A4B2-768F721E5F9B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1720,6 +1449,7 @@ Global {4BE74739-227A-4367-8DBA-AEC2769562C8} = {BC59C0F9-07AC-44B2-BDF1-6533A1371BB2} {1C950F53-542E-4CC4-9281-D9E36072A743} = {BC59C0F9-07AC-44B2-BDF1-6533A1371BB2} {F778ACAE-150F-4D7D-83C1-5BF2E1ACB399} = {BC59C0F9-07AC-44B2-BDF1-6533A1371BB2} + {86317243-45A8-4770-A4B2-768F721E5F9B} = {D3327F36-E161-4FED-A0F4-56F2B735827E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D93836AB-52D3-4DE2-AE25-23F26F55ECED} @@ -1812,7 +1542,6 @@ Global dev\ItemContainer\InteractionTests\ItemContainer_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\ItemsView\InteractionTests\ItemsView_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\MapControl\InteractionTests\MapControl_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 - dev\SelectorBar\InteractionTests\SelectorBar_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\Materials\Acrylic\InteractionTests\AcrylicBrush_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\Materials\Reveal\InteractionTests\Reveal_InteractionTests\Reveal_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\MenuBar\MenuBar_InteractionTests\MenuBar_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 @@ -1833,10 +1562,12 @@ Global dev\Repeater\InteractionTests\Repeater_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\ScrollPresenter\InteractionTests\ScrollPresenter_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\ScrollView\InteractionTests\ScrollView_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 + dev\SelectorBar\InteractionTests\SelectorBar_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\SplitButton\InteractionTests\SplitButton_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\SwipeControl\SwipeControl_InteractionTests\SwipeControl_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\TabView\InteractionTests\TabView_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\TeachingTip\InteractionTests\TeachingTip_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 + dev\TitleBar\InteractionTests\TitleBar_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\TreeView\InteractionTests\TreeView_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\TwoPaneView\InteractionTests\TwoPaneView_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 dev\WebView2\InteractionTests\WebView2_InteractionTests.projitems*{4d8c5d1b-f982-44a1-b744-dd0e51651bf2}*SharedItemsImports = 5 @@ -1874,8 +1605,6 @@ Global dev\LayoutPanel\APITests\LayoutPanel_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\MapControl\APITests\MapControl_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\MapControl\TestUI\MapControl_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 - dev\SelectorBar\APITests\SelectorBar_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 - dev\SelectorBar\TestUI\SelectorBar_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\Materials\Acrylic\APITests\AcrylicBrush_ApiTests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\Materials\Acrylic\TestUI\AcrylicBrush_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\Materials\Reveal\APITests\Reveal_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 @@ -1916,6 +1645,8 @@ Global dev\ScrollPresenter\TestUI\ScrollPresenter_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\ScrollView\APITests\ScrollView_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\ScrollView\TestUI\ScrollView_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 + dev\SelectorBar\APITests\SelectorBar_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 + dev\SelectorBar\TestUI\SelectorBar_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\SplitButton\APITests\SplitButton_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\SplitButton\TestUI\SplitButton_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\SplitView\TestUI\SplitView_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 @@ -1925,6 +1656,7 @@ Global dev\TabView\TestUI\TabView_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\TeachingTip\APITests\TeachingTip_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\TeachingTip\TestUI\TeachingTip_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 + dev\TitleBar\TestUI\TitleBar_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\TreeView\APITests\TreeView_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\TreeView\TestUI\TreeView_TestUI.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 dev\TwoPaneView\APITests\TwoPaneView_APITests.projitems*{4e6f8103-9e20-40dd-8fe0-1e73964bb800}*SharedItemsImports = 5 diff --git a/src/controls/MUXExperimental.sln b/src/controls/MUXExperimental.sln deleted file mode 100644 index dc284579aa..0000000000 --- a/src/controls/MUXExperimental.sln +++ /dev/null @@ -1,269 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29209.152 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dev", "dev", "{67599AD5-51EC-44CB-85CE-B60CD8CBA270}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "dev\Common\Common.vcxitems", "{80AD7F51-8997-47B9-BB41-078B81CFF9B0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D3327F36-E161-4FED-A0F4-56F2B735827E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Collections", "dev\Collections\Collections.vcxitems", "{395A71A1-4327-477B-85D4-AF0851732CCB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5654F115-F01A-495B-91C7-09408ABF14F0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ResourceHelper", "dev\ResourceHelper\ResourceHelper.vcxitems", "{45D41ACC-2C3C-43D2-BC10-02AA73FFC7C7}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CommonManaged", "dev\CommonManaged\CommonManaged.shproj", "{85A134E5-C83F-44A4-80DF-59F6EBF6C60D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Experimental.UI.Xaml", "dev\dll\Microsoft.Experimental.UI.Xaml.vcxproj", "{4647FA1B-124E-4447-AF56-4016AB6FAF4A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleControl", "SampleControl", "{718B6519-D0E4-4236-AB21-517AF3B3EE27}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleControl", "dev\SampleControl\SampleControl.vcxitems", "{A329FB8A-3093-4050-83D3-4D9F5847F3B8}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SampleControl_TestUI", "dev\SampleControl\TestUI\SampleControl_TestUI.shproj", "{05361409-7FBB-4296-996F-2E591857D84A}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SampleControl_InteractionTests", "dev\SampleControl\InteractionTests\SampleControl_InteractionTests.shproj", "{30120040-3EB8-404D-9344-5E99E34B6090}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MUXExperimentalTestApp", "test\MUXExperimentalTest\MUXExperimentalTestApp\MUXExperimentalTestApp.csproj", "{CCA3696F-5CAC-421D-8528-4D9122B4D240}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppTestAutomationHelpers", "test\testinfra\AppTestAutomationHelpers\AppTestAutomationHelpers.vcxproj", "{128E6F7A-578C-48DC-BD3F-750EC662C268}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MUXExperimentalControls.Test", "MUXExperimentalControls.Test", "{C41F6221-0716-4A7B-AE58-7A9D0DDAA53F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MSTest", "MSTest", "{1D0CC29F-61C8-4330-9CB6-AA9D7F9ACE38}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MUXExperimental.Test", "test\MUXExperimentalTest\MUXExperimental.Test\MSTest\MUXExperimental.Test.csproj", "{D06B12F6-8633-4C9C-8F0D-114AA7184459}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "MUXExperimental.Test.Shared", "test\MUXExperimentalTest\MUXExperimental.Test\MUXExperimental.Test.Shared.shproj", "{815C5F42-3DEB-4DCB-B143-1C088FCE97F9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TAEF", "TAEF", "{8CD5C170-B2DE-4E68-B6CC-C52DFEFA6D85}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MUXExperimental.Test.TAEF", "test\MUXExperimentalTest\MUXExperimental.Test\TAEF\MUXExperimental.Test.TAEF.csproj", "{14018522-0223-4334-87D2-C343074DDD48}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MUXTestInfra.TAEF", "test\testinfra\MUXTestInfra\TAEF\MUXTestInfra.TAEF.csproj", "{74F6AA79-E026-4FDC-8294-49102674977A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestInfra", "TestInfra", "{CCF338CD-58F3-4C91-8674-14DA5ADFD8EE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TAEF", "TAEF", "{AD9D5064-9E3C-43FB-9B3A-DD1E44301021}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MSTest", "MSTest", "{85C7AE5E-F4C5-4FEE-82A9-881FA2251649}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MUXTestInfra.MSTest", "test\testinfra\MUXTestInfra\MSTest\MUXTestInfra.MSTest.csproj", "{E9BC58A3-A066-4120-9E8B-611DC8DE4600}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonStyles", "dev\CommonStyles\CommonStyles.vcxitems", "{3A07FA59-C5C1-4B46-8B31-043F9CA91226}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TitleBar", "TitleBar", "{EF60F757-9BD4-4D53-A3C7-6860C67CE4B4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TitleBar", "dev\TitleBar\TitleBar.vcxitems", "{B122B4A6-BA38-4738-984B-3DAB2177D5E2}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TitleBar_TestUI", "dev\TitleBar\TestUI\TitleBar_TestUI.shproj", "{0C05E2F0-F21F-4E60-A5BD-B4F5EB655C1D}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TitleBar_InteractionTests", "dev\TitleBar\InteractionTests\TitleBar_InteractionTests.shproj", "{AEC0BAEE-7A86-4539-9E07-A5363F7B9A8C}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - dev\SampleControl\TestUI\SampleControl_TestUI.projitems*{05361409-7fbb-4296-996f-2e591857d84a}*SharedItemsImports = 13 - dev\TitleBar\TestUI\TitleBar_TestUI.projitems*{0c05e2f0-f21f-4e60-a5bd-b4f5eb655c1d}*SharedItemsImports = 13 - dev\SampleControl\InteractionTests\SampleControl_InteractionTests.projitems*{30120040-3eb8-404d-9344-5e99e34b6090}*SharedItemsImports = 13 - dev\Collections\Collections.vcxitems*{395a71a1-4327-477b-85d4-af0851732ccb}*SharedItemsImports = 9 - dev\CommonStyles\CommonStyles.vcxitems*{3a07fa59-c5c1-4b46-8b31-043f9ca91226}*SharedItemsImports = 9 - dev\ResourceHelper\ResourceHelper.vcxitems*{45d41acc-2c3c-43d2-bc10-02aa73ffc7c7}*SharedItemsImports = 9 - dev\Collections\Collections.vcxitems*{4647fa1b-124e-4447-af56-4016ab6faf4a}*SharedItemsImports = 4 - dev\CommonStyles\CommonStyles.vcxitems*{4647fa1b-124e-4447-af56-4016ab6faf4a}*SharedItemsImports = 4 - dev\ResourceHelper\ResourceHelper.vcxitems*{4647fa1b-124e-4447-af56-4016ab6faf4a}*SharedItemsImports = 4 - dev\SampleControl\SampleControl.vcxitems*{4647fa1b-124e-4447-af56-4016ab6faf4a}*SharedItemsImports = 4 - dev\TitleBar\TitleBar.vcxitems*{4647fa1b-124e-4447-af56-4016ab6faf4a}*SharedItemsImports = 4 - dev\Common\Common.vcxitems*{80ad7f51-8997-47b9-bb41-078b81cff9b0}*SharedItemsImports = 9 - dev\SampleControl\InteractionTests\SampleControl_InteractionTests.projitems*{815c5f42-3deb-4dcb-b143-1c088fce97f9}*SharedItemsImports = 13 - dev\TitleBar\InteractionTests\TitleBar_InteractionTests.projitems*{815c5f42-3deb-4dcb-b143-1c088fce97f9}*SharedItemsImports = 13 - test\MUXExperimentalTest\MUXExperimental.Test\MUXExperimental.Test.Shared.projitems*{815c5f42-3deb-4dcb-b143-1c088fce97f9}*SharedItemsImports = 13 - dev\CommonManaged\CommonManaged.projitems*{85a134e5-c83f-44a4-80df-59f6ebf6c60d}*SharedItemsImports = 13 - dev\SampleControl\SampleControl.vcxitems*{a329fb8a-3093-4050-83d3-4d9f5847f3b8}*SharedItemsImports = 9 - dev\TitleBar\InteractionTests\TitleBar_InteractionTests.projitems*{aec0baee-7a86-4539-9e07-a5363f7b9a8c}*SharedItemsImports = 13 - dev\TitleBar\TitleBar.vcxitems*{b122b4a6-ba38-4738-984b-3dab2177d5e2}*SharedItemsImports = 9 - dev\SampleControl\TestUI\SampleControl_TestUI.projitems*{cca3696f-5cac-421d-8528-4d9122b4d240}*SharedItemsImports = 4 - dev\TitleBar\TestUI\TitleBar_TestUI.projitems*{cca3696f-5cac-421d-8528-4d9122b4d240}*SharedItemsImports = 4 - test\TestAppUtils\TestAppUtils.projitems*{cca3696f-5cac-421d-8528-4d9122b4d240}*SharedItemsImports = 4 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug_test|ARM64 = Debug_test|ARM64 - Debug_test|x64 = Debug_test|x64 - Debug_test|x86 = Debug_test|x86 - Debug|ARM64 = Debug|ARM64 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|ARM64 = Release|ARM64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug_test|x64.ActiveCfg = Debug|x64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug_test|x64.Build.0 = Debug|x64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug_test|x86.ActiveCfg = Debug|Win32 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug_test|x86.Build.0 = Debug|Win32 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug|ARM64.Build.0 = Debug|ARM64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug|x64.ActiveCfg = Debug|x64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug|x64.Build.0 = Debug|x64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug|x86.ActiveCfg = Debug|Win32 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Debug|x86.Build.0 = Debug|Win32 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Release|ARM64.ActiveCfg = Release|ARM64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Release|ARM64.Build.0 = Release|ARM64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Release|x64.ActiveCfg = Release|x64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Release|x64.Build.0 = Release|x64 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Release|x86.ActiveCfg = Release|Win32 - {4647FA1B-124E-4447-AF56-4016AB6FAF4A}.Release|x86.Build.0 = Release|Win32 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug_test|ARM64.ActiveCfg = Debug_test|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug_test|x64.ActiveCfg = Debug_test|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug_test|x64.Build.0 = Debug_test|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug_test|x64.Deploy.0 = Debug_test|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug_test|x86.ActiveCfg = Debug|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug_test|x86.Build.0 = Debug|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug_test|x86.Deploy.0 = Debug|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug|ARM64.ActiveCfg = Debug|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug|x64.ActiveCfg = Debug|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug|x64.Build.0 = Debug|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug|x64.Deploy.0 = Debug|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug|x86.ActiveCfg = Debug|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug|x86.Build.0 = Debug|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Debug|x86.Deploy.0 = Debug|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Release|ARM64.ActiveCfg = Release|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Release|x64.ActiveCfg = Release|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Release|x64.Build.0 = Release|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Release|x64.Deploy.0 = Release|x64 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Release|x86.ActiveCfg = Release|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Release|x86.Build.0 = Release|x86 - {CCA3696F-5CAC-421D-8528-4D9122B4D240}.Release|x86.Deploy.0 = Release|x86 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug_test|ARM64.ActiveCfg = Debug|ARM64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug_test|ARM64.Build.0 = Debug|ARM64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug_test|x64.ActiveCfg = Debug|x64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug_test|x64.Build.0 = Debug|x64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug_test|x86.ActiveCfg = Debug|Win32 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug_test|x86.Build.0 = Debug|Win32 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug|ARM64.Build.0 = Debug|ARM64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug|x64.ActiveCfg = Debug|x64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug|x64.Build.0 = Debug|x64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug|x86.ActiveCfg = Debug|Win32 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Debug|x86.Build.0 = Debug|Win32 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Release|ARM64.ActiveCfg = Release|ARM64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Release|ARM64.Build.0 = Release|ARM64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Release|x64.ActiveCfg = Release|x64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Release|x64.Build.0 = Release|x64 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Release|x86.ActiveCfg = Release|Win32 - {128E6F7A-578C-48DC-BD3F-750EC662C268}.Release|x86.Build.0 = Release|Win32 - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug_test|ARM64.ActiveCfg = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug_test|ARM64.Build.0 = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug_test|x64.ActiveCfg = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug_test|x64.Build.0 = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug_test|x86.ActiveCfg = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug_test|x86.Build.0 = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug|ARM64.Build.0 = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug|x64.ActiveCfg = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug|x64.Build.0 = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug|x86.ActiveCfg = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Debug|x86.Build.0 = Debug|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Release|ARM64.ActiveCfg = Release|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Release|ARM64.Build.0 = Release|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Release|x64.ActiveCfg = Release|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Release|x64.Build.0 = Release|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Release|x86.ActiveCfg = Release|Any CPU - {D06B12F6-8633-4C9C-8F0D-114AA7184459}.Release|x86.Build.0 = Release|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug_test|ARM64.ActiveCfg = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug_test|ARM64.Build.0 = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug_test|x64.ActiveCfg = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug_test|x64.Build.0 = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug_test|x86.ActiveCfg = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug_test|x86.Build.0 = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug|ARM64.Build.0 = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug|x64.ActiveCfg = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug|x64.Build.0 = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug|x86.ActiveCfg = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Debug|x86.Build.0 = Debug|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Release|ARM64.ActiveCfg = Release|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Release|ARM64.Build.0 = Release|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Release|x64.ActiveCfg = Release|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Release|x64.Build.0 = Release|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Release|x86.ActiveCfg = Release|Any CPU - {14018522-0223-4334-87D2-C343074DDD48}.Release|x86.Build.0 = Release|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug_test|ARM64.ActiveCfg = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug_test|ARM64.Build.0 = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug_test|x64.ActiveCfg = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug_test|x64.Build.0 = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug_test|x86.ActiveCfg = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug_test|x86.Build.0 = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug|ARM64.Build.0 = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug|x64.ActiveCfg = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug|x64.Build.0 = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug|x86.ActiveCfg = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Debug|x86.Build.0 = Debug|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Release|ARM64.ActiveCfg = Release|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Release|ARM64.Build.0 = Release|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Release|x64.ActiveCfg = Release|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Release|x64.Build.0 = Release|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Release|x86.ActiveCfg = Release|Any CPU - {74F6AA79-E026-4FDC-8294-49102674977A}.Release|x86.Build.0 = Release|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug_test|ARM64.ActiveCfg = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug_test|ARM64.Build.0 = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug_test|x64.ActiveCfg = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug_test|x64.Build.0 = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug_test|x86.ActiveCfg = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug_test|x86.Build.0 = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug|ARM64.Build.0 = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug|x64.ActiveCfg = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug|x64.Build.0 = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug|x86.ActiveCfg = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Debug|x86.Build.0 = Debug|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Release|ARM64.ActiveCfg = Release|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Release|ARM64.Build.0 = Release|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Release|x64.ActiveCfg = Release|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Release|x64.Build.0 = Release|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Release|x86.ActiveCfg = Release|Any CPU - {E9BC58A3-A066-4120-9E8B-611DC8DE4600}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {80AD7F51-8997-47B9-BB41-078B81CFF9B0} = {5654F115-F01A-495B-91C7-09408ABF14F0} - {395A71A1-4327-477B-85D4-AF0851732CCB} = {5654F115-F01A-495B-91C7-09408ABF14F0} - {5654F115-F01A-495B-91C7-09408ABF14F0} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} - {45D41ACC-2C3C-43D2-BC10-02AA73FFC7C7} = {5654F115-F01A-495B-91C7-09408ABF14F0} - {85A134E5-C83F-44A4-80DF-59F6EBF6C60D} = {5654F115-F01A-495B-91C7-09408ABF14F0} - {4647FA1B-124E-4447-AF56-4016AB6FAF4A} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} - {718B6519-D0E4-4236-AB21-517AF3B3EE27} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} - {A329FB8A-3093-4050-83D3-4D9F5847F3B8} = {718B6519-D0E4-4236-AB21-517AF3B3EE27} - {05361409-7FBB-4296-996F-2E591857D84A} = {718B6519-D0E4-4236-AB21-517AF3B3EE27} - {30120040-3EB8-404D-9344-5E99E34B6090} = {718B6519-D0E4-4236-AB21-517AF3B3EE27} - {CCA3696F-5CAC-421D-8528-4D9122B4D240} = {D3327F36-E161-4FED-A0F4-56F2B735827E} - {128E6F7A-578C-48DC-BD3F-750EC662C268} = {CCF338CD-58F3-4C91-8674-14DA5ADFD8EE} - {C41F6221-0716-4A7B-AE58-7A9D0DDAA53F} = {D3327F36-E161-4FED-A0F4-56F2B735827E} - {1D0CC29F-61C8-4330-9CB6-AA9D7F9ACE38} = {C41F6221-0716-4A7B-AE58-7A9D0DDAA53F} - {D06B12F6-8633-4C9C-8F0D-114AA7184459} = {1D0CC29F-61C8-4330-9CB6-AA9D7F9ACE38} - {815C5F42-3DEB-4DCB-B143-1C088FCE97F9} = {C41F6221-0716-4A7B-AE58-7A9D0DDAA53F} - {8CD5C170-B2DE-4E68-B6CC-C52DFEFA6D85} = {C41F6221-0716-4A7B-AE58-7A9D0DDAA53F} - {14018522-0223-4334-87D2-C343074DDD48} = {8CD5C170-B2DE-4E68-B6CC-C52DFEFA6D85} - {74F6AA79-E026-4FDC-8294-49102674977A} = {AD9D5064-9E3C-43FB-9B3A-DD1E44301021} - {CCF338CD-58F3-4C91-8674-14DA5ADFD8EE} = {D3327F36-E161-4FED-A0F4-56F2B735827E} - {AD9D5064-9E3C-43FB-9B3A-DD1E44301021} = {CCF338CD-58F3-4C91-8674-14DA5ADFD8EE} - {85C7AE5E-F4C5-4FEE-82A9-881FA2251649} = {CCF338CD-58F3-4C91-8674-14DA5ADFD8EE} - {E9BC58A3-A066-4120-9E8B-611DC8DE4600} = {85C7AE5E-F4C5-4FEE-82A9-881FA2251649} - {3A07FA59-C5C1-4B46-8B31-043F9CA91226} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} - {EF60F757-9BD4-4D53-A3C7-6860C67CE4B4} = {67599AD5-51EC-44CB-85CE-B60CD8CBA270} - {B122B4A6-BA38-4738-984B-3DAB2177D5E2} = {EF60F757-9BD4-4D53-A3C7-6860C67CE4B4} - {0C05E2F0-F21F-4E60-A5BD-B4F5EB655C1D} = {EF60F757-9BD4-4D53-A3C7-6860C67CE4B4} - {AEC0BAEE-7A86-4539-9E07-A5363F7B9A8C} = {EF60F757-9BD4-4D53-A3C7-6860C67CE4B4} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {D93836AB-52D3-4DE2-AE25-23F26F55ECED} - EndGlobalSection -EndGlobal diff --git a/src/controls/ProjectImports.targets b/src/controls/ProjectImports.targets index 03211020f2..f60b5b02b2 100644 --- a/src/controls/ProjectImports.targets +++ b/src/controls/ProjectImports.targets @@ -64,5 +64,6 @@ + \ No newline at end of file diff --git a/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.cpp b/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.cpp index c632834805..6b643b4a3c 100644 --- a/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.cpp +++ b/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.cpp @@ -428,9 +428,17 @@ void AnimatedVisualPlayer::OnLoaded(winrt::IInspectable const& /*sender*/, winrt void AnimatedVisualPlayer::OnUnloaded(winrt::IInspectable const& /*sender*/, winrt::RoutedEventArgs const& /*args*/) { - m_isUnloaded = true; - // Remove any content. If we get reloaded the content will get reloaded. - UnloadContent(); + // There is an anomaly in the Loading/Loaded/Unloaded events that can cause an Unloaded event to + // fire when the element is in the tree. When this happens, we end up unlaoding our content + // and not displaying it. Unfortunately, we can't fix this until at least version 2.0 so for + // for now we will work around it (as we have suggested to customers to do), by checking to see + // if we are actually unloaded before removing our content. + if (!IsLoaded()) + { + m_isUnloaded = true; + // Remove any content. If we get reloaded the content will get reloaded. + UnloadContent(); + } } void AnimatedVisualPlayer::OnHiding() diff --git a/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.h b/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.h index 103f666ef2..8dd75b0098 100644 --- a/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.h +++ b/src/controls/dev/AnimatedVisualPlayer/AnimatedVisualPlayer.h @@ -130,7 +130,7 @@ struct AnimatedVisualPlayer : // tracker_ref m_animatedVisual{ this }; // The native size of the current animated visual. Only valid if m_animatedVisual is not nullptr. - winrt::float2 m_animatedVisualSize; + winrt::float2 m_animatedVisualSize{}; winrt::Visual m_animatedVisualRoot{ nullptr }; int m_playAsyncVersion{ 0 }; double m_currentPlayFromProgress{ 0 }; diff --git a/src/controls/dev/AnnotatedScrollBar/InteractionTests/AnnotatedScrollBarInteractionTests.cs b/src/controls/dev/AnnotatedScrollBar/InteractionTests/AnnotatedScrollBarInteractionTests.cs index f316b1b349..08c7e37433 100644 --- a/src/controls/dev/AnnotatedScrollBar/InteractionTests/AnnotatedScrollBarInteractionTests.cs +++ b/src/controls/dev/AnnotatedScrollBar/InteractionTests/AnnotatedScrollBarInteractionTests.cs @@ -327,11 +327,11 @@ public void CollidingLabelsAreRemoved() Verify.IsNotNull(label19); Log.Comment("Some intermediate items not removed by collision logic should be visible."); - var label4 = ElementCache.TryGetObjectByName("Num 4", false); - Verify.IsNotNull(label4); + var label3 = ElementCache.TryGetObjectByName("Num 3", false); + Verify.IsNotNull(label3); - var label16 = ElementCache.TryGetObjectByName("Num 16", false); - Verify.IsNotNull(label16); + var label15 = ElementCache.TryGetObjectByName("Num 15", false); + Verify.IsNotNull(label15); Log.Comment("Some intermediate items removed by collision logic should not be visible."); var label1 = ElementCache.TryGetObjectByName("Num 1", false); diff --git a/src/controls/dev/AutoSuggestBox/AutoSuggestBox_themeresources.xaml b/src/controls/dev/AutoSuggestBox/AutoSuggestBox_themeresources.xaml index 87e1572913..e7c38b22aa 100644 --- a/src/controls/dev/AutoSuggestBox/AutoSuggestBox_themeresources.xaml +++ b/src/controls/dev/AutoSuggestBox/AutoSuggestBox_themeresources.xaml @@ -236,7 +236,7 @@ - + + diff --git a/src/controls/dev/CommonStyles/TestUI/ListViewPage.xaml.cs b/src/controls/dev/CommonStyles/TestUI/ListViewPage.xaml.cs index 72fd6e4b24..3181ad891b 100644 --- a/src/controls/dev/CommonStyles/TestUI/ListViewPage.xaml.cs +++ b/src/controls/dev/CommonStyles/TestUI/ListViewPage.xaml.cs @@ -15,6 +15,7 @@ public ListViewPage() navigateToListView.Click += delegate { Frame.NavigateWithoutAnimation(typeof(ListViewBasePage), false /*use GridView*/); }; navigateToGroupedListView.Click += delegate { Frame.NavigateWithoutAnimation(typeof(GroupedListViewBasePage), false /*use GridView*/); }; navigateToNestedListViews.Click += delegate { Frame.NavigateWithoutAnimation(typeof(NestedListViewsPage)); }; + navigateToListViewAnchoring.Click += delegate { Frame.NavigateWithoutAnimation(typeof(ListViewAnchoringPage)); }; } } } diff --git a/src/controls/dev/CommonStyles/TestUI/NewWindowRootPage.xaml b/src/controls/dev/CommonStyles/TestUI/NewWindowRootPage.xaml new file mode 100644 index 0000000000..790e565c1e --- /dev/null +++ b/src/controls/dev/CommonStyles/TestUI/NewWindowRootPage.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + One + Two + Three + Four + Five + Six + + + + diff --git a/src/controls/dev/CommonStyles/TestUI/NewWindowRootPage.xaml.cs b/src/controls/dev/CommonStyles/TestUI/NewWindowRootPage.xaml.cs new file mode 100644 index 0000000000..c4594206de --- /dev/null +++ b/src/controls/dev/CommonStyles/TestUI/NewWindowRootPage.xaml.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.UI.Xaml.Controls; + +namespace MUXControlsTestApp +{ + public sealed partial class NewWindowRootPage : TestPage + { + public NewWindowRootPage() + { + this.InitializeComponent(); + } + } +} diff --git a/src/controls/dev/CommonStyles/TestUI/TextControlsPage.xaml.cs b/src/controls/dev/CommonStyles/TestUI/TextControlsPage.xaml.cs index 2bb9d4cc0d..c43345c135 100644 --- a/src/controls/dev/CommonStyles/TestUI/TextControlsPage.xaml.cs +++ b/src/controls/dev/CommonStyles/TestUI/TextControlsPage.xaml.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using MUXControlsTestApp.Utilities; namespace MUXControlsTestApp { @@ -21,12 +22,12 @@ private void ResizeRootGrid(object sender, RoutedEventArgs e) { if (isRootGridDefaultSize) { - TestFrame.Instance.SetRootGridSizeToCustomSize(1, 1); + this.FindVisualParentByType().SetRootGridSizeToCustomSize(1, 1); } else { // Reset to default size - TestFrame.Instance.SetRootGridSizeToCustomSize(-1, -1); + this.FindVisualParentByType().SetRootGridSizeToCustomSize(-1, -1); } isRootGridDefaultSize = !isRootGridDefaultSize; } diff --git a/src/controls/dev/CommonStyles/TestUI/VisualPropertiesPage.xaml b/src/controls/dev/CommonStyles/TestUI/VisualPropertiesPage.xaml new file mode 100644 index 0000000000..feba2b75b7 --- /dev/null +++ b/src/controls/dev/CommonStyles/TestUI/VisualPropertiesPage.xaml @@ -0,0 +1,196 @@ + + + + + + + + + + + + Red + + + + Purple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ComboBoxItem1 + + + + + + + + + + + + + + + Center + + + + + + + + + Layers + + + + + + + + Pins + + + + + + + + + Output + - diff --git a/src/controls/dev/MapControl/TestUI/MapControlPage.xaml.cs b/src/controls/dev/MapControl/TestUI/MapControlPage.xaml.cs index 1534b38a8b..1c62ac8520 100644 --- a/src/controls/dev/MapControl/TestUI/MapControlPage.xaml.cs +++ b/src/controls/dev/MapControl/TestUI/MapControlPage.xaml.cs @@ -20,31 +20,88 @@ public sealed partial class MapControlPage : TestPage public MapControlPage() { this.InitializeComponent(); + + myMap.MapServiceToken = MapControlApiKey.AzureMapsToken; BasicGeoposition firstCenterPosition = new BasicGeoposition() { Latitude = 0, Longitude = 0 }; Geopoint firstCenterPoint = new Geopoint(firstCenterPosition); myMap.Center = firstCenterPoint; - var iconLayer = new MapElementsLayer - { - MapElements = new List() - { - new MapIcon - { - Location = new Geopoint(new BasicGeoposition - { - Latitude = 14.865162, - Longitude = -14.858078 - }), - } - } - }; - myMap.Layers.Add(iconLayer); + myMap.MapElementClick += Map_MapElementClick; + myMap.MapServiceErrorOccurred += Map_MapServiceErrorOccurred; } private void GoButton_Click(object sender, RoutedEventArgs e) { myMap.MapServiceToken = MapServiceToken.Password; } + + private void Map_MapServiceErrorOccurred(MapControl sender, MapControlMapServiceErrorOccurredEventArgs args) + { + output.Text += args.DiagnosticMessage; + } + + private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e) + { + ToggleSwitch toggleSwitch = sender as ToggleSwitch; + if (toggleSwitch != null) + { + myMap.InteractiveControlsVisible = toggleSwitch.IsOn; + } + } + private void CenterButton_Click(object sender, RoutedEventArgs e) + { + BasicGeoposition centerPosition = new BasicGeoposition() + { + Latitude = double.Parse(latitudeText.Text), + Longitude = double.Parse(longitudeText.Text) + }; + Geopoint centerPoint = new Geopoint(centerPosition); + myMap.Center = centerPoint; + } + private void SetZoom_Click(object sender, RoutedEventArgs e) + { + myMap.ZoomLevel = double.Parse(zoomText.Text); + } + private void AddPin_Click(object sender, RoutedEventArgs e) + { + BasicGeoposition position = new BasicGeoposition() + { + Latitude = double.Parse(latitudePinText.Text), + Longitude = double.Parse(longitudePinText.Text) + }; + Geopoint point = new Geopoint(position); + + var icon = new MapIcon + { + Location = point, + }; + + var selectedLayer = layersSelection.SelectedItem as MapElementsLayer; + selectedLayer.MapElements.Add(icon); + } + private void AddLayer_Click(object sender, RoutedEventArgs e) + { + var newLayer = new MapElementsLayer{}; + + newLayer.MapElementClick += Layer_MapElementClick; + myMap.Layers.Add(newLayer); + layersSelection.Items.Add(newLayer); + if(layersSelection.SelectedIndex == -1) + { + layersSelection.SelectedIndex = 0; + } + } + + private void Layer_MapElementClick(MapElementsLayer sender, MapElementClickEventArgs args) + { + var icon = args.Element as MapIcon; + sender.MapElements.Remove(icon); + output.Text += "Layer Clicked\n"; + } + private void Map_MapElementClick(MapControl sender, MapElementClickEventArgs args) + { + output.Text += "Map Clicked\n"; + } } } diff --git a/src/controls/dev/MapControl/TestUI/MapControl_TestUI.projitems b/src/controls/dev/MapControl/TestUI/MapControl_TestUI.projitems index 2a6ab3ad2b..ef64b83f35 100644 --- a/src/controls/dev/MapControl/TestUI/MapControl_TestUI.projitems +++ b/src/controls/dev/MapControl/TestUI/MapControl_TestUI.projitems @@ -19,5 +19,6 @@ MapControlPage.xaml + diff --git a/src/controls/dev/MapControl/map.html b/src/controls/dev/MapControl/map.html index 43a49ace5a..f009f32ab9 100644 --- a/src/controls/dev/MapControl/map.html +++ b/src/controls/dev/MapControl/map.html @@ -5,6 +5,556 @@ + - \ No newline at end of file + diff --git a/src/controls/dev/MenuBar/MenuBar_themeresources.xaml b/src/controls/dev/MenuBar/MenuBar_themeresources.xaml index 8cc6b2b527..96cf1b1e78 100644 --- a/src/controls/dev/MenuBar/MenuBar_themeresources.xaml +++ b/src/controls/dev/MenuBar/MenuBar_themeresources.xaml @@ -3,6 +3,7 @@ + @@ -15,6 +16,7 @@ + @@ -27,6 +29,7 @@ + @@ -41,4 +44,4 @@ 40 10,4,10,4 4,4,4,4 - \ No newline at end of file + diff --git a/src/controls/dev/NavigationView/NavigationView.cpp b/src/controls/dev/NavigationView/NavigationView.cpp index 305bb3c885..ea5f8a7a13 100644 --- a/src/controls/dev/NavigationView/NavigationView.cpp +++ b/src/controls/dev/NavigationView/NavigationView.cpp @@ -454,7 +454,7 @@ void NavigationView::OnApplyTemplate() if (auto stackLayout = leftNavRepeater.Layout().try_as()) { auto stackLayoutImpl = winrt::get_self(stackLayout); - stackLayoutImpl->DisableVirtualization(true); + stackLayoutImpl->IsVirtualizationEnabled(false); } m_leftNavItemsRepeaterElementPreparedRevoker = leftNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared }); @@ -476,7 +476,7 @@ void NavigationView::OnApplyTemplate() if (auto stackLayout = topNavRepeater.Layout().try_as()) { auto stackLayoutImpl = winrt::get_self(stackLayout); - stackLayoutImpl->DisableVirtualization(true); + stackLayoutImpl->IsVirtualizationEnabled(false); } m_topNavItemsRepeaterElementPreparedRevoker = topNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared }); @@ -499,7 +499,7 @@ void NavigationView::OnApplyTemplate() if (auto stackLayout = topNavListOverflowRepeater.Layout().try_as()) { auto stackLayoutImpl = winrt::get_self(stackLayout); - stackLayoutImpl->DisableVirtualization(true); + stackLayoutImpl->IsVirtualizationEnabled(false); } m_topNavOverflowItemsRepeaterElementPreparedRevoker = topNavListOverflowRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared }); @@ -541,7 +541,7 @@ void NavigationView::OnApplyTemplate() if (auto stackLayout = leftFooterMenuNavRepeater.Layout().try_as()) { auto stackLayoutImpl = winrt::get_self(stackLayout); - stackLayoutImpl->DisableVirtualization(true); + stackLayoutImpl->IsVirtualizationEnabled(false); } m_leftNavFooterMenuItemsRepeaterElementPreparedRevoker = leftFooterMenuNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared }); @@ -564,7 +564,7 @@ void NavigationView::OnApplyTemplate() if (auto stackLayout = topFooterMenuNavRepeater.Layout().try_as()) { auto stackLayoutImpl = winrt::get_self(stackLayout); - stackLayoutImpl->DisableVirtualization(true); + stackLayoutImpl->IsVirtualizationEnabled(false); } m_topNavFooterMenuItemsRepeaterElementPreparedRevoker = topFooterMenuNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared }); @@ -2281,6 +2281,9 @@ winrt::UIElement NavigationView::FindSelectionIndicator(const winrt::IInspectabl // Indicator was not found, so maybe the layout hasn't updated yet. // So let's do that now. container.UpdateLayout(); + // Before manually calling ApplyTemplate, make sure the NavigationViewItem is aware + // of its owning NavigationView (it is required info for the NavigationViewItem ApplyTemplate process). + winrt::get_self(container)->SetNavigationViewParent(*this); container.ApplyTemplate(); return winrt::get_self(container)->GetSelectionIndicator(); } diff --git a/src/controls/dev/NavigationView/NavigationViewItem.cpp b/src/controls/dev/NavigationView/NavigationViewItem.cpp index 285413d8f1..5413b525b8 100644 --- a/src/controls/dev/NavigationView/NavigationViewItem.cpp +++ b/src/controls/dev/NavigationView/NavigationViewItem.cpp @@ -161,7 +161,7 @@ void NavigationViewItem::LoadMenuItemsHost() if (auto stackLayout = repeater.Layout().try_as()) { auto stackLayoutImpl = winrt::get_self(stackLayout); - stackLayoutImpl->DisableVirtualization(true); + stackLayoutImpl->IsVirtualizationEnabled(false); } // Primary element setup happens in NavigationView diff --git a/src/controls/dev/NavigationView/NavigationViewItemPresenter.cpp b/src/controls/dev/NavigationView/NavigationViewItemPresenter.cpp index 63e82938e0..8825f074ad 100644 --- a/src/controls/dev/NavigationView/NavigationViewItemPresenter.cpp +++ b/src/controls/dev/NavigationView/NavigationViewItemPresenter.cpp @@ -23,12 +23,17 @@ void NavigationViewItemPresenter::UnhookEventsAndClearFields() { m_expandCollapseChevronPointerPressedRevoker.revoke(); m_expandCollapseChevronPointerReleasedRevoker.revoke(); + m_expandCollapseChevronPointerExitedRevoker.revoke(); + m_expandCollapseChevronPointerCanceledRevoker.revoke(); + m_expandCollapseChevronPointerCaptureLostRevoker.revoke(); m_contentGrid.set(nullptr); m_infoBadgePresenter.set(nullptr); m_expandCollapseChevron.set(nullptr); m_chevronExpandedStoryboard.set(nullptr); m_chevronCollapsedStoryboard.set(nullptr); + + m_isChevronPressed = false; } void NavigationViewItemPresenter::OnApplyTemplate() @@ -83,15 +88,56 @@ void NavigationViewItemPresenter::LoadChevron() m_expandCollapseChevronPointerPressedRevoker = expandCollapseChevron.PointerPressed(winrt::auto_revoke, { this, &NavigationViewItemPresenter::OnExpandCollapseChevronPointerPressed }); m_expandCollapseChevronPointerReleasedRevoker = expandCollapseChevron.PointerReleased(winrt::auto_revoke, { this, &NavigationViewItemPresenter::OnExpandCollapseChevronPointerReleased }); + + m_expandCollapseChevronPointerCanceledRevoker = AddRoutedEventHandler( + *this, + { this, &NavigationViewItemPresenter::OnExpandCollapseChevronPointerCanceled }, + true /*handledEventsToo*/); + + m_expandCollapseChevronPointerExitedRevoker = AddRoutedEventHandler( + *this, + { this, &NavigationViewItemPresenter::OnExpandCollapseChevronPointerExited }, + true /*handledEventsToo*/); + + m_expandCollapseChevronPointerCaptureLostRevoker = AddRoutedEventHandler( + *this, + { this, &NavigationViewItemPresenter::OnExpandCollapseChevronPointerCaptureLost }, + true /*handledEventsToo*/); } } } } + +void NavigationViewItemPresenter::ResetTrackedPointerId() +{ + m_trackedPointerId = 0; +} + +// Returns False when the provided pointer Id matches the currently tracked Id. +// When there is no currently tracked Id, sets the tracked Id to the provided Id and returns False. +// Returns True when the provided pointer Id does not match the currently tracked Id. +bool NavigationViewItemPresenter::IgnorePointerId(const winrt::PointerRoutedEventArgs& args) +{ + uint32_t pointerId = args.Pointer().PointerId(); + + if (m_trackedPointerId == 0) + { + m_trackedPointerId = pointerId; + } + else if (m_trackedPointerId != pointerId) + { + return true; + } + return false; +} + void NavigationViewItemPresenter::OnExpandCollapseChevronPointerPressed(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args) { + const bool ignorePointerId = IgnorePointerId(args); const auto pointerProperties = args.GetCurrentPoint(*this).Properties(); - if (!pointerProperties.IsLeftButtonPressed() || + if (ignorePointerId || + !pointerProperties.IsLeftButtonPressed() || args.Handled()) { // We are only interested in the primary action of the pointer device @@ -100,20 +146,63 @@ void NavigationViewItemPresenter::OnExpandCollapseChevronPointerPressed(const wi return; } + m_isChevronPressed = true; args.Handled(true); } void NavigationViewItemPresenter::OnExpandCollapseChevronPointerReleased(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args) { + if (IgnorePointerId(args)) + { + return; + } + const auto navigationViewItem = GetNavigationViewItem(); const auto pointerProperties = args.GetCurrentPoint(*this).Properties(); if (!args.Handled() && + m_isChevronPressed && pointerProperties.PointerUpdateKind() == winrt::PointerUpdateKind::LeftButtonReleased && navigationViewItem) { navigationViewItem->OnExpandCollapseChevronPointerReleased(); args.Handled(true); } + + m_isChevronPressed = false; + ResetTrackedPointerId(); +} + +void NavigationViewItemPresenter::OnExpandCollapseChevronPointerCanceled(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args) +{ + if (IgnorePointerId(args)) + { + return; + } + + m_isChevronPressed = false; + ResetTrackedPointerId(); +} + +void NavigationViewItemPresenter::OnExpandCollapseChevronPointerExited(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args) +{ + if (IgnorePointerId(args)) + { + return; + } + + m_isChevronPressed = false; + ResetTrackedPointerId(); +} + +void NavigationViewItemPresenter::OnExpandCollapseChevronPointerCaptureLost(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args) +{ + if (IgnorePointerId(args)) + { + return; + } + + m_isChevronPressed = false; + ResetTrackedPointerId(); } void NavigationViewItemPresenter::RotateExpandCollapseChevron(bool isExpanded) diff --git a/src/controls/dev/NavigationView/NavigationViewItemPresenter.h b/src/controls/dev/NavigationView/NavigationViewItemPresenter.h index aa0e257791..785cf151d6 100644 --- a/src/controls/dev/NavigationView/NavigationViewItemPresenter.h +++ b/src/controls/dev/NavigationView/NavigationViewItemPresenter.h @@ -39,11 +39,19 @@ class NavigationViewItemPresenter: NavigationViewItem * GetNavigationViewItem(); void UpdateMargin(); void UnhookEventsAndClearFields(); + void ResetTrackedPointerId(); + bool IgnorePointerId(const winrt::PointerRoutedEventArgs& args); void OnExpandCollapseChevronPointerPressed(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args); void OnExpandCollapseChevronPointerReleased(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args); + void OnExpandCollapseChevronPointerExited(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args); + void OnExpandCollapseChevronPointerCanceled(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args); + void OnExpandCollapseChevronPointerCaptureLost(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args); + bool m_isChevronPressed{ false }; double m_compactPaneLengthValue { 40 }; + double m_leftIndentation{ 0 }; + uint32_t m_trackedPointerId{ 0 }; NavigationViewItemHelper m_helper{ this }; tracker_ref m_contentGrid{ this }; @@ -52,9 +60,10 @@ class NavigationViewItemPresenter: winrt::UIElement::PointerPressed_revoker m_expandCollapseChevronPointerPressedRevoker{}; winrt::UIElement::PointerReleased_revoker m_expandCollapseChevronPointerReleasedRevoker{}; - - double m_leftIndentation{ 0 }; - + RoutedEventHandler_revoker m_expandCollapseChevronPointerExitedRevoker{}; + RoutedEventHandler_revoker m_expandCollapseChevronPointerCanceledRevoker{}; + RoutedEventHandler_revoker m_expandCollapseChevronPointerCaptureLostRevoker{}; + tracker_ref m_chevronExpandedStoryboard{ this }; tracker_ref m_chevronCollapsedStoryboard{ this }; }; diff --git a/src/controls/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs b/src/controls/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs index 88e672fa91..0efd15ca69 100644 --- a/src/controls/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs +++ b/src/controls/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs @@ -54,7 +54,9 @@ private NavigationView SetupNavigationView(NavigationViewPaneDisplayMode paneDis RunOnUIThread.Execute(() => { navView = new NavigationView(); - navView.MenuItems.Add(new NavigationViewItem() { Content = "Undo", Icon = new SymbolIcon(Symbol.Undo) }); + var undoNVI = new NavigationViewItem() { Content = "Undo", Icon = new SymbolIcon(Symbol.Undo) }; + undoNVI.Resources.Add("NavigationViewItemIconBackground", new SolidColorBrush(Colors.Red)); + navView.MenuItems.Add(undoNVI); navView.MenuItems.Add(new NavigationViewItem() { Content = "Cut", Icon = new SymbolIcon(Symbol.Cut) }); navView.PaneTitle = "Title"; @@ -1437,17 +1439,22 @@ public void VerifySelectingACollapsedItemShowsSelectionIndicator() IdleSynchronizer.Wait(); + selectionChangedEvent.Reset(); + RunOnUIThread.Execute(() => { Category newItem2 = new("Menu Item 5", "MI5", "Icon", null, true); subCategories.Add(newItem2); + // This doesn't use SelectItem. I'm guessing we're testing for adding an item and immediately selecting + // it, rather than waiting for it to render first. navView.SelectedItem = newItem2; }); selectionChangedEvent.WaitOne(); IdleSynchronizer.Wait(); - Verify.IsTrue(ItemHasSelectionIndicator(navView, "Menu Item 5")); + // Disabled - see Bug 50123187: NavigationViewTests.VerifySelectingACollapsedItemShowsSelectionIndicator is unstable + //Verify.IsTrue(ItemHasSelectionIndicator(navView, "Menu Item 5")); } [TestMethod] diff --git a/src/controls/dev/NavigationView/NavigationView_InteractionTests/FocusBehaviorTests.cs b/src/controls/dev/NavigationView/NavigationView_InteractionTests/FocusBehaviorTests.cs index 463668df11..b7a00f3d08 100644 --- a/src/controls/dev/NavigationView/NavigationView_InteractionTests/FocusBehaviorTests.cs +++ b/src/controls/dev/NavigationView/NavigationView_InteractionTests/FocusBehaviorTests.cs @@ -302,6 +302,13 @@ public void TabNavigationHierarchicalTest() Button togglePaneButton = new Button(FindElement.ById("TogglePaneButton")); Button getSelectItemButton = new Button(FindElement.ByName("GetSelectedItemLabelButton")); + Log.Comment("Deselect Menu Item 1"); + UIObject menuItem1 = FindElement.ByName("Menu Item 1"); + menuItem1.SetFocus(); + AutomationElement menuItem1AE = AutomationElement.FocusedElement; + SelectionItemPattern menuItem1SIP = menuItem1AE.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern; + menuItem1SIP.RemoveFromSelection(); + VerifyTabNavigationWithoutMenuItemSelected(); VerifyTabNavigationWithMenuItemSelected(); VerifyTabNavigationWithSettingsItemVisible(); @@ -315,7 +322,6 @@ void VerifyTabNavigationWithoutMenuItemSelected() Verify.AreEqual("No Item Selected", GetSelectedItem()); - UIObject menuItem1 = FindElement.ByName("Menu Item 1"); UIObject menuItem29 = FindElement.ByName("Menu Item 29 (Selectable)"); // Set focus on the pane's toggle button. diff --git a/src/controls/dev/NavigationView/NavigationView_InteractionTests/SelectionTests.cs b/src/controls/dev/NavigationView/NavigationView_InteractionTests/SelectionTests.cs index 6568a994d7..34475e2e81 100644 --- a/src/controls/dev/NavigationView/NavigationView_InteractionTests/SelectionTests.cs +++ b/src/controls/dev/NavigationView/NavigationView_InteractionTests/SelectionTests.cs @@ -547,5 +547,24 @@ public void VerifySettingCustomSelectedItemInConstructorWorks() Verify.IsFalse(Convert.ToBoolean(thirdItem.GetProperty(UIProperty.Get("SelectionItem.IsSelected")))); } } + + [TestMethod] + public void VerifyNVIItemsRepeaterIsLoadedAfterSelectionSetInMarkup() + { + using (var setup = new TestSetupHelper(new[] { "NavigationView Tests", "HierarchicalNavigationView Markup Test" })) + { + Log.Comment("Verifying first item is selected."); + var firstItem = FindElement.ById("MI1"); + Verify.IsTrue(Convert.ToBoolean(firstItem.GetProperty(UIProperty.Get("SelectionItem.IsSelected")))); + + Log.Comment("Clicking on first item to expand it."); + InputHelper.LeftClick(firstItem); + Wait.ForIdle(); + + Log.Comment("Verifying children are shown."); + var secondItem = FindElement.ById("MI2"); + Verify.IsNotNull(secondItem, "Second item should be visible after expanding parent item."); + } + } } } diff --git a/src/controls/dev/NavigationView/NavigationView_InteractionTests/TopModeTests.cs b/src/controls/dev/NavigationView/NavigationView_InteractionTests/TopModeTests.cs index 430fff519d..78bd5867cf 100644 --- a/src/controls/dev/NavigationView/NavigationView_InteractionTests/TopModeTests.cs +++ b/src/controls/dev/NavigationView/NavigationView_InteractionTests/TopModeTests.cs @@ -752,5 +752,42 @@ void VerifyOverflowButtonIsCollapsed() } } } + + [TestMethod] + public void TopNavigationChevronClickTest() + { + using (var setup = new TestSetupHelper(new[] { "NavigationView Tests", "HierarchicalNavigationView Markup Test" })) + { + Log.Comment("Set PaneDisplayMode to Top"); + var panelDisplayModeComboBox = new ComboBox(FindElement.ByName("PaneDisplayModeCombobox")); + panelDisplayModeComboBox.SelectItemByName("Top"); + Wait.ForIdle(); + + UIObject menuItem1 = FindElement.ByName("Menu Item 1"); + Verify.IsNotNull(menuItem1); + + UIObject menuItem2 = FindElement.ByName("Menu Item 2"); + Verify.IsNull(menuItem2, "Menu Item 2 should not be visible."); + + ClickOnNavigationViewItemChevron(menuItem1); + + menuItem2 = FindElement.ByName("Menu Item 2"); + Verify.IsNotNull(menuItem2, "Menu Item 2 should be visible."); + + ClickOnNavigationViewItemChevron(menuItem1); + + ElementCache.Refresh(); + + menuItem2 = FindElement.ByName("Menu Item 2"); + Verify.IsNull(menuItem2, "Menu Item 2 should not be visible."); + } + } + + private void ClickOnNavigationViewItemChevron(UIObject nvi) + { + Log.Comment("Click On NavigationViewItem Chevron"); + InputHelper.LeftClick(nvi, nvi.BoundingRectangle.Width - 20, nvi.BoundingRectangle.Height / 2 + 10); + Wait.ForIdle(); + } } } diff --git a/src/controls/dev/NavigationView/NavigationView_themeresources.xaml b/src/controls/dev/NavigationView/NavigationView_themeresources.xaml index 9424310780..aa3ff11b2c 100644 --- a/src/controls/dev/NavigationView/NavigationView_themeresources.xaml +++ b/src/controls/dev/NavigationView/NavigationView_themeresources.xaml @@ -42,6 +42,7 @@ + @@ -107,6 +108,7 @@ + @@ -172,6 +174,7 @@ + @@ -607,7 +610,7 @@ - + @@ -708,7 +711,7 @@ - + @@ -883,7 +886,7 @@ - + @@ -1054,7 +1057,7 @@ - + diff --git a/src/controls/dev/NavigationView/TestUI/Hierarchical/HierarchicalNavigationViewMarkup.xaml b/src/controls/dev/NavigationView/TestUI/Hierarchical/HierarchicalNavigationViewMarkup.xaml index 0fbdd7a87b..735c16f772 100644 --- a/src/controls/dev/NavigationView/TestUI/Hierarchical/HierarchicalNavigationViewMarkup.xaml +++ b/src/controls/dev/NavigationView/TestUI/Hierarchical/HierarchicalNavigationViewMarkup.xaml @@ -21,7 +21,10 @@ PaneClosed="NavView_PaneClosed" PaneOpened="NavView_PaneOpened"> - + + + + diff --git a/src/controls/dev/NumberBox/InteractionTests/NumberBoxTests.cs b/src/controls/dev/NumberBox/InteractionTests/NumberBoxTests.cs index fcb933fd64..b7a63cfa89 100644 --- a/src/controls/dev/NumberBox/InteractionTests/NumberBoxTests.cs +++ b/src/controls/dev/NumberBox/InteractionTests/NumberBoxTests.cs @@ -43,7 +43,7 @@ public void UpDownTest() using (var setup = new TestSetupHelper("NumberBox Tests")) { RangeValueSpinner numBox = FindElement.ByName("TestNumberBox"); - numBox.SetValue(0); + numBox.SetValue(1); ComboBox spinModeComboBox = FindElement.ByName("SpinModeComboBox"); spinModeComboBox.SelectItemByName("Inline"); @@ -52,6 +52,23 @@ public void UpDownTest() Button upButton = FindButton(numBox, "Increase"); Button downButton = FindButton(numBox, "Decrease"); + Log.Comment("Change SmallChange value to 0.01"); + RangeValueSpinner smallChangeNumBox = FindElement.ByName("SmallChangeNumberBox"); + EnterText(smallChangeNumBox, "0.01"); + Wait.ForIdle(); + + Log.Comment("Verify that up button increases value by 0.01"); + upButton.InvokeAndWait(); + Edit edit = FindTextBox(numBox); + Verify.AreEqual("1.01", edit.GetText()); + + Log.Comment("Change Value to 0"); + numBox.SetValue(0); + + Log.Comment("Change SmallChange value to 1"); + EnterText(smallChangeNumBox, "1"); + Wait.ForIdle(); + Log.Comment("Verify that up button increases value by 1"); upButton.InvokeAndWait(); Verify.AreEqual(1, numBox.Value); @@ -61,7 +78,6 @@ public void UpDownTest() Verify.AreEqual(0, numBox.Value); Log.Comment("Change SmallChange value to 5"); - RangeValueSpinner smallChangeNumBox = FindElement.ByName("SmallChangeNumberBox"); smallChangeNumBox.SetValue(5); Wait.ForIdle(); @@ -189,6 +205,30 @@ public void ValueTextTest() Log.Comment("Verify that even if the value doesn't change, the textbox text is updated"); EnterText(numBox, " 15 "); Verify.AreEqual("15", edit.GetText()); + + Log.Comment("Verify that there is no rounding error for value 25.8"); + EnterText(numBox, "25.8"); + Verify.AreEqual("25.8", edit.GetText()); + + Log.Comment("Verify that there is no rounding error for value 0.0001"); + EnterText(numBox, "0.0001"); + Verify.AreEqual("0.0001", edit.GetText()); + + Log.Comment("Verify that there is no rounding error for value 294.1"); + EnterText(numBox, "294.1"); + Verify.AreEqual("294.1", edit.GetText()); + + Log.Comment("Verify that there is no rounding error for value 2924.8"); + EnterText(numBox, "2924.8"); + Verify.AreEqual("2924.8", edit.GetText()); + + Log.Comment("Verify that there is no rounding error for value 1.01"); + EnterText(numBox, "1.01"); + Verify.AreEqual("1.01", edit.GetText()); + + Log.Comment("Verify that there is no rounding error for value 0.03"); + EnterText(numBox, "0.03"); + Verify.AreEqual("0.03", edit.GetText()); } } diff --git a/src/controls/dev/NumberBox/NumberBox.cpp b/src/controls/dev/NumberBox/NumberBox.cpp index f7402739da..0dd65f5216 100644 --- a/src/controls/dev/NumberBox/NumberBox.cpp +++ b/src/controls/dev/NumberBox/NumberBox.cpp @@ -214,10 +214,7 @@ void NumberBox::OnApplyTemplate() m_isEnabledChangedRevoker = IsEnabledChanged(winrt::auto_revoke, { this, &NumberBox::OnIsEnabledChanged }); - // printf() defaults to 6 digits. 6 digits are sufficient for most - // users under most circumstances, while simultaneously avoiding most - // rounding errors for instance during double/float conversion. - m_displayRounder.Increment(1e-6); + m_displayRounder.SignificantDigits(10); UpdateSpinButtonPlacement(); UpdateSpinButtonEnabled(); diff --git a/src/controls/dev/NumberBox/NumberBox.h b/src/controls/dev/NumberBox/NumberBox.h index c3c6f26331..34086e68af 100644 --- a/src/controls/dev/NumberBox/NumberBox.h +++ b/src/controls/dev/NumberBox/NumberBox.h @@ -101,7 +101,7 @@ class NumberBox : bool m_valueUpdating{ false }; bool m_textUpdating{ false }; - winrt::IncrementNumberRounder m_displayRounder{}; + winrt::SignificantDigitsNumberRounder m_displayRounder{}; tracker_ref m_textBox{ this }; tracker_ref m_headerPresenter{ this }; diff --git a/src/controls/dev/NumberBox/NumberBox.xaml b/src/controls/dev/NumberBox/NumberBox.xaml index 58ccc82220..c7e930c0b0 100644 --- a/src/controls/dev/NumberBox/NumberBox.xaml +++ b/src/controls/dev/NumberBox/NumberBox.xaml @@ -109,7 +109,7 @@ - + @@ -366,4 +366,4 @@ - \ No newline at end of file + diff --git a/src/controls/dev/PagerControl/PagerControl.cpp b/src/controls/dev/PagerControl/PagerControl.cpp index a13ff44bb6..5da4927088 100644 --- a/src/controls/dev/PagerControl/PagerControl.cpp +++ b/src/controls/dev/PagerControl/PagerControl.cpp @@ -136,7 +136,7 @@ void PagerControl::OnApplyTemplate() m_numberBox.set(numberBox); if (numberBox) { - numberBox.Value(SelectedPageIndex() + 1); + numberBox.Value(static_cast(SelectedPageIndex()) + 1); winrt::AutomationProperties::SetName(numberBox, ResourceAccessor::GetLocalizedStringResource(SR_PagerControlPageTextName)); m_numberBoxValueChangedRevoker = numberBox.ValueChanged(winrt::auto_revoke, { this,&PagerControl::NumberBoxValueChanged }); } @@ -335,7 +335,7 @@ void PagerControl::OnSelectedPageIndexChange(const int oldValue) } if (const auto numBox = m_numberBox.get()) { - numBox.Value(SelectedPageIndex() + 1); + numBox.Value(static_cast(SelectedPageIndex()) + 1); } UpdateOnEdgeButtonVisualStates(); diff --git a/src/controls/dev/PersonPicture/APITests/PersonPictureTests.cs b/src/controls/dev/PersonPicture/APITests/PersonPictureTests.cs index 45784b281a..a618b2cd09 100644 --- a/src/controls/dev/PersonPicture/APITests/PersonPictureTests.cs +++ b/src/controls/dev/PersonPicture/APITests/PersonPictureTests.cs @@ -161,7 +161,7 @@ public void VerifyVSMStatesForPhotosAndInitials() personPicture.IsGroup = false; personPicture.Initials = "JS"; Content.UpdateLayout(); - Verify.AreEqual(initialsTextBlock.FontFamily.Source, "Segoe UI"); + Verify.AreEqual(initialsTextBlock.FontFamily.Source, "Segoe UI Variable"); Verify.AreEqual(initialsTextBlock.Text, "JS"); personPicture.Initials = ""; diff --git a/src/controls/dev/PipsPager/InteractionTests/PipsPagerElements.cs b/src/controls/dev/PipsPager/InteractionTests/PipsPagerElements.cs index ece50308b0..090057f070 100644 --- a/src/controls/dev/PipsPager/InteractionTests/PipsPagerElements.cs +++ b/src/controls/dev/PipsPager/InteractionTests/PipsPagerElements.cs @@ -20,6 +20,7 @@ public class PipsPagerElements private ComboBox NumberOfPagesComboBox; private ComboBox MaxVisualIndicatorsComboBox; private ComboBox OrientationComboBox; + private ComboBox WrapModeComboBox; private CheckBox PreviousPageButtonIsVisibleCheckBox; private CheckBox PreviousPageButtonIsEnabledCheckBox; private CheckBox NextPageButtonIsVisibleCheckBox; @@ -87,6 +88,10 @@ public ComboBox GetOrientationComboBox() { return GetElement(ref OrientationComboBox, "TestPipsPagerOrientationComboBox"); } + public ComboBox GetWrapModeComboBox() + { + return GetElement(ref WrapModeComboBox, "TestPipsPagerWrapModeComboBox"); + } public TextBlock GetCurrentPageTextBlock() { return GetElement(ref CurrentPageTextBlock, "CurrentPageIndexTextBlock"); diff --git a/src/controls/dev/PipsPager/InteractionTests/PipsPagerTestBase.cs b/src/controls/dev/PipsPager/InteractionTests/PipsPagerTestBase.cs index 41cca9c4f7..48a6092e18 100644 --- a/src/controls/dev/PipsPager/InteractionTests/PipsPagerTestBase.cs +++ b/src/controls/dev/PipsPager/InteractionTests/PipsPagerTestBase.cs @@ -101,6 +101,11 @@ protected void SetOrientation(OrientationType orientation) { elements.GetOrientationComboBox().SelectItemByName($"{orientation}Orientation"); } + + protected void SetWrapMode(WrapMode wrapMode) + { + elements.GetWrapModeComboBox().SelectItemByName($"{wrapMode}"); + } protected void VerifyOrientationChanged(OrientationType orientation) { @@ -167,6 +172,11 @@ protected string GetSelectedNumberOfPages() protected int GetSelectedNumberOfPagesAsInt32() { + var selectedNumberOfPages = GetSelectedNumberOfPages(); + if (selectedNumberOfPages == "Infinite") + { + return -1; + } return Convert.ToInt32(GetSelectedNumberOfPages()); } protected void VerifyNumberOfPages(string numberOfPages) @@ -196,10 +206,17 @@ public enum ButtonVisibilityMode public enum NumberOfPagesOptions { Zero, + One, Five, Ten, Twenty, Infinite } + + public enum WrapMode + { + None, + Wrap + } } } diff --git a/src/controls/dev/PipsPager/InteractionTests/PipsPagerTests.cs b/src/controls/dev/PipsPager/InteractionTests/PipsPagerTests.cs index ae3c6c8a6f..5f6201ccd1 100644 --- a/src/controls/dev/PipsPager/InteractionTests/PipsPagerTests.cs +++ b/src/controls/dev/PipsPager/InteractionTests/PipsPagerTests.cs @@ -385,5 +385,80 @@ public void PipsPagerRTLDoesNotCrash() InputHelper.LeftClick(elements.GetNextPageButton()); } } + + [TestMethod] + [TestProperty("TestSuite", "F")] + public void PipsPagerWrapModeNavigation() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + ChangeNumberOfPages(NumberOfPagesOptions.Twenty); + VerifyNumberOfPages("20"); + + SetWrapMode(WrapMode.Wrap); + + VerifySelectedPageIndex(0); + + InputHelper.LeftClick(elements.GetPreviousPageButton()); + + VerifySelectedPageIndex(19); + + InputHelper.LeftClick(elements.GetNextPageButton()); + + VerifySelectedPageIndex(0); + } + } + + [TestMethod] + [TestProperty("TestSuite", "F")] + public void PipsPagerWrapModeNavigationInfinitePages() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + SetWrapMode(WrapMode.Wrap); + + ChangeNumberOfPages(NumberOfPagesOptions.Infinite); + VerifyNumberOfPages("Infinite"); + + InputHelper.LeftClick(elements.GetNextPageButton()); + InputHelper.LeftClick(elements.GetPreviousPageButton()); + + VerifySelectedPageIndex(0); + + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.Collapsed); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.Visible); + } + } + + [TestMethod] + [TestProperty("TestSuite", "F")] + public void PipsPagerWrapModeNavigationButtonsHiddenInOnePageScenario() + { + using (var setup = new TestSetupHelper("PipsPager Tests")) + { + elements = new PipsPagerElements(); + + SetWrapMode(WrapMode.Wrap); + + ChangeNumberOfPages(NumberOfPagesOptions.One); + VerifyNumberOfPages("1"); + + SetPreviousPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + SetNextPageButtonVisibilityMode(ButtonVisibilityMode.Visible); + + VerifySelectedPageIndex(0); + + VerifyPageButtonWithVisibilityModeSet(ButtonType.Previous, ButtonVisibilityMode.Collapsed); + VerifyPageButtonWithVisibilityModeSet(ButtonType.Next, ButtonVisibilityMode.Collapsed); + } + } } } diff --git a/src/controls/dev/PipsPager/PipsPager.cpp b/src/controls/dev/PipsPager/PipsPager.cpp index 5a9d4d1a41..781133b07a 100644 --- a/src/controls/dev/PipsPager/PipsPager.cpp +++ b/src/controls/dev/PipsPager/PipsPager.cpp @@ -10,6 +10,7 @@ #include "PipsPagerTemplateSettings.h" #include "PipsPagerSelectedIndexChangedEventArgs.h" #include "PipsPagerAutomationPeer.h" +#include "StackLayout.h" typedef winrt::PipsPagerButtonVisibility ButtonVisibility; @@ -67,6 +68,11 @@ PipsPager::PipsPager() SetDefaultStyleKey(this); } +PipsPager::~PipsPager() +{ + RestoreLayoutVirtualization(); +} + void PipsPager::OnApplyTemplate() { winrt::AutomationProperties::SetName(*this, ResourceAccessor::GetLocalizedStringResource(SR_PipsPagerNameText)); @@ -96,6 +102,8 @@ void PipsPager::OnApplyTemplate() m_pipsPagerElementPreparedRevoker.revoke(); m_pipsAreaGettingFocusRevoker.revoke(); m_pipsAreaBringIntoViewRequestedRevoker.revoke(); + m_itemsRepeaterStackLayoutChangedRevoker.revoke(); + RestoreLayoutVirtualization(); [this](const winrt::ItemsRepeater repeater) { m_pipsPagerRepeater.set(repeater); @@ -104,6 +112,12 @@ void PipsPager::OnApplyTemplate() m_pipsPagerElementPreparedRevoker = repeater.ElementPrepared(winrt::auto_revoke, { this, &PipsPager::OnElementPrepared }); m_pipsAreaGettingFocusRevoker = repeater.GettingFocus(winrt::auto_revoke, { this, &PipsPager::OnPipsAreaGettingFocus }); m_pipsAreaBringIntoViewRequestedRevoker = repeater.BringIntoViewRequested(winrt::auto_revoke, { this, &PipsPager::OnPipsAreaBringIntoViewRequested }); + + m_itemsRepeaterStackLayoutChangedRevoker = RegisterPropertyChanged(repeater, + winrt::ItemsRepeater::LayoutProperty(), + { this, &PipsPager::OnItemsRepeaterLayoutChanged }); + + UpdateLayoutVirtualization(); } }(GetTemplateChildT(c_pipsPagerRepeaterName, *this)); @@ -189,17 +203,18 @@ void PipsPager::UpdateIndividualNavigationButtonVisualState( const wstring_view& enabledStateName, const wstring_view& disabledStateName) { - const auto ifGenerallyVisible = !hiddenOnEdgeCondition && NumberOfPages() != 0 && MaxVisiblePips() > 0; + const auto isGenerallyVisible = (!hiddenOnEdgeCondition || (IsWrapEnabled() && NumberOfPages() > 1)) && + NumberOfPages() != 0 && MaxVisiblePips() > 0; if (visibility != ButtonVisibility::Collapsed) { - if ((visibility == ButtonVisibility::Visible || m_isPointerOver || m_isFocused) && ifGenerallyVisible) + if ((visibility == ButtonVisibility::Visible || m_isPointerOver || m_isFocused) && isGenerallyVisible) { winrt::VisualStateManager::GoToState(*this, visibleStateName, false); winrt::VisualStateManager::GoToState(*this, enabledStateName, false); } else { - if (!ifGenerallyVisible) + if (!isGenerallyVisible) { winrt::VisualStateManager::GoToState(*this, disabledStateName, false); } @@ -216,13 +231,13 @@ void PipsPager::UpdateNavigationButtonVisualStates() { const int selectedPageIndex = SelectedPageIndex(); const int numberOfPages = NumberOfPages(); - auto const ifPreviousButtonHiddenOnEdge = selectedPageIndex == 0; - UpdateIndividualNavigationButtonVisualState(ifPreviousButtonHiddenOnEdge, PreviousButtonVisibility(), + auto const isPreviousButtonHiddenOnEdge = selectedPageIndex == 0; + UpdateIndividualNavigationButtonVisualState(isPreviousButtonHiddenOnEdge, PreviousButtonVisibility(), c_previousPageButtonVisibleVisualState, c_previousPageButtonHiddenVisualState, c_previousPageButtonEnabledVisualState, c_previousPageButtonDisabledVisualState); - auto const ifNextButtonHiddenOnEdge = selectedPageIndex == numberOfPages - 1; - UpdateIndividualNavigationButtonVisualState(ifNextButtonHiddenOnEdge, NextButtonVisibility(), + auto const isNextButtonHiddenOnEdge = selectedPageIndex == numberOfPages - 1; + UpdateIndividualNavigationButtonVisualState(isNextButtonHiddenOnEdge, NextButtonVisibility(), c_nextPageButtonVisibleVisualState, c_nextPageButtonHiddenVisualState, c_nextPageButtonEnabledVisualState, c_nextPageButtonDisabledVisualState); } @@ -276,7 +291,7 @@ double PipsPager::CalculateScrollViewerSize(const double defaultPipSize, const d { numberOfPagesToDisplay = maxVisualIndicators; } - return defaultPipSize * (numberOfPagesToDisplay - 1) + selectedPipSize; + return defaultPipSize * (static_cast(numberOfPagesToDisplay) - 1) + selectedPipSize; } void PipsPager::SetScrollViewerMaxSize() { @@ -436,6 +451,12 @@ void PipsPager::OnSelectedPageIndexChanged(const int oldValue) } } +void PipsPager::OnWrapModeChanged() +{ + UpdateLayoutVirtualization(); + UpdateNavigationButtonVisualStates(); +} + void PipsPager::OnOrientationChanged() { if (Orientation() == winrt::Orientation::Horizontal) @@ -505,14 +526,47 @@ void PipsPager::OnNavigationButtonVisibilityChanged(const ButtonVisibility visib void PipsPager::OnPreviousButtonClicked(const IInspectable& sender, const winrt::RoutedEventArgs& e) { - // In this method, SelectedPageIndex is always greater than 0. - SelectedPageIndex(SelectedPageIndex() - 1); + // Navigation buttons are hidden in this scenario. + // However in case someone re-templates the control and + // leaves the buttons active, we want to make sure + // we don't navigate to a non-existent index. + if (NumberOfPages() == 0 || NumberOfPages() == 1) + { + return; + } + + auto newPageIndex = std::max(0, SelectedPageIndex() - 1); + + if (IsWrapEnabled() && NumberOfPages() > -1 && + SelectedPageIndex() == 0) + { + newPageIndex = NumberOfPages() - 1; + } + + SelectedPageIndex(newPageIndex); } void PipsPager::OnNextButtonClicked(const IInspectable& sender, const winrt::RoutedEventArgs& e) { - // In this method, SelectedPageIndex is always less than maximum. - SelectedPageIndex(SelectedPageIndex() + 1); + // Navigation buttons are hidden in this scenario. + // However in case someone re-templates the control and + // leaves the buttons active, we want to make sure + // we don't navigate to a non-existent index. + if (NumberOfPages() == 0 || NumberOfPages() == 1) + { + return; + } + + auto newPageIndex = NumberOfPages() > -1 ? + std::min(SelectedPageIndex() + 1, NumberOfPages() - 1) : SelectedPageIndex() + 1; + + if (IsWrapEnabled() && + SelectedPageIndex() == (NumberOfPages() - 1)) + { + newPageIndex = 0; + } + + SelectedPageIndex(newPageIndex); } @@ -636,6 +690,44 @@ void PipsPager::OnScrollViewerBringIntoViewRequested(const IInspectable& sender, args.Handled(true); } +void PipsPager::OnItemsRepeaterLayoutChanged(const winrt::DependencyObject& /*sender*/, const winrt::DependencyProperty& args) +{ + RestoreLayoutVirtualization(); + UpdateLayoutVirtualization(); +} + +void PipsPager::RestoreLayoutVirtualization() +{ + // Make sure to reset the layout virtualization settings on old layout + if (auto stackLayout = m_itemsRepeaterStackLayout.get()) + { + auto stackLayoutImpl = winrt::get_self(stackLayout); + stackLayoutImpl->IsVirtualizationEnabled(m_cachedIsVirtualizationEnabledFlag); + } + m_itemsRepeaterStackLayout = nullptr; + m_cachedIsVirtualizationEnabledFlag = true; +} + +void PipsPager::UpdateLayoutVirtualization() +{ + if (auto repeater = m_pipsPagerRepeater.get()) + { + if (auto stackLayout = repeater.Layout().try_as()) + { + // Turn off virtualization when wrap around is enabled + // in order to avoid a bug where the pips disappear + // when navigating to the last page from the first page + auto stackLayoutImpl = winrt::get_self(stackLayout); + if (m_itemsRepeaterStackLayout.get() == nullptr) + { + m_cachedIsVirtualizationEnabledFlag = stackLayoutImpl->IsVirtualizationEnabled(); + m_itemsRepeaterStackLayout = winrt::make_weak(stackLayout); + } + stackLayoutImpl->IsVirtualizationEnabled(!IsWrapEnabled()); + } + } +} + void PipsPager::OnPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args) { winrt::IDependencyProperty property = args.Property(); @@ -652,6 +744,10 @@ void PipsPager::OnPropertyChanged(const winrt::DependencyPropertyChangedEventArg else if (property == MaxVisiblePipsProperty()) { OnMaxVisiblePipsChanged(); } + else if (property == WrapModeProperty()) + { + OnWrapModeChanged(); + } else if (property == PreviousButtonVisibilityProperty()) { OnNavigationButtonVisibilityChanged(PreviousButtonVisibility(), c_previousPageButtonCollapsedVisualState, c_previousPageButtonDisabledVisualState); diff --git a/src/controls/dev/PipsPager/PipsPager.h b/src/controls/dev/PipsPager/PipsPager.h index daeeba208c..c23c5754f1 100644 --- a/src/controls/dev/PipsPager/PipsPager.h +++ b/src/controls/dev/PipsPager/PipsPager.h @@ -20,6 +20,7 @@ class PipsPager : { public: PipsPager(); + ~PipsPager(); /* IFrameworkElement */ void OnApplyTemplate(); @@ -46,6 +47,7 @@ class PipsPager : const wstring_view& collapsedStateName, const wstring_view& disabledStateName); void OnOrientationChanged(); + void OnWrapModeChanged(); winrt::UIElement GetSelectedItem(); @@ -70,6 +72,9 @@ class PipsPager : void UpdateSelectedPip(const int index); void UpdatePipOrientation(const winrt::Control& pip); void ApplyStyleToPipAndUpdateOrientation(const winrt::FrameworkElement& pip, const winrt::Style& style); + void RestoreLayoutVirtualization(); + void UpdateLayoutVirtualization(); + bool IsWrapEnabled(){ return WrapMode() == winrt::PipsPagerWrapMode::Wrap; }; /* Eventing */ void RaiseSelectedIndexChanged(); @@ -80,6 +85,9 @@ class PipsPager : void OnPipsAreaBringIntoViewRequested(const IInspectable& sender, const winrt::BringIntoViewRequestedEventArgs& args); void OnScrollViewerBringIntoViewRequested(const IInspectable& sender, const winrt::BringIntoViewRequestedEventArgs& args); + /* Event listeners */ + void OnItemsRepeaterLayoutChanged(const winrt::DependencyObject& /*sender*/, const winrt::DependencyProperty& args); + /* Pips Logic */ void UpdatePipsItems(const int numberOfPages, int maxVisualIndicators); void OnElementPrepared(winrt::ItemsRepeater sender, winrt::ItemsRepeaterElementPreparedEventArgs args); @@ -98,6 +106,7 @@ class PipsPager : winrt::UIElement::GettingFocus_revoker m_pipsAreaGettingFocusRevoker{}; winrt::ItemsRepeater::BringIntoViewRequested_revoker m_pipsAreaBringIntoViewRequestedRevoker{}; winrt::FxScrollViewer::BringIntoViewRequested_revoker m_scrollViewerBringIntoViewRequestedRevoker{}; + PropertyChanged_revoker m_itemsRepeaterStackLayoutChangedRevoker{}; /* Items */ winrt::IObservableVector m_pipsPagerItems{}; @@ -107,4 +116,6 @@ class PipsPager : int m_lastSelectedPageIndex{ -1 }; bool m_isPointerOver{ false }; bool m_isFocused{ false }; + winrt::weak_ref m_itemsRepeaterStackLayout{ nullptr }; + bool m_cachedIsVirtualizationEnabledFlag{ true }; }; diff --git a/src/controls/dev/PipsPager/PipsPager.idl b/src/controls/dev/PipsPager/PipsPager.idl index 4816235aa8..fa3192433f 100644 --- a/src/controls/dev/PipsPager/PipsPager.idl +++ b/src/controls/dev/PipsPager/PipsPager.idl @@ -10,6 +10,14 @@ enum PipsPagerButtonVisibility Collapsed }; +[MUX_PUBLIC_V7] +[webhosthidden] +enum PipsPagerWrapMode +{ + None, + Wrap +}; + [MUX_PUBLIC] [default_interface] [webhosthidden] @@ -71,6 +79,13 @@ unsealed runtimeclass PipsPager : Microsoft.UI.Xaml.Controls.Control static Microsoft.UI.Xaml.DependencyProperty NextButtonStyleProperty{ get; }; static Microsoft.UI.Xaml.DependencyProperty SelectedPipStyleProperty{ get; }; static Microsoft.UI.Xaml.DependencyProperty NormalPipStyleProperty{ get; }; + + [MUX_PUBLIC_V7] + { + [MUX_DEFAULT_VALUE("winrt::PipsPagerWrapMode::None")] + PipsPagerWrapMode WrapMode; + static Microsoft.UI.Xaml.DependencyProperty WrapModeProperty{ get; }; + } }; } diff --git a/src/controls/dev/PipsPager/TestUI/PipsPagerPage.xaml b/src/controls/dev/PipsPager/TestUI/PipsPagerPage.xaml index c50c291ec8..5fc02959f1 100644 --- a/src/controls/dev/PipsPager/TestUI/PipsPagerPage.xaml +++ b/src/controls/dev/PipsPager/TestUI/PipsPagerPage.xaml @@ -12,7 +12,7 @@ - + @@ -39,8 +39,9 @@ VisibleOnPointerOver Collapsed - + 0 Pages + 1 Page 5 Pages 10 Pages 20 Pages @@ -56,6 +57,10 @@ Vertical Horizontal + + None + Wrap + @@ -81,6 +86,10 @@ + + + @@ -40,15 +40,15 @@ - + ItemSpacing - + MinColumnSpacing - + LineAlignment (Start/Center/End/SpaceEvenly/SpaceAround/SpaceBetween) - + Scroll Orientation @@ -83,7 +83,7 @@ - + @@ -105,5 +105,5 @@ - + diff --git a/src/controls/dev/Repeater/TestUI/RepeaterTestUIPage.xaml.cs b/src/controls/dev/Repeater/TestUI/RepeaterTestUIPage.xaml.cs index 9db1e31e42..74a2257367 100644 --- a/src/controls/dev/Repeater/TestUI/RepeaterTestUIPage.xaml.cs +++ b/src/controls/dev/Repeater/TestUI/RepeaterTestUIPage.xaml.cs @@ -63,6 +63,10 @@ public RepeaterTestUIPage() Frame.NavigateWithoutAnimation(typeof(SortingAndFilteringPage)); }; + variableSizedItemsDemo.Click += delegate { + Frame.NavigateWithoutAnimation(typeof(VariableSizedItemsPage)); + }; + animationsDemo.Click += delegate { Frame.NavigateWithoutAnimation(typeof(AnimationsDemoPage)); diff --git a/src/controls/dev/Repeater/TestUI/Repeater_TestUI.projitems b/src/controls/dev/Repeater/TestUI/Repeater_TestUI.projitems index 1d9b0ba19f..460919a505 100644 --- a/src/controls/dev/Repeater/TestUI/Repeater_TestUI.projitems +++ b/src/controls/dev/Repeater/TestUI/Repeater_TestUI.projitems @@ -19,6 +19,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -128,6 +132,9 @@ SortingAndFilteringPage.xaml + + VariableSizedItemsPage.xaml + DisposableUserControl.xaml diff --git a/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml b/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml index bb845f7707..8116ab2a1c 100644 --- a/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml +++ b/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml @@ -40,7 +40,7 @@ - + diff --git a/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml.cs b/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml.cs index 0301167786..64b26d6a94 100644 --- a/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml.cs +++ b/src/controls/dev/Repeater/TestUI/Samples/BasicDemo.xaml.cs @@ -18,7 +18,7 @@ public BasicDemo() this.InitializeComponent(); repeater.ItemTemplate = elementFactory; var stack = repeater.Layout as StackLayout; - int numItems = (stack != null && stack.DisableVirtualization) ? 10 : 10000; + int numItems = (stack != null && !stack.IsVirtualizationEnabled) ? 10 : 10000; repeater.ItemsSource = Enumerable.Range(0, numItems).Select(x => x.ToString()); } diff --git a/src/controls/dev/Repeater/TestUI/Samples/ItemsSourceSamples/VariableSizedItemsPage.xaml b/src/controls/dev/Repeater/TestUI/Samples/ItemsSourceSamples/VariableSizedItemsPage.xaml new file mode 100644 index 0000000000..327ce1cb80 --- /dev/null +++ b/src/controls/dev/Repeater/TestUI/Samples/ItemsSourceSamples/VariableSizedItemsPage.xaml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + Click="GetRepeaterActualHeightButtonClick" Margin="2">Get actual ItemsRepeater height + + + + + + + + Click="GetUniformGridLayoutMinColumnSpacingButtonClick" Margin="2">Get + Click="SetUniformGridLayoutMinColumnSpacingButtonClick" Margin="2">Set + Click="GetUniformGridLayoutMinRowSpacingButtonClick" Margin="2">Get + Click="SetUniformGridLayoutMinRowSpacingButtonClick" Margin="2">Set + Click="GetUniformGridLayoutMinItemWidthButtonClick" Margin="2">Get + Click="SetUniformGridLayoutMinItemWidthButtonClick" Margin="2">Set + Click="GetUniformGridLayoutMinItemHeightButtonClick" Margin="2">Get + Click="SetUniformGridLayoutMinItemHeightButtonClick" Margin="2">Set - + None Fill Uniform @@ -77,7 +85,8 @@ - + Start Center End @@ -89,7 +98,8 @@ - + Vertical Horizontal @@ -99,41 +109,42 @@ + Click="GetScrollViewerMaxWidthButtonClick" Margin="2">Get + Click="SetScrollViewerMaxWidthButtonClick" Margin="2">Set + Click="GetScrollViewerMaxHeightButtonClick" Margin="2">Get + Click="SetScrollViewerMaxHeightButtonClick" Margin="2">Set + Click="GetScrollViewerHorizontalOffsetButtonClick" Margin="2">Get + Click="SetScrollViewerHorizontalOffsetButtonClick" Margin="2">Set + Click="GetScrollViewerVerticalOffsetButtonClick" Margin="2">Get + Click="SetScrollViewerVerticalOffsetButtonClick" Margin="2">Set - + Disabled Auto Hidden @@ -149,7 +160,7 @@ IsVerticalScrollChainingEnabled="False" AutomationProperties.Name="RepeaterScrollViewer" MaxHeight="500"> - @@ -162,19 +173,20 @@ VerticalAlignment="Top" Opacity="0.2" Source="/Images/recipe1.png" /> - - - + - - + + - + - - + + diff --git a/src/controls/dev/Repeater/UniformGridLayout.cpp b/src/controls/dev/Repeater/UniformGridLayout.cpp index c5c838eeaa..a74761f760 100644 --- a/src/controls/dev/Repeater/UniformGridLayout.cpp +++ b/src/controls/dev/Repeater/UniformGridLayout.cpp @@ -71,7 +71,7 @@ winrt::Size UniformGridLayout::MeasureOverride( LineSpacing(), m_maximumRowsOrColumns /* maxItemsPerLine */, OrientationBasedMeasures::GetScrollOrientation(), - false /* disableVirtualization */, + true /* isVirtualizationEnabled */, LayoutId()); return { desiredSize.Width, desiredSize.Height }; @@ -139,7 +139,7 @@ winrt::FlowLayoutAnchorInfo UniformGridLayout::Algorithm_GetAnchorForRealization const auto lastExtent = gridState->FlowAlgorithm().LastExtent(); const int itemsPerLine = GetItemsPerLine(availableSize, context); const double majorSize = (itemsCount / itemsPerLine) * (double)(GetMajorSizeWithSpacing(context)); - const double realizationWindowStartWithinExtent = (double)(MajorStart(realizationRect) - MajorStart(lastExtent)); + const double realizationWindowStartWithinExtent = static_cast(MajorStart(realizationRect)) - static_cast(MajorStart(lastExtent)); if ((realizationWindowStartWithinExtent + MajorSize(realizationRect)) >= 0 && realizationWindowStartWithinExtent <= majorSize) { const double offset = std::max(0.0f, MajorStart(realizationRect) - MajorStart(lastExtent)); diff --git a/src/controls/dev/Repeater/UniformGridLayoutState.cpp b/src/controls/dev/Repeater/UniformGridLayoutState.cpp index 11220ab63b..7e8ac4943b 100644 --- a/src/controls/dev/Repeater/UniformGridLayoutState.cpp +++ b/src/controls/dev/Repeater/UniformGridLayoutState.cpp @@ -30,8 +30,8 @@ void UniformGridLayoutState::EnsureElementSize( const double layoutItemHeight, const winrt::UniformGridLayoutItemsStretch& stretch, const winrt::Orientation& orientation, - double minRowSpacing, - double minColumnSpacing, + const double minRowSpacing, + const double minColumnSpacing, unsigned int maxItemsPerLine) { if (maxItemsPerLine == 0) @@ -72,14 +72,15 @@ void UniformGridLayoutState::InvalidateElementSize() m_isEffectiveSizeValid = false; } -winrt::Size UniformGridLayoutState::CalculateAvailableSize(const winrt::Size availableSize, +winrt::Size UniformGridLayoutState::CalculateAvailableSize( + const winrt::Size availableSize, const winrt::Orientation orientation, const winrt::UniformGridLayoutItemsStretch& stretch, const unsigned int maxItemsPerLine, const double itemWidth, const double itemHeight, - double minRowSpacing, - double minColumnSpacing) + const double minRowSpacing, + const double minColumnSpacing) const { // Since some controls might have certain requirements when rendering (e.g. maintaining an aspect ratio), // we will let elements know the actual size they will get within our layout and let them measure based on that assumption. @@ -87,49 +88,53 @@ winrt::Size UniformGridLayoutState::CalculateAvailableSize(const winrt::Size ava // for the column width (or row height) being provided. if (orientation == winrt::Orientation::Horizontal) { - if (!isnan(itemWidth)) + if (!isnan(itemWidth) && std::isfinite(availableSize.Width)) { double allowedColumnWidth = itemWidth; if (stretch != winrt::UniformGridLayoutItemsStretch::None) { allowedColumnWidth += CalculateExtraPixelsInLine(maxItemsPerLine, availableSize.Width, itemWidth, minColumnSpacing); } - return winrt::Size{ (float)allowedColumnWidth, availableSize.Height}; + return winrt::Size{ static_cast(allowedColumnWidth), availableSize.Height }; } } - else { - if (!isnan(itemHeight)) + else + { + if (!isnan(itemHeight) && std::isfinite(availableSize.Height)) { double allowedRowHeight = itemHeight; if (stretch != winrt::UniformGridLayoutItemsStretch::None) { allowedRowHeight += CalculateExtraPixelsInLine(maxItemsPerLine, availableSize.Height, itemHeight, minRowSpacing); } - return winrt::Size{availableSize.Width, (float)itemHeight}; + return winrt::Size{ availableSize.Width, static_cast(allowedRowHeight) }; } } return availableSize; } -double UniformGridLayoutState::CalculateExtraPixelsInLine(unsigned int maxItemsPerLine, +double UniformGridLayoutState::CalculateExtraPixelsInLine( + const unsigned int maxItemsPerLine, const float availableSizeMinor, const double itemSizeMinor, - const double minorItemSpacing) + const double minorItemSpacing) const { - const auto numItemsPerColumn = [](unsigned int maxItemsPerLine, const float availableSizeMinor, const double itemSizeMinor, const double minorItemSpacing){ + const auto numItemsPerColumn = [](const unsigned int maxItemsPerLine, const float availableSizeMinor, const double itemSizeMinor, const double minorItemSpacing) + { const unsigned int numItemsBasedOnSize = static_cast(std::max(1.0, availableSizeMinor / (itemSizeMinor + minorItemSpacing))); - if (numItemsBasedOnSize == 0) { + if (numItemsBasedOnSize == 0) + { return maxItemsPerLine; } - else { - return std::min( - maxItemsPerLine, - numItemsBasedOnSize); + else + { + return std::min(maxItemsPerLine, numItemsBasedOnSize); } }(maxItemsPerLine,availableSizeMinor,itemSizeMinor,minorItemSpacing); + const auto usedSpace = (numItemsPerColumn * (itemSizeMinor + minorItemSpacing)) - minorItemSpacing; - const auto remainingSpace = ((int)(availableSizeMinor - usedSpace)); - return remainingSpace / ((int)numItemsPerColumn); + const auto remainingSpace = static_cast(availableSizeMinor - usedSpace); + return remainingSpace / static_cast(numItemsPerColumn); } void UniformGridLayoutState::SetSize( @@ -139,8 +144,8 @@ void UniformGridLayoutState::SetSize( const winrt::Size availableSize, const winrt::UniformGridLayoutItemsStretch& stretch, const winrt::Orientation& orientation, - double minRowSpacing, - double minColumnSpacing, + const double minRowSpacing, + const double minColumnSpacing, unsigned int maxItemsPerLine) { if (maxItemsPerLine == 0) @@ -153,7 +158,6 @@ void UniformGridLayoutState::SetSize( const auto availableSizeMinor = orientation == winrt::Orientation::Horizontal ? availableSize.Width : availableSize.Height; const auto minorItemSpacing = orientation == winrt::Orientation::Vertical ? minRowSpacing : minColumnSpacing; - const auto itemSizeMinor = orientation == winrt::Orientation::Horizontal ? m_effectiveItemWidth : m_effectiveItemHeight; double extraMinorPixelsForEachItem = 0.0; @@ -177,6 +181,7 @@ void UniformGridLayoutState::SetSize( { const auto itemSizeMajor = orientation == winrt::Orientation::Horizontal ? m_effectiveItemHeight : m_effectiveItemWidth; const auto extraMajorPixelsForEachItem = itemSizeMajor * (extraMinorPixelsForEachItem / itemSizeMinor); + if (orientation == winrt::Orientation::Horizontal) { m_effectiveItemWidth += extraMinorPixelsForEachItem; diff --git a/src/controls/dev/Repeater/UniformGridLayoutState.h b/src/controls/dev/Repeater/UniformGridLayoutState.h index 9259275c87..a0013d992b 100644 --- a/src/controls/dev/Repeater/UniformGridLayoutState.h +++ b/src/controls/dev/Repeater/UniformGridLayoutState.h @@ -4,7 +4,6 @@ #pragma once #include "ElementManager.h" - #include "UniformGridLayoutState.g.h" #include "FlowLayoutAlgorithm.h" @@ -18,8 +17,8 @@ class UniformGridLayoutState : void UninitializeForContext(const winrt::VirtualizingLayoutContext& context); ::FlowLayoutAlgorithm& FlowAlgorithm() { return m_flowAlgorithm; } - double EffectiveItemWidth() { return m_effectiveItemWidth; } - double EffectiveItemHeight() { return m_effectiveItemHeight; } + double EffectiveItemWidth() const { return m_effectiveItemWidth; } + double EffectiveItemHeight() const { return m_effectiveItemHeight; } void EnsureElementSize( const winrt::Size availableSize, @@ -28,31 +27,32 @@ class UniformGridLayoutState : const double itemHeight, const winrt::UniformGridLayoutItemsStretch& stretch, const winrt::Orientation& orientation, - double minRowSpacing, - double minColumnSpacing, + const double minRowSpacing, + const double minColumnSpacing, unsigned int maxItemsPerLine); void InvalidateElementSize(); private: ::FlowLayoutAlgorithm m_flowAlgorithm{ this }; - bool m_isEffectiveSizeValid = false; + bool m_isEffectiveSizeValid{ false }; double m_effectiveItemWidth{ 0.0 }; double m_effectiveItemHeight{ 0.0 }; - winrt::Size CalculateAvailableSize(const winrt::Size availableSize, + winrt::Size CalculateAvailableSize( + const winrt::Size availableSize, const winrt::Orientation orientation, const winrt::UniformGridLayoutItemsStretch& stretch, const unsigned int maxItemsPerLine, const double itemWidth, const double itemHeight, - double minRowSpacing, - double minColumnSpacing); + const double minRowSpacing, + const double minColumnSpacing) const; - double CalculateExtraPixelsInLine(unsigned int maxItemsPerLine, + double CalculateExtraPixelsInLine( + const unsigned int maxItemsPerLine, const float availableSizeMinor, const double itemSizeMinor, - const double minorItemSpacing); - + const double minorItemSpacing) const; void SetSize(const winrt::Size& desiredItemSize, const double itemWidth, @@ -60,7 +60,7 @@ class UniformGridLayoutState : const winrt::Size availableSize, const winrt::UniformGridLayoutItemsStretch& stretch, const winrt::Orientation& orientation, - double minRowSpacing, - double minColumnSpacing, + const double minRowSpacing, + const double minColumnSpacing, unsigned int maxItemsPerLine); }; diff --git a/src/controls/dev/Repeater/ViewManager.cpp b/src/controls/dev/Repeater/ViewManager.cpp index de862b30da..7f437dfd34 100644 --- a/src/controls/dev/Repeater/ViewManager.cpp +++ b/src/controls/dev/Repeater/ViewManager.cpp @@ -7,10 +7,6 @@ #include "ViewManager.h" #include "ItemsRepeater.h" #include "RepeaterTestHooks.h" -#include - -// Bug 50344748: [1.5 Servicing][WASDK] 1-up viewer opens behind Collections (looks like nothing's happened, but the viewer is actually hidden behind the Collections window) -#define WINAPPSDK_CHANGEID_50344748 50344748 ViewManager::ViewManager(ItemsRepeater* owner) : m_owner(owner), @@ -226,15 +222,8 @@ void ViewManager::MoveFocusFromClearedIndex(int clearedIndex) // If the last focused element has focus, use its focus state, if not use programmatic. focusState = focusState == winrt::FocusState::Unfocused ? winrt::FocusState::Programmatic : focusState; - if (WinAppSdk::Containment::IsChangeEnabled()) - { - // Since this focus change is due to the focused element getting recycled, don't activate the window. - focusCandidate.as().FocusNoActivate(focusState); - } - else - { - focusCandidate.Focus(focusState); - } + // Since this focus change is due to the focused element getting recycled, don't activate the window. + focusCandidate.as().FocusNoActivate(focusState); m_lastFocusedElement.set(focusedChild); // Add pin to hold the focused element. @@ -924,8 +913,9 @@ bool ViewManager::ClearElementToAnimator(const winrt::UIElement& element, const bool ViewManager::ClearElementToPinnedPool(const winrt::UIElement& element, const winrt::com_ptr& virtInfo, bool isClearedDueToCollectionChange) { + const bool isInPinnedPool = virtInfo->IsInPinnedPool(); const bool moveToPinnedPool = - !isClearedDueToCollectionChange && virtInfo->IsPinned(); + !isClearedDueToCollectionChange && virtInfo->IsPinned() && !isInPinnedPool; if (moveToPinnedPool) { @@ -946,7 +936,8 @@ bool ViewManager::ClearElementToPinnedPool(const winrt::UIElement& element, cons virtInfo->MoveOwnershipToPinnedPool(); } - return moveToPinnedPool; + // Element is already in pinnedPool or is moved to pinnedPool. Both mean element is cleared. + return isInPinnedPool || moveToPinnedPool; } #pragma endregion diff --git a/src/controls/dev/Repeater/ViewportManager.h b/src/controls/dev/Repeater/ViewportManager.h index 17f07bce43..15f059f02d 100644 --- a/src/controls/dev/Repeater/ViewportManager.h +++ b/src/controls/dev/Repeater/ViewportManager.h @@ -14,7 +14,7 @@ class ViewportManager virtual winrt::Rect GetLayoutVisibleWindow() const = 0; virtual winrt::Rect GetLayoutRealizationWindow() const = 0; - virtual void SetLayoutExtent(winrt::Rect extent) = 0; + virtual void SetLayoutExtent(const winrt::Rect& layoutExtent) = 0; virtual winrt::Rect GetLayoutExtent() const = 0; virtual winrt::Point GetOrigin() const = 0; @@ -24,8 +24,9 @@ class ViewportManager virtual void OnOwnerMeasuring() = 0; virtual void OnOwnerArranged() = 0; virtual void OnMakeAnchor(const winrt::UIElement& anchor, const bool isAnchorOutsideRealizedRange) = 0; - virtual void OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs args) = 0; + virtual void OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs& args) = 0; + virtual void ResetLayoutRealizationWindowCacheBuffer() = 0; virtual void ResetScrollers() = 0; virtual winrt::UIElement MadeAnchor() const = 0; diff --git a/src/controls/dev/Repeater/ViewportManagerDownlevel.cpp b/src/controls/dev/Repeater/ViewportManagerDownlevel.cpp index 37c07273df..8c81982c7a 100644 --- a/src/controls/dev/Repeater/ViewportManagerDownlevel.cpp +++ b/src/controls/dev/Repeater/ViewportManagerDownlevel.cpp @@ -127,7 +127,7 @@ winrt::Rect ViewportManagerDownLevel::GetLayoutRealizationWindow() const return realizationWindow; } -void ViewportManagerDownLevel::SetLayoutExtent(winrt::Rect extent) +void ViewportManagerDownLevel::SetLayoutExtent(const winrt::Rect& extent) { m_expectedViewportShift.X += m_layoutExtent.X - extent.X; m_expectedViewportShift.Y += m_layoutExtent.Y - extent.Y; @@ -170,6 +170,23 @@ void ViewportManagerDownLevel::OnElementCleared(const winrt::UIElement& element) } } +void ViewportManagerDownLevel::OnOwnerMeasuring() +{ + winrt::Rect currentLayoutRealizationWindow = GetLayoutRealizationWindow(); + + if ((m_horizontalCacheBufferPerSide != 0.0 || m_verticalCacheBufferPerSide != 0.0) && + (m_lastLayoutRealizationWindow.Width <= 0.0f || m_lastLayoutRealizationWindow.Height <= 0.0f || + currentLayoutRealizationWindow.Width <= 0.0f || currentLayoutRealizationWindow.Height <= 0.0f || + !SharedHelpers::DoRectsIntersect(m_lastLayoutRealizationWindow, currentLayoutRealizationWindow))) + { + // Two consecutive measure passes use disconnected realization windows. + // Reset the potential cache buffer so that it regrows from scratch. + ResetLayoutRealizationWindowCacheBuffer(); + } + + m_lastLayoutRealizationWindow = currentLayoutRealizationWindow; +} + void ViewportManagerDownLevel::OnOwnerArranged() { if (m_managingViewportDisabled) @@ -211,7 +228,7 @@ void ViewportManagerDownLevel::OnMakeAnchor(const winrt::UIElement& anchor, cons m_isAnchorOutsideRealizedRange = isAnchorOutsideRealizedRange; } -void ViewportManagerDownLevel::OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs args) +void ViewportManagerDownLevel::OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs& args) { if (!m_managingViewportDisabled) { @@ -417,12 +434,17 @@ void ViewportManagerDownLevel::UpdateViewport() } } -void ViewportManagerDownLevel::ResetCacheBuffer() +void ViewportManagerDownLevel::ResetLayoutRealizationWindowCacheBuffer() +{ + ResetCacheBuffer(false /*registerCacheBuildWork*/); +} + +void ViewportManagerDownLevel::ResetCacheBuffer(bool registerCacheBuildWork) { m_horizontalCacheBufferPerSide = 0.0; m_verticalCacheBufferPerSide = 0.0; - if (!m_managingViewportDisabled) + if (!m_managingViewportDisabled && registerCacheBuildWork) { // We need to start building the realization buffer again. RegisterCacheBuildWork(); diff --git a/src/controls/dev/Repeater/ViewportManagerDownlevel.h b/src/controls/dev/Repeater/ViewportManagerDownlevel.h index a21c9af7c9..6a10264ca7 100644 --- a/src/controls/dev/Repeater/ViewportManagerDownlevel.h +++ b/src/controls/dev/Repeater/ViewportManagerDownlevel.h @@ -27,18 +27,19 @@ class ViewportManagerDownLevel : public ViewportManager winrt::Rect GetLayoutVisibleWindow() const override; winrt::Rect GetLayoutRealizationWindow() const override; - void SetLayoutExtent(winrt::Rect extent) override; + void SetLayoutExtent(const winrt::Rect& extent) override; winrt::Rect GetLayoutExtent() const override { return m_layoutExtent; } winrt::Point GetOrigin() const override{ return winrt::Point(m_layoutExtent.X, m_layoutExtent.Y); } void OnLayoutChanged(bool isVirtualizing) override; void OnElementPrepared(const winrt::UIElement& element) override {} void OnElementCleared(const winrt::UIElement& element) override; - void OnOwnerMeasuring() override {}; + void OnOwnerMeasuring() override; void OnOwnerArranged() override; void OnMakeAnchor(const winrt::UIElement& anchor, const bool isAnchorOutsideRealizedRange) override; - void OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs args) override; + void OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs& args) override; + void ResetLayoutRealizationWindowCacheBuffer() override; void ResetScrollers() override; winrt::UIElement MadeAnchor() const override { return m_makeAnchorElement.get(); } @@ -55,7 +56,7 @@ class ViewportManagerDownLevel : public ViewportManager bool HasScrollers() const { return !!m_horizontalScroller || !!m_verticalScroller; } bool AddScroller(const winrt::IRepeaterScrollingSurface& scroller); void UpdateViewport(); - void ResetCacheBuffer(); + void ResetCacheBuffer(bool registerCacheBuildWork = true); void ValidateCacheLength(double cacheLength); void RegisterCacheBuildWork(); void TryInvalidateMeasure(); @@ -85,6 +86,7 @@ class ViewportManagerDownLevel : public ViewportManager tracker_ref m_cacheBuildAction; + winrt::Rect m_lastLayoutRealizationWindow{}; winrt::Rect m_visibleWindow{}; winrt::Rect m_layoutExtent{}; winrt::Point m_expectedViewportShift{}; diff --git a/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.cpp b/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.cpp index bf950fe842..c58946ec41 100644 --- a/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.cpp +++ b/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.cpp @@ -6,7 +6,7 @@ #include "ItemsRepeater.common.h" #include "ViewportManagerWithPlatformFeatures.h" #include "ItemsRepeater.h" -#include "layout.h" +#include "Layout.h" // Pixel delta by which to inflate the cache buffer on each side. Rather than fill the entire // cache buffer all at once, we chunk the work to make the UI thread more responsive. We inflate @@ -36,9 +36,7 @@ winrt::UIElement ViewportManagerWithPlatformFeatures::SuggestedAnchor() const if (anchorElement) { - ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR, METH_NAME, this, GetLayoutId().data(), L"SuggestedAnchor returns IScrollAnchorProvider.CurrentAnchor."); - - // We can't simply return anchorElement because, in case of nested Repeaters, it may not + // We can't simply return anchorElement because, in case of nested ItemsRepeaters, it may not // be a direct child of ours, or even an indirect child. We need to walk up the tree starting // from anchorElement to figure out what child of ours (if any) to use as the suggested element. winrt::UIElement owner = *m_owner; @@ -55,6 +53,8 @@ winrt::UIElement ViewportManagerWithPlatformFeatures::SuggestedAnchor() const child = parent; parent = CachedVisualTreeHelpers::GetParent(parent).as(); } + + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_PTR, METH_NAME, this, GetLayoutId().data(), L"SuggestedAnchor returns IScrollAnchorProvider.CurrentAnchor.", suggestedAnchor); } #ifdef DBG else @@ -66,7 +66,8 @@ winrt::UIElement ViewportManagerWithPlatformFeatures::SuggestedAnchor() const #ifdef DBG else { - ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR, METH_NAME, this, GetLayoutId().data(), L"SuggestedAnchor returns non-null m_makeAnchorElement."); + // Since we have an anchor element, we do not want the scroll anchor provider to start anchoring some other element. + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_PTR, METH_NAME, this, GetLayoutId().data(), L"SuggestedAnchor returns non-null m_makeAnchorElement.", m_makeAnchorElement); } #endif return suggestedAnchor; @@ -147,23 +148,69 @@ winrt::Rect ViewportManagerWithPlatformFeatures::GetLayoutRealizationWindow() co return realizationWindow; } -void ViewportManagerWithPlatformFeatures::SetLayoutExtent(winrt::Rect extent) +void ViewportManagerWithPlatformFeatures::SetVisibleWindow(const winrt::Rect& visibleWindow) { - m_expectedViewportShift.X += m_layoutExtent.X - extent.X; - m_expectedViewportShift.Y += m_layoutExtent.Y - extent.Y; + if (visibleWindow.X != m_visibleWindow.X || visibleWindow.Y != m_visibleWindow.Y || + visibleWindow.Width != m_visibleWindow.Width || visibleWindow.Height != m_visibleWindow.Height) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_visibleWindow set:", + visibleWindow.X, visibleWindow.Y, visibleWindow.Width, visibleWindow.Height); - // We tolerate viewport imprecisions up to 1 pixel to avoid invaliding layout too much. - if (std::abs(m_expectedViewportShift.X) > 1.f || std::abs(m_expectedViewportShift.Y) > 1.f) + m_visibleWindow = visibleWindow; + } +} + +void ViewportManagerWithPlatformFeatures::SetPendingViewportShift(const winrt::Point& pendingViewportShift) +{ + if (pendingViewportShift.X != m_pendingViewportShift.X || pendingViewportShift.Y != m_pendingViewportShift.Y) { ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, - GetLayoutId().data(), L"Expecting viewport shift:", - m_expectedViewportShift.X, m_expectedViewportShift.Y); + GetLayoutId().data(), L"m_pendingViewportShift set:", + pendingViewportShift.X, pendingViewportShift.Y); + + m_pendingViewportShift = pendingViewportShift; + } +} + +void ViewportManagerWithPlatformFeatures::SetExpectedViewportShift(float expectedViewportShiftX, float expectedViewportShiftY) +{ + if (expectedViewportShiftX != m_expectedViewportShift.X || expectedViewportShiftY != m_expectedViewportShift.Y) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_expectedViewportShift set:", + expectedViewportShiftX, expectedViewportShiftY); + + m_expectedViewportShift.X = expectedViewportShiftX; + m_expectedViewportShift.Y = expectedViewportShiftY; + } +} + +void ViewportManagerWithPlatformFeatures::SetUnshiftableShift(float unshiftableShiftX, float unshiftableShiftY) +{ + if (unshiftableShiftX != m_unshiftableShift.X || unshiftableShiftY != m_unshiftableShift.Y) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_unshiftableShift set:", + unshiftableShiftX, unshiftableShiftY); + m_unshiftableShift.X = unshiftableShiftX; + m_unshiftableShift.Y = unshiftableShiftY; + } +} + +void ViewportManagerWithPlatformFeatures::SetLayoutExtent(const winrt::Rect& layoutExtent) +{ + SetExpectedViewportShift(m_expectedViewportShift.X + m_layoutExtent.X - layoutExtent.X, m_expectedViewportShift.Y + m_layoutExtent.Y - layoutExtent.Y); + + // We tolerate viewport imprecisions up to 1 pixel to avoid invaliding layout too much. + if (std::abs(m_expectedViewportShift.X) > 1.f || std::abs(m_expectedViewportShift.Y) > 1.f) + { // There are cases where we might be expecting a shift but not get it. We will - // be waiting for the effective viewport event but if the scroll viewer is not able + // be waiting for the effective viewport event but if the scroller is not able // to perform the shift (perhaps because it cannot scroll in negative offset), - // then we will end up not realizing elements in the visible - // window. To avoid this, we register to layout updated for this layout pass. If we + // then we will end up not realizing elements in the visible window. + // To avoid this, we register to layout updated for this layout pass. If we // get an effective viewport, we know we have a new viewport and we unregister from // layout updated. If we get the layout updated handler, then we know that the // scroller was unable to perform the shift and we invalidate measure and unregister @@ -174,24 +221,98 @@ void ViewportManagerWithPlatformFeatures::SetLayoutExtent(winrt::Rect extent) } } - m_layoutExtent = extent; - m_pendingViewportShift = m_expectedViewportShift; + if (layoutExtent.X != m_layoutExtent.X || layoutExtent.Y != m_layoutExtent.Y || + layoutExtent.Width != m_layoutExtent.Width || layoutExtent.Height != m_layoutExtent.Height) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_layoutExtent set:", + layoutExtent.X, layoutExtent.Y); + + m_layoutExtent = layoutExtent; + } + + SetPendingViewportShift(m_expectedViewportShift); // We just finished a measure pass and have a new extent. - // Let's make sure the scrollers will run its arrange so that they track the anchor. + // Let's make sure the scroller will run its arrange so that it tracks the anchor. if (m_scroller) { m_scroller.as().InvalidateArrange(); } } +void ViewportManagerWithPlatformFeatures::ResetLayoutExtent() +{ + if (m_layoutExtent.X != 0.0f || m_layoutExtent.Y != 0.0f || + m_layoutExtent.Width != 0.0f || m_layoutExtent.Height != 0.0f) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_layoutExtent reset:", + m_layoutExtent.X, m_layoutExtent.Y, m_layoutExtent.Width, m_layoutExtent.Height); + + m_layoutExtent = {}; + } +} + +void ViewportManagerWithPlatformFeatures::ResetVisibleWindow() +{ + if (m_visibleWindow.X != 0.0f || m_visibleWindow.Y != 0.0f || + m_visibleWindow.Width != 0.0f || m_visibleWindow.Height != 0.0f) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_visibleWindow reset:", + m_visibleWindow.X, m_visibleWindow.Y, m_visibleWindow.Width, m_visibleWindow.Height); + + m_visibleWindow = {}; + } +} + +void ViewportManagerWithPlatformFeatures::ResetExpectedViewportShift() +{ + if (m_expectedViewportShift.X != 0.0f || m_expectedViewportShift.Y != 0.0f) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_expectedViewportShift reset:", + m_expectedViewportShift.X, m_expectedViewportShift.Y); + + m_expectedViewportShift = {}; + } +} + +void ViewportManagerWithPlatformFeatures::ResetPendingViewportShift() +{ + if (m_pendingViewportShift.X != 0.0f || m_pendingViewportShift.Y != 0.0f) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_pendingViewportShift reset:", + m_pendingViewportShift.X, m_pendingViewportShift.Y); + + m_pendingViewportShift = {}; + } +} + +void ViewportManagerWithPlatformFeatures::ResetUnshiftableShift() +{ + if (m_unshiftableShift.X != 0.0f || m_unshiftableShift.Y != 0.0f) + { + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_unshiftableShift reset:", + m_unshiftableShift.X, m_unshiftableShift.Y); + + m_unshiftableShift = {}; + } +} + void ViewportManagerWithPlatformFeatures::OnLayoutChanged(bool isVirtualizing) { + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR_INT, METH_NAME, this, + GetLayoutId().data(), isVirtualizing); + m_managingViewportDisabled = !isVirtualizing; - m_layoutExtent = {}; - m_expectedViewportShift = {}; - m_pendingViewportShift = {}; + ResetLayoutExtent(); + ResetExpectedViewportShift(); + ResetPendingViewportShift(); if (m_managingViewportDisabled) { @@ -202,20 +323,55 @@ void ViewportManagerWithPlatformFeatures::OnLayoutChanged(bool isVirtualizing) m_effectiveViewportChangedRevoker = m_owner->EffectiveViewportChanged(winrt::auto_revoke, { this, &ViewportManagerWithPlatformFeatures::OnEffectiveViewportChanged }); } - m_unshiftableShift = {}; + ResetUnshiftableShift(); ResetCacheBuffer(); } void ViewportManagerWithPlatformFeatures::OnElementPrepared(const winrt::UIElement& element) { - // If we have an anchor element, we do not want the - // scroll anchor provider to start anchoring some other element. - element.CanBeScrollAnchor(true); + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_PTR, METH_NAME, this, element); + + // The newly prepared element is not registered as an anchor candidate right away. It first needs to be arranged at least once so its position + // tracked by the scroller is valid. + // The element is first put into a list of prepared elements. Then once arranged it is put into a list of prepared+arranged elements. Then finally + // at the beginning of the following measure pass, it is registered as an anchor candidate. + + const auto itPreparedElement = std::find_if(m_preparedElements.cbegin(), m_preparedElements.cend(), [&element](const tracker_ref& preparedElement) { return preparedElement.get() == element; }); + + if (itPreparedElement == m_preparedElements.cend()) + { + m_preparedElements.push_back(tracker_ref{ m_owner, element }); + } } void ViewportManagerWithPlatformFeatures::OnElementCleared(const winrt::UIElement& element) { - element.CanBeScrollAnchor(false); + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_PTR, METH_NAME, this, element); + + // Remove the element from the prepared and prepared+arranged lists so it no longer gets registered as an anchor candidate for the scroller + // after the next arrange pass. + + const auto itPreparedElement = std::find_if(m_preparedElements.cbegin(), m_preparedElements.cend(), + [&element](const tracker_ref& preparedElement) { return preparedElement.get() == element; }); + + if (itPreparedElement != m_preparedElements.cend()) + { + m_preparedElements.erase(itPreparedElement); + } + + const auto itPreparedAndArrangedElement = std::find_if(m_preparedAndArrangedElements.cbegin(), m_preparedAndArrangedElements.cend(), + [&element](const tracker_ref& preparedAndArrangedElement) { return preparedAndArrangedElement.get() == element; }); + + if (itPreparedAndArrangedElement != m_preparedAndArrangedElements.cend()) + { + m_preparedAndArrangedElements.erase(itPreparedAndArrangedElement); + } + + if (element.CanBeScrollAnchor()) + { + // Unregister the element as an anchor candidate since it was already declared as such. + element.CanBeScrollAnchor(false); + } } void ViewportManagerWithPlatformFeatures::OnOwnerMeasuring() @@ -224,11 +380,64 @@ void ViewportManagerWithPlatformFeatures::OnOwnerMeasuring() // fire if you register during arrange. // Bug 17411076: EffectiveViewport: registering for effective viewport in arrange should invalidate viewport EnsureScroller(); + + winrt::Rect currentLayoutRealizationWindow = GetLayoutRealizationWindow(); + + if ((m_horizontalCacheBufferPerSide != 0.0 || m_verticalCacheBufferPerSide != 0.0) && + (m_lastLayoutRealizationWindow.Width <= 0.0f || m_lastLayoutRealizationWindow.Height <= 0.0f || + currentLayoutRealizationWindow.Width <= 0.0f || currentLayoutRealizationWindow.Height <= 0.0f || + !SharedHelpers::DoRectsIntersect(m_lastLayoutRealizationWindow, currentLayoutRealizationWindow))) + { + // Two consecutive measure passes use disconnected realization windows. + // Reset the potential cache buffer so that it regrows from scratch. + ResetLayoutRealizationWindowCacheBuffer(); + } + + m_lastLayoutRealizationWindow = currentLayoutRealizationWindow; + + if (m_skipScrollAnchorRegistrationsDuringNextMeasurePass) + { + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR, METH_NAME, this, L"m_skipScrollAnchorRegistrationsDuringNextMeasurePass reset."); + + m_skipScrollAnchorRegistrationsDuringNextMeasurePass = false; + } + else if (!m_skipScrollAnchorRegistrationsDuringNextArrangePass) + { + // Now that a new measure pass is starting, register the previously arranged elements as anchor candidates for the scroller. + RegisterPreparedAndArrangedElementsAsScrollAnchorCandidates(); + } + +#ifdef DBG + TraceScrollerDbg(); +#endif // DBG } void ViewportManagerWithPlatformFeatures::OnOwnerArranged() { - m_expectedViewportShift = {}; +#ifdef DBG + ITEMSREPEATER_TRACE_VERBOSE(nullptr, TRACE_MSG_METH_STR, METH_NAME, this, GetLayoutId().data()); + + TraceScrollerDbg(); + TraceFieldsDbg(); +#endif // DBG + + if (!m_skipScrollAnchorRegistrationsDuringNextMeasurePass) + { + if (m_skipScrollAnchorRegistrationsDuringNextArrangePass) + { + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR, METH_NAME, this, L"m_skipScrollAnchorRegistrationsDuringNextArrangePass reset."); + + m_skipScrollAnchorRegistrationsDuringNextArrangePass = false; + } + else + { + // Now that an arrange pass completed, register the prepared elements as arranged. They will be registered as anchor candidates + // during the next measure pass. + RegisterPreparedElementsAsArranged(); + } + } + + ResetExpectedViewportShift(); if (!m_managingViewportDisabled) { @@ -264,6 +473,8 @@ void ViewportManagerWithPlatformFeatures::OnOwnerArranged() void ViewportManagerWithPlatformFeatures::OnLayoutUpdated(winrt::IInspectable const& sender, winrt::IInspectable const& args) { + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR, METH_NAME, this, GetLayoutId().data()); + m_layoutUpdatedRevoker.revoke(); if (m_managingViewportDisabled) { @@ -272,9 +483,9 @@ void ViewportManagerWithPlatformFeatures::OnLayoutUpdated(winrt::IInspectable co // We were expecting a viewport shift but we never got one and we are not going to in this // layout pass. We likely will never get this shift, so lets assume that we are never going to get it and - // adjust our expected shift to track that. One case where this can happen is when there is no scrollviewer + // adjust our expected shift to track that. One case where this can happen is when there is no scroller // that can scroll in the direction where the shift is expected. - if (m_pendingViewportShift.X != 0 || m_pendingViewportShift.Y != 0) + if (m_pendingViewportShift.X != 0.0f || m_pendingViewportShift.Y != 0.0f) { ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, GetLayoutId().data(), L"Layout Updated with pending shift - invalidating measure", @@ -282,10 +493,9 @@ void ViewportManagerWithPlatformFeatures::OnLayoutUpdated(winrt::IInspectable co m_pendingViewportShift.Y); // Assume this is never going to come. - m_unshiftableShift.X += m_pendingViewportShift.X; - m_unshiftableShift.Y += m_pendingViewportShift.Y; - m_pendingViewportShift = {}; - m_expectedViewportShift = {}; + SetUnshiftableShift(m_unshiftableShift.X + m_pendingViewportShift.X, m_unshiftableShift.Y + m_pendingViewportShift.Y); + ResetPendingViewportShift(); + ResetExpectedViewportShift(); TryInvalidateMeasure(); } @@ -296,11 +506,11 @@ void ViewportManagerWithPlatformFeatures::OnMakeAnchor(const winrt::UIElement& a #ifdef DBG if (anchor == nullptr) { - ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR, METH_NAME, this, GetLayoutId().data(), L"Resets m_makeAnchorElement."); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_PTR, METH_NAME, this, GetLayoutId().data(), L"Resets m_makeAnchorElement.", m_makeAnchorElement); } else { - ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR, METH_NAME, this, GetLayoutId().data(), L"%Sets m_makeAnchorElement."); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_PTR, METH_NAME, this, GetLayoutId().data(), L"%Sets m_makeAnchorElement.", anchor); } #endif // DBG @@ -308,8 +518,10 @@ void ViewportManagerWithPlatformFeatures::OnMakeAnchor(const winrt::UIElement& a m_isAnchorOutsideRealizedRange = isAnchorOutsideRealizedRange; } -void ViewportManagerWithPlatformFeatures::OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs args) +void ViewportManagerWithPlatformFeatures::OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs& args) { + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR, METH_NAME, this, GetLayoutId().data()); + if (!m_managingViewportDisabled) { // We do not animate bring-into-view operations where the anchor is disconnected because @@ -332,13 +544,7 @@ void ViewportManagerWithPlatformFeatures::OnBringIntoViewRequested(const winrt:: const auto targetChild = GetImmediateChildOfRepeater(args.TargetElement()); // Make sure that only the target child can be the anchor during the bring into view operation. - for (const auto& child : m_owner->Children()) - { - if (child.CanBeScrollAnchor() && child != targetChild) - { - child.CanBeScrollAnchor(false); - } - } + UnregisterScrollAnchorCandidates(targetChild /*exceptionElement*/, false /*registerAsPreparedAndArrangedElements*/); // Register to rendering event to go back to how things were before where any child can be the anchor. m_isBringIntoViewInProgress = true; @@ -370,9 +576,9 @@ winrt::UIElement ViewportManagerWithPlatformFeatures::GetImmediateChildOfRepeate void ViewportManagerWithPlatformFeatures::OnCompositionTargetRendering(const winrt::IInspectable& /*sender*/, const winrt::IInspectable& /*args*/) { - ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR, METH_NAME, this, GetLayoutId().data(), L"Resets m_makeAnchorElement."); + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_PTR, METH_NAME, this, GetLayoutId().data(), L"Resets m_makeAnchorElement.", m_makeAnchorElement); - assert(!m_managingViewportDisabled); + MUX_ASSERT(!m_managingViewportDisabled); m_renderingToken.revoke(); @@ -396,7 +602,10 @@ void ViewportManagerWithPlatformFeatures::OnCompositionTargetRendering(const win void ViewportManagerWithPlatformFeatures::ResetScrollers() { m_scroller.set(nullptr); + m_scrollPresenterViewChangingRevoker.revoke(); m_effectiveViewportChangedRevoker.revoke(); + m_skipScrollAnchorRegistrationsDuringNextMeasurePass = false; + m_skipScrollAnchorRegistrationsDuringNextArrangePass = false; m_ensuredScroller = false; } @@ -409,21 +618,139 @@ void ViewportManagerWithPlatformFeatures::OnCacheBuildActionCompleted() } } +// Detect an imminent ScrollPresenter view change triggered by a ScrollTo, ScrollBy, ZoomTo, or ZoomBy call (which is likely originated from a ScrollBar interaction) +// in order to generate items around the destination area. This is to avoid the ScrollPresenter showing blank content because the Compositor thread moved the ScrollPresenter.Content +// visual before the ItemsRepeater was measured and arranged for the destination view. +// This event handler checks if that anticipated view, without UI re-generation, would create a blank region in the ScrollPresenter. In the interest of performance, less than +// 5% blank is tolerated and will not trigger a re-generation. Beyond that, UpdateViewport is called with the anticipated realization window. This is trigger an ItemsRepeater +// measure/arrange pass based on the anticipated view. +void ViewportManagerWithPlatformFeatures::OnScrollPresenterViewChanging(winrt::ScrollPresenter const& scrollPresenter, winrt::ScrollingViewChangingEventArgs const& args) +{ + const float blankViewportRatioTolerated = 0.05f; + const float anticipatedHorizontalOffset = static_cast(args.HorizontalOffset()); + const float anticipatedVerticalOffset = static_cast(args.VerticalOffset()); + const float anticipatedZoomFactor = args.ZoomFactor(); + const float anticipatedExtentWidth = static_cast(scrollPresenter.ExtentWidth() * anticipatedZoomFactor); + const float anticipatedExtentHeight = static_cast(scrollPresenter.ExtentHeight() * anticipatedZoomFactor); + const float viewportWidth = static_cast(scrollPresenter.ViewportWidth()); + const float viewportHeight = static_cast(scrollPresenter.ViewportHeight()); + const float unzoomedAnticipatedHorizontalOffset = anticipatedHorizontalOffset / anticipatedZoomFactor; + const float unzoomedAnticipatedVerticalOffset = anticipatedVerticalOffset / anticipatedZoomFactor; + const float scaledViewportWidth = viewportWidth / anticipatedZoomFactor; + const float scaledViewportHeight = viewportHeight / anticipatedZoomFactor; + const winrt::UIElement owner = *m_owner; + const winrt::FrameworkElement ownerAsFE = owner.as(); + +#ifdef DBG + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, GetLayoutId().data(), + L"Anticipated HorizontalOffset, VerticalOffset:", anticipatedHorizontalOffset, anticipatedVerticalOffset); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT, METH_NAME, this, GetLayoutId().data(), + L"Anticipated ZoomFactor:", anticipatedZoomFactor); + + TraceFieldsDbg(); +#endif // DBG + + winrt::Rect anticipatedLayoutRealizationWindow = { + unzoomedAnticipatedHorizontalOffset, + unzoomedAnticipatedVerticalOffset, + scaledViewportWidth, + scaledViewportHeight }; + + if (anticipatedExtentWidth < viewportWidth) + { + const winrt::HorizontalAlignment horizontalAlignment = ownerAsFE.HorizontalAlignment(); + + if (horizontalAlignment == winrt::HorizontalAlignment::Center || horizontalAlignment == winrt::HorizontalAlignment::Stretch) + { + anticipatedLayoutRealizationWindow.X -= (viewportWidth - anticipatedExtentWidth) / 2.0f / anticipatedZoomFactor; + } + else if (horizontalAlignment == winrt::HorizontalAlignment::Right) + { + anticipatedLayoutRealizationWindow.X -= (viewportWidth - anticipatedExtentWidth) / anticipatedZoomFactor; + } + } + + if (anticipatedExtentHeight < viewportHeight) + { + const winrt::VerticalAlignment verticalAlignment = ownerAsFE.VerticalAlignment(); + + if (verticalAlignment == winrt::VerticalAlignment::Center || verticalAlignment == winrt::VerticalAlignment::Stretch) + { + anticipatedLayoutRealizationWindow.Y -= (viewportHeight - anticipatedExtentHeight) / 2.0f / anticipatedZoomFactor; + } + else if (verticalAlignment == winrt::VerticalAlignment::Bottom) + { + anticipatedLayoutRealizationWindow.Y -= (viewportHeight - anticipatedExtentHeight) / anticipatedZoomFactor; + } + } + + // No UI re-generation is performed if the last recorded realization window, m_lastLayoutRealizationWindow, is empty. This avoids UI generation when the actual effective viewport is empty. + if (m_lastLayoutRealizationWindow.Width > 0.0f && m_lastLayoutRealizationWindow.Height > 0.0f && + m_unshiftableShift == winrt::Point() && // Do not affect start of a bring-into-view operation when the target layout anchor is realized and arranged, which results in m_unshiftableShift being set. + (anticipatedLayoutRealizationWindow.X < m_lastLayoutRealizationWindow.X - blankViewportRatioTolerated * scaledViewportWidth || + anticipatedLayoutRealizationWindow.X > m_lastLayoutRealizationWindow.X + m_lastLayoutRealizationWindow.Width - (1.0f - blankViewportRatioTolerated) * scaledViewportWidth || + anticipatedLayoutRealizationWindow.Y < m_lastLayoutRealizationWindow.Y - blankViewportRatioTolerated * scaledViewportHeight || + anticipatedLayoutRealizationWindow.Y > m_lastLayoutRealizationWindow.Y + m_lastLayoutRealizationWindow.Height - (1.0f - blankViewportRatioTolerated) * scaledViewportHeight)) + { + // Using the smallest effective viewport, viewportWidth x viewportHeight, to cover the ScrollPresenter's viewport. It may still be too large if a part of the scroller is not displayed on screen. + const bool invalidatedMeasure = UpdateViewport(anticipatedLayoutRealizationWindow); + + if (invalidatedMeasure) + { + UnregisterScrollAnchorCandidates(nullptr /*exceptionElement*/, true /*registerAsPreparedAndArrangedElements*/); + + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR, METH_NAME, this, L"m_skipScrollAnchorRegistrationsDuringNextMeasurePass/m_skipScrollAnchorRegistrationsDuringNextArrangePass set."); + + // During such a UI re-generation, scroll anchoring is momentarily turned off to avoid unwanted anchoring-driven scrolls. + m_skipScrollAnchorRegistrationsDuringNextMeasurePass = true; + m_skipScrollAnchorRegistrationsDuringNextArrangePass = true; + } + } +} + void ViewportManagerWithPlatformFeatures::OnEffectiveViewportChanged(winrt::FrameworkElement const& sender, winrt::EffectiveViewportChangedEventArgs const& args) { - assert(!m_managingViewportDisabled); - ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR, METH_NAME, this, GetLayoutId().data()); - UpdateViewport(args.EffectiveViewport()); + winrt::Rect effectiveViewport = args.EffectiveViewport(); - m_pendingViewportShift = {}; - m_unshiftableShift = {}; - if (m_visibleWindow == winrt::Rect()) +#ifdef DBG + MUX_ASSERT(!m_managingViewportDisabled); + + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, GetLayoutId().data(), + L"EffectiveViewport:", effectiveViewport.X, effectiveViewport.Y, effectiveViewport.Width, effectiveViewport.Height); + + TraceScrollerDbg(); +#endif // DBG + + bool invalidateMeasure = false; + const bool invalidatedMeasure = UpdateViewport(args.EffectiveViewport()); + const winrt::Point emptyPoint = {}; + const winrt::Rect emptyRect = {}; + + if (m_pendingViewportShift != emptyPoint) + { + ResetPendingViewportShift(); + invalidateMeasure = true; + } + + if (m_unshiftableShift != emptyPoint) + { + ResetUnshiftableShift(); + invalidateMeasure = true; + } + + if (m_visibleWindow == emptyRect && m_layoutExtent != emptyRect) { // We got cleared. - m_layoutExtent = {}; + ResetLayoutExtent(); + invalidateMeasure = true; + } + + if (invalidateMeasure && !invalidatedMeasure) + { + TryInvalidateMeasure(); } - // We got a new viewport, we dont need to wait for layout updated anymore to + // We got a new viewport, we don't need to wait for layout updated anymore to // see if our request for a pending shift was handled. m_layoutUpdatedRevoker.revoke(); } @@ -452,53 +779,82 @@ void ViewportManagerWithPlatformFeatures::EnsureScroller() m_effectiveViewportChangedRevoker = m_owner->EffectiveViewportChanged(winrt::auto_revoke, { this, &ViewportManagerWithPlatformFeatures::OnEffectiveViewportChanged }); } + if (const auto scrollPresenter2 = m_scroller.try_as()) + { + m_scrollPresenterViewChangingRevoker = scrollPresenter2.ViewChanging(winrt::auto_revoke, { this, &ViewportManagerWithPlatformFeatures::OnScrollPresenterViewChanging }); + } + m_ensuredScroller = true; } } -void ViewportManagerWithPlatformFeatures::UpdateViewport(winrt::Rect const& viewport) +// Returns True when m_visibleWindow changes and TryInvalidateMeasure is invoked. +bool ViewportManagerWithPlatformFeatures::UpdateViewport(winrt::Rect const& effectiveViewport) { - assert(!m_managingViewportDisabled); - const auto previousVisibleWindow = m_visibleWindow; +#ifdef DBG + MUX_ASSERT(!m_managingViewportDisabled); - ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, - GetLayoutId().data(), - L"Previous Effective Viewport:", - previousVisibleWindow.X, previousVisibleWindow.Y, previousVisibleWindow.Width, previousVisibleWindow.Height); - ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, - GetLayoutId().data(), - L"Current Effective Viewport:", - viewport.X, viewport.Y, viewport.Width, viewport.Height); + const auto previousVisibleWindowDbg = m_visibleWindow; - const auto& currentVisibleWindow = viewport; + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, GetLayoutId().data(), + L"Previous Effective Viewport:", previousVisibleWindowDbg.X, previousVisibleWindowDbg.Y, previousVisibleWindowDbg.Width, previousVisibleWindowDbg.Height); + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, GetLayoutId().data(), + L"Current Effective Viewport:", effectiveViewport.X, effectiveViewport.Y, effectiveViewport.Width, effectiveViewport.Height); + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, GetLayoutId().data(), + L"Effective Viewport shift:", effectiveViewport.X - previousVisibleWindowDbg.X, effectiveViewport.Y - previousVisibleWindowDbg.Y, effectiveViewport.Width - previousVisibleWindowDbg.Width, effectiveViewport.Height - previousVisibleWindowDbg.Height); +#endif // DBG - if (-currentVisibleWindow.X <= ItemsRepeater::ClearedElementsArrangePosition.X && - -currentVisibleWindow.Y <= ItemsRepeater::ClearedElementsArrangePosition.Y) + if (-effectiveViewport.X <= ItemsRepeater::ClearedElementsArrangePosition.X && + -effectiveViewport.Y <= ItemsRepeater::ClearedElementsArrangePosition.Y) { - ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR, METH_NAME, this, GetLayoutId().data(), L"Viewport is invalid. visible window cleared."); + ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR, METH_NAME, this, GetLayoutId().data(), L"Viewport is invalid. Visible window cleared."); // We got cleared. - m_visibleWindow = {}; + ResetVisibleWindow(); } else { - ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, GetLayoutId().data(), L"Previous Viewport:", - previousVisibleWindow.X, previousVisibleWindow.Y, previousVisibleWindow.Width, previousVisibleWindow.Height); - ITEMSREPEATER_TRACE_INFO_DBG(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, GetLayoutId().data(), L"Current Viewport:", - currentVisibleWindow.X, currentVisibleWindow.Y, currentVisibleWindow.Width, currentVisibleWindow.Height); + const float roundingTolerance = 0.01f; + + if (std::abs(m_visibleWindow.X - effectiveViewport.X) > roundingTolerance || + std::abs(m_visibleWindow.Y - effectiveViewport.Y) > roundingTolerance || + std::abs(m_visibleWindow.Width - effectiveViewport.Width) > roundingTolerance || + std::abs(m_visibleWindow.Height - effectiveViewport.Height) > roundingTolerance) + { + SetVisibleWindow(effectiveViewport); - m_visibleWindow = currentVisibleWindow; + TryInvalidateMeasure(); + return true; + } } - TryInvalidateMeasure(); + return false; +} + +void ViewportManagerWithPlatformFeatures::ResetLayoutRealizationWindowCacheBuffer() +{ + ResetCacheBuffer(false /*registerCacheBuildWork*/); } -void ViewportManagerWithPlatformFeatures::ResetCacheBuffer() +void ViewportManagerWithPlatformFeatures::ResetCacheBuffer(bool registerCacheBuildWork) { +#ifdef DBG + if (m_horizontalCacheBufferPerSide != 0.0) + { + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_DBL, METH_NAME, this, + GetLayoutId().data(), L"m_horizontalCacheBufferPerSide reset:", m_horizontalCacheBufferPerSide); + } + if (m_verticalCacheBufferPerSide != 0.0) + { + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_DBL, METH_NAME, this, + GetLayoutId().data(), L"m_verticalCacheBufferPerSide reset:", m_verticalCacheBufferPerSide); + } +#endif // DBG + m_horizontalCacheBufferPerSide = 0.0; m_verticalCacheBufferPerSide = 0.0; - if (!m_managingViewportDisabled) + if (!m_managingViewportDisabled && registerCacheBuildWork) { // We need to start building the realization buffer again. RegisterCacheBuildWork(); @@ -513,13 +869,65 @@ void ViewportManagerWithPlatformFeatures::ValidateCacheLength(double cacheLength } } +void ViewportManagerWithPlatformFeatures::RegisterPreparedElementsAsArranged() +{ + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR_INT, METH_NAME, this, L"m_preparedElements.size:", m_preparedElements.size()); + + if (m_preparedElements.size() == 0) + { + return; + } + + for (tracker_ref preparedElementTracker : m_preparedElements) + { + const winrt::UIElement preparedElement = preparedElementTracker.get(); + + const auto it = std::find_if(m_preparedAndArrangedElements.cbegin(), m_preparedAndArrangedElements.cend(), + [&preparedElement](const tracker_ref& preparedAndArrangedElement) { return preparedAndArrangedElement.get() == preparedElement; }); + + if (it == m_preparedAndArrangedElements.cend()) + { + m_preparedAndArrangedElements.push_back(tracker_ref{ m_owner, preparedElement }); + } + } + + m_preparedElements.clear(); +} + +void ViewportManagerWithPlatformFeatures::RegisterPreparedAndArrangedElementsAsScrollAnchorCandidates() +{ + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR_INT, METH_NAME, this, L"m_preparedAndArrangedElements.size:", m_preparedAndArrangedElements.size()); + + if (m_preparedAndArrangedElements.size() == 0) + { + return; + } + + for (tracker_ref anchorCandidateTracker : m_preparedAndArrangedElements) + { + const winrt::UIElement anchorCandidate = anchorCandidateTracker.get(); + + if (!anchorCandidate.CanBeScrollAnchor()) + { + const auto info = ItemsRepeater::GetVirtualizationInfo(anchorCandidate); + + if (info->IsRealized() && info->IsHeldByLayout()) + { + anchorCandidate.CanBeScrollAnchor(true); + } + } + } + + m_preparedAndArrangedElements.clear(); +} + void ViewportManagerWithPlatformFeatures::RegisterCacheBuildWork() { - assert(!m_managingViewportDisabled); + MUX_ASSERT(!m_managingViewportDisabled); if (m_owner->Layout() && !m_cacheBuildActionOutstanding) { - // We capture 'owner' (a strong refernce on ItemsRepeater) to make sure ItemsRepeater is still around + // We capture 'owner' (a strong reference on ItemsRepeater) to make sure ItemsRepeater is still around // when the async action completes. By protecting ItemsRepeater, we also ensure that this instance // of ViewportManager (referenced by 'this' pointer) is valid because the lifetime of ItemsRepeater // and ViewportManager is the same (see ItemsRepeater::m_viewportManager). @@ -547,6 +955,24 @@ void ViewportManagerWithPlatformFeatures::TryInvalidateMeasure() } } +void ViewportManagerWithPlatformFeatures::UnregisterScrollAnchorCandidates(winrt::UIElement const& exceptionElement, bool registerAsPreparedAndArrangedElements) +{ + ITEMSREPEATER_TRACE_VERBOSE_DBG(nullptr, TRACE_MSG_METH_STR_INT, METH_NAME, this, L"registerAsPreparedAndArrangedElements:", registerAsPreparedAndArrangedElements); + + for (const winrt::UIElement& child : m_owner->Children()) + { + if (child.CanBeScrollAnchor() && child != exceptionElement) + { + child.CanBeScrollAnchor(false); + + if (registerAsPreparedAndArrangedElements) + { + m_preparedAndArrangedElements.push_back(tracker_ref{ m_owner, child }); + } + } + } +} + winrt::hstring ViewportManagerWithPlatformFeatures::GetLayoutId() const { if (auto layout = m_owner->Layout()) @@ -556,3 +982,41 @@ winrt::hstring ViewportManagerWithPlatformFeatures::GetLayoutId() const return winrt::hstring{}; } + +#ifdef DBG +void ViewportManagerWithPlatformFeatures::TraceFieldsDbg() +{ + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_expectedViewportShift:", m_expectedViewportShift.X, m_expectedViewportShift.Y); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_pendingViewportShift:", m_pendingViewportShift.X, m_pendingViewportShift.Y); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_unshiftableShift:", m_unshiftableShift.X, m_unshiftableShift.Y); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_visibleWindow:", m_visibleWindow.X, m_visibleWindow.Y, m_visibleWindow.Width, m_visibleWindow.Height); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_lastLayoutRealizationWindow:", m_lastLayoutRealizationWindow.X, m_lastLayoutRealizationWindow.Y, m_lastLayoutRealizationWindow.Width, m_lastLayoutRealizationWindow.Height); + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT, METH_NAME, this, + GetLayoutId().data(), L"m_layoutExtent:", m_layoutExtent.X, m_layoutExtent.Y, m_layoutExtent.Width, m_layoutExtent.Height); +} + +void ViewportManagerWithPlatformFeatures::TraceScrollerDbg() +{ + if (const auto scrollViewerDbg = m_scroller.try_as()) + { + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_DBL_DBL, METH_NAME, this, + GetLayoutId().data(), L"ScrollViewer Offsets:", scrollViewerDbg.HorizontalOffset(), scrollViewerDbg.VerticalOffset()); + + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_DBL_DBL, METH_NAME, this, + GetLayoutId().data(), L"ScrollViewer Scrollable Sizes:", scrollViewerDbg.ScrollableWidth(), scrollViewerDbg.ScrollableHeight()); + } + else if (const auto scrollPresenterDbg = m_scroller.try_as()) + { + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_DBL_DBL, METH_NAME, this, + GetLayoutId().data(), L"ScrollPresenter Offsets:", scrollPresenterDbg.HorizontalOffset(), scrollPresenterDbg.VerticalOffset()); + + ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_STR_STR_DBL_DBL, METH_NAME, this, + GetLayoutId().data(), L"ScrollPresenter Scrollable Sizes:", scrollPresenterDbg.ScrollableWidth(), scrollPresenterDbg.ScrollableHeight()); + } +} +#endif // DBG diff --git a/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.h b/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.h index 4a36ae2653..2f7b95c755 100644 --- a/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.h +++ b/src/controls/dev/Repeater/ViewportManagerWithPlatformFeatures.h @@ -4,15 +4,14 @@ #pragma once #include "ViewportManager.h" +#include "ScrollingViewChangingEventArgs.h" class ItemsRepeater; -// Manages the virtualization windows (visible/realization). This class essentially is -// does the equivalent behavior as ViewportManager class except that here we use +// Manages the virtualization windows (visible/realization). This class essentially +// does the equivalent behavior of ViewportManager class except that here we use // EffectiveViewport and ScrollAnchoring features added to the framework in RS5. // We also do not use the IRepeaterScrollingSurface internal API used by ViewManager. -// Not that this class is used when built in the OS build (under wuxc) and ViewManager -// is used when building in MUX to keep down level support. class ViewportManagerWithPlatformFeatures : public ViewportManager { public: @@ -29,7 +28,7 @@ class ViewportManagerWithPlatformFeatures : public ViewportManager winrt::Rect GetLayoutVisibleWindow() const override; winrt::Rect GetLayoutRealizationWindow() const override; - void SetLayoutExtent(winrt::Rect extent) override; + void SetLayoutExtent(const winrt::Rect& layoutExtent) override; winrt::Rect GetLayoutExtent() const override { return m_layoutExtent; } winrt::Point GetOrigin() const override { return winrt::Point(m_layoutExtent.X, m_layoutExtent.Y); } @@ -39,8 +38,9 @@ class ViewportManagerWithPlatformFeatures : public ViewportManager void OnOwnerMeasuring() override; void OnOwnerArranged() override; void OnMakeAnchor(const winrt::UIElement& anchor, const bool isAnchorOutsideRealizedRange) override; - void OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs args) override; + void OnBringIntoViewRequested(const winrt::BringIntoViewRequestedEventArgs& args) override; + void ResetLayoutRealizationWindowCacheBuffer() override; void ResetScrollers() override; winrt::UIElement MadeAnchor() const override { return m_makeAnchorElement.get(); } @@ -48,33 +48,60 @@ class ViewportManagerWithPlatformFeatures : public ViewportManager private: struct ScrollerInfo; + void SetVisibleWindow(const winrt::Rect& visibleWindow); + void SetPendingViewportShift(const winrt::Point& pendingViewportShift); + void SetExpectedViewportShift(float expectedViewportShiftX, float expectedViewportShiftY); + void SetUnshiftableShift(float unshiftableShiftX, float unshiftableShiftY); + + void ResetLayoutExtent(); + void ResetVisibleWindow(); + void ResetExpectedViewportShift(); + void ResetPendingViewportShift(); + void ResetUnshiftableShift(); + void OnCacheBuildActionCompleted(); void OnEffectiveViewportChanged(winrt::FrameworkElement const& sender, winrt::EffectiveViewportChangedEventArgs const& args); void OnLayoutUpdated(winrt::IInspectable const& sender, winrt::IInspectable const& args); + void OnScrollPresenterViewChanging(winrt::ScrollPresenter const& scrollPresenter, winrt::ScrollingViewChangingEventArgs const& args); void EnsureScroller(); bool HasScroller() const { return m_scroller != nullptr; } - void UpdateViewport(winrt::Rect const& args); - void ResetCacheBuffer(); + bool UpdateViewport(winrt::Rect const& effectiveViewport); + void ResetCacheBuffer(bool registerCacheBuildWork = true); void ValidateCacheLength(double cacheLength); + void RegisterPreparedElementsAsArranged(); + void RegisterPreparedAndArrangedElementsAsScrollAnchorCandidates(); void RegisterCacheBuildWork(); void TryInvalidateMeasure(); + void UnregisterScrollAnchorCandidates(winrt::UIElement const& exceptionElement, bool registerAsPreparedAndArrangedElements); winrt::Rect GetLayoutVisibleWindowDiscardAnchor() const; winrt::hstring GetLayoutId() const; void OnCompositionTargetRendering(winrt::IInspectable const& sender, winrt::IInspectable const& args); winrt::UIElement GetImmediateChildOfRepeater(winrt::UIElement const& descendant); +#ifdef DBG + void TraceFieldsDbg(); + void TraceScrollerDbg(); +#endif // DBG + ItemsRepeater* m_owner{ nullptr }; bool m_ensuredScroller{ false }; tracker_ref m_scroller; + std::vector> m_preparedElements; + std::vector> m_preparedAndArrangedElements; + tracker_ref m_makeAnchorElement; bool m_isAnchorOutsideRealizedRange{}; // Value is only valid when m_makeAnchorElement is set. + bool m_skipScrollAnchorRegistrationsDuringNextMeasurePass{}; + bool m_skipScrollAnchorRegistrationsDuringNextArrangePass{}; + bool m_cacheBuildActionOutstanding{}; + winrt::Rect m_lastLayoutRealizationWindow{}; winrt::Rect m_visibleWindow{}; winrt::Rect m_layoutExtent{}; // This is the expected shift by the layout. @@ -85,11 +112,10 @@ class ViewportManagerWithPlatformFeatures : public ViewportManager winrt::Point m_pendingViewportShift{}; // Unshiftable shift amount that this view manager can // handle on its own to fake it to the layout as if the shift - // actually happened. This can happen in cases where no scrollviewer + // actually happened. This can happen in cases where no scroller // in the parent chain can scroll in the shift direction. winrt::Point m_unshiftableShift{}; - // Realization window cache fields double m_maximumHorizontalCacheLength{ 2.0 }; double m_maximumVerticalCacheLength{ 2.0 }; @@ -103,8 +129,8 @@ class ViewportManagerWithPlatformFeatures : public ViewportManager bool m_managingViewportDisabled{ false }; // Event tokens + winrt::ScrollPresenter::ViewChanging_revoker m_scrollPresenterViewChangingRevoker{}; winrt::FrameworkElement::EffectiveViewportChanged_revoker m_effectiveViewportChangedRevoker{}; - winrt::FrameworkElement::LayoutUpdated_revoker m_layoutUpdatedRevoker{}; winrt::Microsoft::UI::Xaml::Media::CompositionTarget::Rendering_revoker m_renderingToken{}; }; diff --git a/src/controls/dev/Repeater/VirtualizationInfo.cpp b/src/controls/dev/Repeater/VirtualizationInfo.cpp index a992528147..67686ee45d 100644 --- a/src/controls/dev/Repeater/VirtualizationInfo.cpp +++ b/src/controls/dev/Repeater/VirtualizationInfo.cpp @@ -25,9 +25,9 @@ bool VirtualizationInfo::IsHeldByLayout() const return m_owner == ElementOwner::Layout; } -bool VirtualizationInfo::IsRealized() const +bool VirtualizationInfo::IsInPinnedPool() const { - return IsHeldByLayout() || m_owner == ElementOwner::PinnedPool; + return m_owner == ElementOwner::PinnedPool; } bool VirtualizationInfo::IsInUniqueIdResetPool() const @@ -35,6 +35,11 @@ bool VirtualizationInfo::IsInUniqueIdResetPool() const return m_owner == ElementOwner::UniqueIdResetPool; } +bool VirtualizationInfo::IsRealized() const +{ + return IsHeldByLayout() || IsInPinnedPool(); +} + void VirtualizationInfo::UpdatePhasingInfo(int phase, const winrt::IInspectable& data, const winrt::IDataTemplateComponent& component) { m_phase = phase; @@ -98,7 +103,7 @@ void VirtualizationInfo::MoveOwnershipToLayoutFromPinnedPool() void VirtualizationInfo::MoveOwnershipToElementFactory() { #ifdef DBG - if (m_index == s_logItemIndexDbg) + if (m_index == s_logItemIndexDbg && !(m_owner == ElementOwner::Animator && m_index == -1)) { ITEMSREPEATER_TRACE_INFO(nullptr, TRACE_MSG_METH_INT, METH_NAME, this, s_logItemIndexDbg); MUX_ASSERT(s_logItemIndexDbg != -1); diff --git a/src/controls/dev/Repeater/VirtualizationInfo.h b/src/controls/dev/Repeater/VirtualizationInfo.h index 93100672d7..bca18f23a3 100644 --- a/src/controls/dev/Repeater/VirtualizationInfo.h +++ b/src/controls/dev/Repeater/VirtualizationInfo.h @@ -38,8 +38,9 @@ class VirtualizationInfo : public winrt::implements GetFileContents(const wstring_view& assetFileName); static winrt::IInspectable ResourceLookup(const winrt::Control& control, const winrt::IInspectable& key); diff --git a/src/controls/dev/SampleControl/InteractionTests/SampleControlTests.cs b/src/controls/dev/SampleControl/InteractionTests/SampleControlTests.cs deleted file mode 100644 index 9601d6d126..0000000000 --- a/src/controls/dev/SampleControl/InteractionTests/SampleControlTests.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -using System; -using Common; -using Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests.Infra; -using Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests.Common; -using System.Collections.Generic; - -using WEX.TestExecution; -using WEX.TestExecution.Markup; -using WEX.Logging.Interop; - -using Microsoft.Windows.Apps.Test.Automation; -using Microsoft.Windows.Apps.Test.Foundation; -using Microsoft.Windows.Apps.Test.Foundation.Controls; -using Microsoft.Windows.Apps.Test.Foundation.Patterns; -using Microsoft.Windows.Apps.Test.Foundation.Waiters; - -namespace Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests -{ - [TestClass] - public class SampleControlTests - { - [ClassInitialize] - [TestProperty("RunAs", "User")] - [TestProperty("Classification", "Integration")] - [TestProperty("Platform", "Any")] - public static void ClassInitialize(TestContext testContext) - { - TestEnvironment.Initialize(testContext, TestApplicationInfo.MUXExperimentalTestApp); - } - - [TestCleanup] - public void TestCleanup() - { - TestEnvironment.AssemblyCleanupWorker(TestApplicationInfo.MUXExperimentalTestApp); - } - - [TestMethod] - public void BasicTest() - { - Log.Comment("SampleControl Basic Test"); - using (var setup = new TestSetupHelper("SampleControl Tests")) - { - Log.Comment("Retrieve SampleControl as generic UIElement"); - UIObject sampleControl = FindElement.ByName("TestSampleControl"); - Verify.IsNotNull(sampleControl, "Verifying that we found a UIElement called TestSampleControl"); - } - } - } -} diff --git a/src/controls/dev/SampleControl/InteractionTests/SampleControl_InteractionTests.projitems b/src/controls/dev/SampleControl/InteractionTests/SampleControl_InteractionTests.projitems deleted file mode 100644 index a761e81ad9..0000000000 --- a/src/controls/dev/SampleControl/InteractionTests/SampleControl_InteractionTests.projitems +++ /dev/null @@ -1,15 +0,0 @@ - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - A1553559-5786-4B44-AB9E-94AB95C86D4D - - - SampleControl_InteractionTests - - - - - diff --git a/src/controls/dev/SampleControl/InteractionTests/SampleControl_InteractionTests.shproj b/src/controls/dev/SampleControl/InteractionTests/SampleControl_InteractionTests.shproj deleted file mode 100644 index f83ede1359..0000000000 --- a/src/controls/dev/SampleControl/InteractionTests/SampleControl_InteractionTests.shproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - {30120040-3EB8-404D-9344-5E99E34B6090} - 15.0 - - - - - - - - \ No newline at end of file diff --git a/src/controls/dev/SampleControl/SampleControl.cpp b/src/controls/dev/SampleControl/SampleControl.cpp deleted file mode 100644 index d86d50bdba..0000000000 --- a/src/controls/dev/SampleControl/SampleControl.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -#include "pch.h" -#include "common.h" -#include "SampleControl.h" -#include "ResourceAccessor.h" - -SampleControl::SampleControl() -{ - SetDefaultStyleKey(this); -} - -void SampleControl::OnApplyTemplate() -{ - winrt::IControlProtected controlProtected{ *this }; -} - -void SampleControl::OnPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args) -{ - winrt::IDependencyProperty property = args.Property(); -} diff --git a/src/controls/dev/SampleControl/SampleControl.h b/src/controls/dev/SampleControl/SampleControl.h deleted file mode 100644 index 4eac194ced..0000000000 --- a/src/controls/dev/SampleControl/SampleControl.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -#pragma once - -#include "pch.h" -#include "common.h" - -#include "SampleControl.g.h" -#include "SampleControl.properties.h" - -class SampleControl : - public ReferenceTracker, - public SampleControlProperties -{ - -public: - SampleControl(); - ~SampleControl() {} - - // IFrameworkElement - void OnApplyTemplate(); - - void OnPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args); -}; diff --git a/src/controls/dev/SampleControl/SampleControl.idl b/src/controls/dev/SampleControl/SampleControl.idl deleted file mode 100644 index a39c6071f2..0000000000 --- a/src/controls/dev/SampleControl/SampleControl.idl +++ /dev/null @@ -1,17 +0,0 @@ -namespace MEU_XC_NAMESPACE -{ - -[MUX_EXPERIMENTAL] -[webhosthidden] -[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)] -[MUX_PROPERTY_CHANGED_CALLBACK_METHODNAME("OnPropertyChanged")] -unsealed runtimeclass SampleControl : Microsoft.UI.Xaml.Controls.Control -{ - SampleControl(); - - Object Placeholder{ get; set; }; - - static Microsoft.UI.Xaml.DependencyProperty PlaceholderProperty{ get; }; -} - -} diff --git a/src/controls/dev/SampleControl/SampleControl.vcxitems b/src/controls/dev/SampleControl/SampleControl.vcxitems deleted file mode 100644 index 58b0f40922..0000000000 --- a/src/controls/dev/SampleControl/SampleControl.vcxitems +++ /dev/null @@ -1,39 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - {A329FB8A-3093-4050-83D3-4D9F5847F3B8} - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - %(PreprocessorDefinitions);SAMPLECONTROL_INCLUDED - - - - - - - - - - - - - - - Any - RS1 - DefaultStyle - - - Any - RS1 - ThemeResources - - - - - - \ No newline at end of file diff --git a/src/controls/dev/SampleControl/SampleControl.xaml b/src/controls/dev/SampleControl/SampleControl.xaml deleted file mode 100644 index acc1dfde6c..0000000000 --- a/src/controls/dev/SampleControl/SampleControl.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/controls/dev/SampleControl/SampleControl_themeresources.xaml b/src/controls/dev/SampleControl/SampleControl_themeresources.xaml deleted file mode 100644 index b7c10c05d9..0000000000 --- a/src/controls/dev/SampleControl/SampleControl_themeresources.xaml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/src/controls/dev/SampleControl/TestUI/SampleControlPage.xaml b/src/controls/dev/SampleControl/TestUI/SampleControlPage.xaml deleted file mode 100644 index 88fd2a3e4c..0000000000 --- a/src/controls/dev/SampleControl/TestUI/SampleControlPage.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - diff --git a/src/controls/dev/SampleControl/TestUI/SampleControl_TestUI.projitems b/src/controls/dev/SampleControl/TestUI/SampleControl_TestUI.projitems deleted file mode 100644 index 950b9cd7c5..0000000000 --- a/src/controls/dev/SampleControl/TestUI/SampleControl_TestUI.projitems +++ /dev/null @@ -1,23 +0,0 @@ - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - 280C91F4-96B5-4BDE-9E02-E573E1DEF583 - - - SampleControl_TestUI - - - - Designer - MSBuild:Compile - - - - - SampleControlPage.xaml - - - diff --git a/src/controls/dev/SampleControl/TestUI/SampleControl_TestUI.shproj b/src/controls/dev/SampleControl/TestUI/SampleControl_TestUI.shproj deleted file mode 100644 index 915f617982..0000000000 --- a/src/controls/dev/SampleControl/TestUI/SampleControl_TestUI.shproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - {05361409-7FBB-4296-996F-2E591857D84A} - 15.0 - - - - - - - - \ No newline at end of file diff --git a/src/controls/dev/ScrollPresenter/APITests/ScrollControllerTests.cs b/src/controls/dev/ScrollPresenter/APITests/ScrollControllerTests.cs index a82d40dcbe..afb4cedf36 100644 --- a/src/controls/dev/ScrollPresenter/APITests/ScrollControllerTests.cs +++ b/src/controls/dev/ScrollPresenter/APITests/ScrollControllerTests.cs @@ -126,7 +126,7 @@ public void ChangeOffsetsWhileScrollControllersAreAttached() (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 2.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: true, + hookViewChangingAndChanged: true, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 2.0, expectedFinalVerticalOffset: (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 2.0); @@ -138,7 +138,7 @@ public void ChangeOffsetsWhileScrollControllersAreAttached() (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 4.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false, + hookViewChangingAndChanged: false, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 4.0, expectedFinalVerticalOffset: (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 4.0); @@ -151,7 +151,7 @@ public void ChangeOffsetsWhileScrollControllersAreAttached() 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false); + hookViewChangingAndChanged: false); Log.Comment("Animate to zoomFactor 1.5"); ZoomTo( @@ -161,7 +161,7 @@ public void ChangeOffsetsWhileScrollControllersAreAttached() 0.0f, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false); + hookViewChangingAndChanged: false); } [TestMethod] @@ -477,7 +477,7 @@ public void ChangeOffsetsWhileBiDirectionalScrollControllerIsAttached() (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 2.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: true, + hookViewChangingAndChanged: true, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 2.0, expectedFinalVerticalOffset: (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 2.0); @@ -489,7 +489,7 @@ public void ChangeOffsetsWhileBiDirectionalScrollControllerIsAttached() (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 4.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false, + hookViewChangingAndChanged: false, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 4.0, expectedFinalVerticalOffset: (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 4.0); @@ -502,7 +502,7 @@ public void ChangeOffsetsWhileBiDirectionalScrollControllerIsAttached() 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false); + hookViewChangingAndChanged: false); Log.Comment("Animate to zoomFactor 1.5"); ZoomTo( @@ -512,7 +512,7 @@ public void ChangeOffsetsWhileBiDirectionalScrollControllerIsAttached() 0.0f, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false); + hookViewChangingAndChanged: false); } [TestMethod] diff --git a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterAnchoringTests.cs b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterAnchoringTests.cs index a3ea8c97a0..a1066ab169 100644 --- a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterAnchoringTests.cs +++ b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterAnchoringTests.cs @@ -166,7 +166,7 @@ private void AnchoringAtFarEdgeWhileIncreasingContent(Orientation orientation, d } }); - ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChanged*/); + ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChangingAndChanged*/); RunOnUIThread.Execute(() => { @@ -282,7 +282,7 @@ private void AnchoringAtFarEdgeWhileDecreasingViewport(Orientation orientation) } }); - ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChanged*/); + ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChangingAndChanged*/); RunOnUIThread.Execute(() => { @@ -461,7 +461,7 @@ private void AnchoringAtAlmostFarEdge(Orientation orientation) } }); - ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChanged*/); + ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChangingAndChanged*/); RunOnUIThread.Execute(() => { @@ -542,7 +542,7 @@ private void AnchoringElementWithResizedViewport(Orientation orientation, double } }); - ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChanged*/); + ScrollTo(scrollPresenter, horizontalOffset, verticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChangingAndChanged*/); RunOnUIThread.Execute(() => { @@ -834,7 +834,7 @@ public void AnchoringAtRepeaterMiddle() WaitForEvent("Waiting for Loaded event", scrollPresenterLoadedEvent); ZoomTo(scrollPresenter, 2.0f, 0.0f, 0.0f, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore); - ScrollTo(scrollPresenter, 0.0, 250.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChanged*/); + ScrollTo(scrollPresenter, 0.0, 250.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, false /*hookViewChangingAndChanged*/); ItemsRepeater repeater = null; TestDataSource dataSource = null; diff --git a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterBringIntoViewTests.cs b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterBringIntoViewTests.cs index 400702a29d..b57ded51ec 100644 --- a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterBringIntoViewTests.cs +++ b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterBringIntoViewTests.cs @@ -655,7 +655,7 @@ private void BringElementIntoView( if (originalHorizontalOffset != 0 || originalVerticalOffset != 0) { - ScrollTo(scrollPresenter, originalHorizontalOffset, originalVerticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, originalZoomFactor == 1.0f /*hookViewChanged*/); + ScrollTo(scrollPresenter, originalHorizontalOffset, originalVerticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, originalZoomFactor == 1.0f /*hookViewChangingAndChanged*/); } RunOnUIThread.Execute(() => @@ -782,7 +782,7 @@ private void BringElementInNestedScrollPresentersIntoView( if (originalOuterHorizontalOffset != 0 || originalOuterVerticalOffset != 0) { - ScrollTo(outerScrollPresenter, originalOuterHorizontalOffset, originalOuterVerticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, originalOuterZoomFactor == 1.0f /*hookViewChanged*/); + ScrollTo(outerScrollPresenter, originalOuterHorizontalOffset, originalOuterVerticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, originalOuterZoomFactor == 1.0f /*hookViewChangingAndChanged*/); } if (originalInnerZoomFactor != 1.0f) @@ -792,7 +792,7 @@ private void BringElementInNestedScrollPresentersIntoView( if (originalInnerHorizontalOffset != 0 || originalInnerVerticalOffset != 0) { - ScrollTo(innerScrollPresenter, originalInnerHorizontalOffset, originalInnerVerticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, originalInnerZoomFactor == 1.0f /*hookViewChanged*/); + ScrollTo(innerScrollPresenter, originalInnerHorizontalOffset, originalInnerVerticalOffset, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, originalInnerZoomFactor == 1.0f /*hookViewChangingAndChanged*/); } RunOnUIThread.Execute(() => diff --git a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterLayoutTests.cs b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterLayoutTests.cs index f21be57eb2..3409a5d078 100644 --- a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterLayoutTests.cs +++ b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterLayoutTests.cs @@ -63,7 +63,7 @@ public void BasicMargin() c_defaultUIScrollPresenterContentHeight + 2 * c_Margin - c_defaultUIScrollPresenterHeight + 10.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: true, + hookViewChangingAndChanged: true, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: c_defaultUIScrollPresenterContentWidth + 2 * c_Margin - c_defaultUIScrollPresenterWidth, expectedFinalVerticalOffset: c_defaultUIScrollPresenterContentHeight + 2 * c_Margin - c_defaultUIScrollPresenterHeight); @@ -83,7 +83,7 @@ public void BasicMargin() c_defaultUIScrollPresenterContentHeight - 2 * c_Margin - c_defaultUIScrollPresenterHeight + 10.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false, + hookViewChangingAndChanged: false, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: c_defaultUIScrollPresenterContentWidth - 2 * c_Margin - c_defaultUIScrollPresenterWidth, expectedFinalVerticalOffset: c_defaultUIScrollPresenterContentHeight - 2 * c_Margin - c_defaultUIScrollPresenterHeight); @@ -128,7 +128,7 @@ public void BasicPadding() c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight + 10.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: true, + hookViewChangingAndChanged: true, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth, expectedFinalVerticalOffset: c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight); @@ -592,7 +592,7 @@ public void ImageWithUnnaturalSize() c_UnnaturalImageHeight - c_defaultUIScrollPresenterHeight + 10.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: true, + hookViewChangingAndChanged: true, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: c_UnnaturalImageWidth - c_defaultUIScrollPresenterWidth, expectedFinalVerticalOffset: c_UnnaturalImageHeight - c_defaultUIScrollPresenterHeight); @@ -739,7 +739,7 @@ public void ImageWithConstrainedWidth() expectedZoomFactor: c_smallZoomFactor); // Jump to absolute large zoomFactor to make the content larger than the viewport. - ZoomTo(scrollPresenter, c_largeZoomFactor, 0.0f, 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); + ZoomTo(scrollPresenter, c_largeZoomFactor, 0.0f, 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); ValidateContentWithConstrainedWidth( compositor, @@ -933,7 +933,7 @@ public void ImageWithConstrainedHeight() expectedZoomFactor: c_smallZoomFactor); // Jump to absolute large zoomFactor to make the content larger than the viewport. - ZoomTo(scrollPresenter, c_largeZoomFactor, 0.0f, 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); + ZoomTo(scrollPresenter, c_largeZoomFactor, 0.0f, 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); ValidateContentWithConstrainedHeight( compositor, @@ -1045,7 +1045,7 @@ public void ImageWithConstrainedSize() expectedZoomFactor: c_smallZoomFactor); // Jump to absolute large zoomFactor to make the content larger than the viewport. - ZoomTo(scrollPresenter, c_largeZoomFactor, 0.0f, 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); + ZoomTo(scrollPresenter, c_largeZoomFactor, 0.0f, 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); ValidateContentWithConstrainedSize( compositor, @@ -1086,7 +1086,7 @@ public void RightToLeftFlowDirection() 17.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: true, + hookViewChangingAndChanged: true, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: 11.0, expectedFinalVerticalOffset: 17.0); @@ -1099,7 +1099,7 @@ public void RightToLeftFlowDirection() 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false); + hookViewChangingAndChanged: false); IdleSynchronizer.Wait(); @@ -1133,7 +1133,7 @@ public void RightToLeftFlowDirection() 13.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false, + hookViewChangingAndChanged: false, isAnimationsEnabledOverride: null, expectedFinalHorizontalOffset: 7.0, expectedFinalVerticalOffset: 13.0); @@ -1146,7 +1146,7 @@ public void RightToLeftFlowDirection() 0.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, - hookViewChanged: false); + hookViewChangingAndChanged: false); IdleSynchronizer.Wait(); diff --git a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterSnapPointTests.cs b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterSnapPointTests.cs index 3c334e7f00..396068e9aa 100644 --- a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterSnapPointTests.cs +++ b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterSnapPointTests.cs @@ -310,7 +310,7 @@ public void SnapToFirstRepeatedScrollSnapPoint() }); // Flick with horizontal offset velocity to naturally land around offset 15. - AddScrollVelocity(scrollPresenter, horizontalVelocity: -165.0f, verticalVelocity: 0.0f, horizontalInertiaDecayRate: null, verticalInertiaDecayRate: null, hookViewChanged: false); + AddScrollVelocity(scrollPresenter, horizontalVelocity: -165.0f, verticalVelocity: 0.0f, horizontalInertiaDecayRate: null, verticalInertiaDecayRate: null, hookViewChangingAndChanged: false); RunOnUIThread.Execute(() => { @@ -365,7 +365,7 @@ public void SnapToFirstRepeatedZoomSnapPoint() inertiaDecayRate: 0.6675f, centerPointX: 150.0f, centerPointY: 100.0f, - hookViewChanged: false); + hookViewChangingAndChanged: false); RunOnUIThread.Execute(() => { diff --git a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterTests.cs b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterTests.cs index 301e86ded3..4dcdf283d1 100644 --- a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterTests.cs +++ b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterTests.cs @@ -707,7 +707,7 @@ public void ListenToContentEffectiveViewportChanged() verticalOffset: 150, animationMode: ScrollingAnimationMode.Enabled, snapPointsMode: ScrollingSnapPointsMode.Ignore, - hookViewChanged: false); + hookViewChangingAndChanged: false); RunOnUIThread.Execute(() => { diff --git a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterViewChangeTests.cs b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterViewChangeTests.cs index c5ace6c501..c7f60e037f 100644 --- a/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterViewChangeTests.cs +++ b/src/controls/dev/ScrollPresenter/APITests/ScrollPresenterViewChangeTests.cs @@ -38,6 +38,7 @@ private enum ViewChangeInterruptionKind private const int c_MaxStockOffsetsChangeDuration = 1000; private const int c_MaxStockZoomFactorChangeDuration = 1000; + private uint viewChangingCount = 0u; private uint viewChangedCount = 0u; [TestMethod] @@ -60,37 +61,37 @@ public void BasicOffsetChanges() // Jump to absolute offsets ScrollTo(scrollPresenter, 11.0, 22.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore); - ScrollTo(scrollPresenter, 22.0, 11.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: false); + ScrollTo(scrollPresenter, 22.0, 11.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: false); // Jump to relative offsets - ScrollBy(scrollPresenter, -4.0, 15.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); - ScrollBy(scrollPresenter, 15.0, 4.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: false); + ScrollBy(scrollPresenter, -4.0, 15.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); + ScrollBy(scrollPresenter, 15.0, 4.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: false); // Animate to absolute offsets - ScrollTo(scrollPresenter, 55.0, 25.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); - ScrollTo(scrollPresenter, 5.0, 75.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: true); + ScrollTo(scrollPresenter, 55.0, 25.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); + ScrollTo(scrollPresenter, 5.0, 75.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: true); // Jump or animate to absolute offsets based on UISettings.AnimationsEnabled - ScrollTo(scrollPresenter, 55.0, 25.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); + ScrollTo(scrollPresenter, 55.0, 25.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); // Animate to relative offsets - ScrollBy(scrollPresenter, 700.0, -8.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); - ScrollBy(scrollPresenter, -80.0, 200.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: true); + ScrollBy(scrollPresenter, 700.0, -8.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); + ScrollBy(scrollPresenter, -80.0, 200.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: true); // Jump or animate to relative offsets based on UISettings.AnimationsEnabled - ScrollBy(scrollPresenter, 80.0, -200.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); + ScrollBy(scrollPresenter, 80.0, -200.0, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); // Flick with additional offsets velocity - AddScrollVelocity(scrollPresenter, horizontalVelocity: -65.0f, verticalVelocity: 80.0f, horizontalInertiaDecayRate: null, verticalInertiaDecayRate: null, hookViewChanged: false); + AddScrollVelocity(scrollPresenter, horizontalVelocity: -65.0f, verticalVelocity: 80.0f, horizontalInertiaDecayRate: null, verticalInertiaDecayRate: null, hookViewChangingAndChanged: false); // Flick with additional offsets velocity and custom scroll inertia decay rate - AddScrollVelocity(scrollPresenter, horizontalVelocity: 65.0f, verticalVelocity: -80.0f, horizontalInertiaDecayRate: 0.7f, verticalInertiaDecayRate: 0.8f, hookViewChanged: false); + AddScrollVelocity(scrollPresenter, horizontalVelocity: 65.0f, verticalVelocity: -80.0f, horizontalInertiaDecayRate: 0.7f, verticalInertiaDecayRate: 0.8f, hookViewChangingAndChanged: false); // Do it all again while respecting snap points - ScrollTo(scrollPresenter, 11.0, 22.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Default, hookViewChanged: false); - ScrollBy(scrollPresenter, -4.0, 15.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Default, hookViewChanged: false); - ScrollTo(scrollPresenter, 55.0, 25.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Default, hookViewChanged: false); - ScrollBy(scrollPresenter, 700.0, -8.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Default, hookViewChanged: false); + ScrollTo(scrollPresenter, 11.0, 22.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Default, hookViewChangingAndChanged: false); + ScrollBy(scrollPresenter, -4.0, 15.0, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Default, hookViewChangingAndChanged: false); + ScrollTo(scrollPresenter, 55.0, 25.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Default, hookViewChangingAndChanged: false); + ScrollBy(scrollPresenter, 700.0, -8.0, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Default, hookViewChangingAndChanged: false); } [TestMethod] @@ -113,31 +114,31 @@ public void BasicZoomFactorChanges() // Jump to absolute zoomFactor ZoomTo(scrollPresenter, 2.0f, 22.0f, 33.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore); - ZoomTo(scrollPresenter, 5.0f, 33.0f, 22.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: false); + ZoomTo(scrollPresenter, 5.0f, 33.0f, 22.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: false); // Jump to relative zoomFactor - ZoomBy(scrollPresenter, 1.0f, 55.0f, 66.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); - ZoomBy(scrollPresenter, 1.0f, 66.0f, 55.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: false); + ZoomBy(scrollPresenter, 1.0f, 55.0f, 66.0f, ScrollingAnimationMode.Disabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); + ZoomBy(scrollPresenter, 1.0f, 66.0f, 55.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: false); // Animate to absolute zoomFactor - ZoomTo(scrollPresenter, 4.0f, -40.0f, -25.0f, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); - ZoomTo(scrollPresenter, 6.0f, 25.0f, 40.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: true); + ZoomTo(scrollPresenter, 4.0f, -40.0f, -25.0f, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); + ZoomTo(scrollPresenter, 6.0f, 25.0f, 40.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: true); // Jump or animate to absolute zoomFactor based on UISettings.AnimationsEnabled - ZoomTo(scrollPresenter, 3.0f, 10.0f, 20.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); + ZoomTo(scrollPresenter, 3.0f, 10.0f, 20.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); // Animate to relative zoomFactor - ZoomBy(scrollPresenter, -2.0f, 100.0f, 200.0f, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); - ZoomBy(scrollPresenter, 1.0f, 100.0f, 200.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: true); + ZoomBy(scrollPresenter, -2.0f, 100.0f, 200.0f, ScrollingAnimationMode.Enabled, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); + ZoomBy(scrollPresenter, 1.0f, 100.0f, 200.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false, isAnimationsEnabledOverride: true); // Jump or animate to relative zoomFactor based on UISettings.AnimationsEnabled - ZoomBy(scrollPresenter, 2.0f, 200.0f, 100.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChanged: false); + ZoomBy(scrollPresenter, 2.0f, 200.0f, 100.0f, ScrollingAnimationMode.Auto, ScrollingSnapPointsMode.Ignore, hookViewChangingAndChanged: false); // Flick with additional zoomFactor velocity - AddZoomVelocity(scrollPresenter, zoomFactorVelocity: 2.0f, inertiaDecayRate: null, centerPointX: -50.0f, centerPointY: 800.0f, waitForViewChangeCompletion: true, hookViewChanged: false); + AddZoomVelocity(scrollPresenter, zoomFactorVelocity: 2.0f, inertiaDecayRate: null, centerPointX: -50.0f, centerPointY: 800.0f, waitForViewChangeCompletion: true, hookViewChangingAndChanged: false); // Flick with additional zoomFactor velocity and custom zoomFactor inertia decay rate - AddZoomVelocity(scrollPresenter, zoomFactorVelocity: -2.0f, inertiaDecayRate: 0.75f, centerPointX: -50.0f, centerPointY: 800.0f, waitForViewChangeCompletion: true, hookViewChanged: false); + AddZoomVelocity(scrollPresenter, zoomFactorVelocity: -2.0f, inertiaDecayRate: 0.75f, centerPointX: -50.0f, centerPointY: 800.0f, waitForViewChangeCompletion: true, hookViewChangingAndChanged: false); } [TestMethod] @@ -194,13 +195,13 @@ public void SuccessiveAdditionalScrollVelocities() WaitForEvent("Waiting for Loaded event", scrollPresenterLoadedEvent); // Add scroll velocity with very small inertia decay rate - AddScrollVelocity(scrollPresenter, horizontalVelocity: 50.0f, verticalVelocity: 60.0f, horizontalInertiaDecayRate: 0.0007f, verticalInertiaDecayRate: 0.0008f, waitForViewChangeCompletion: false, hookViewChanged: false); + AddScrollVelocity(scrollPresenter, horizontalVelocity: 50.0f, verticalVelocity: 60.0f, horizontalInertiaDecayRate: 0.0007f, verticalInertiaDecayRate: 0.0008f, waitForViewChangeCompletion: false, hookViewChangingAndChanged: false); // Waiting for first view changed event WaitForEvent("Waiting for first ViewChanged event", scrollPresenterViewChangedEvent); // Add scroll velocity with default inertia decay rate - AddScrollVelocity(scrollPresenter, horizontalVelocity: 170.0f, verticalVelocity: 180.0f, horizontalInertiaDecayRate: null, verticalInertiaDecayRate: null, waitForViewChangeCompletion: false, hookViewChanged: false); + AddScrollVelocity(scrollPresenter, horizontalVelocity: 170.0f, verticalVelocity: 180.0f, horizontalInertiaDecayRate: null, verticalInertiaDecayRate: null, waitForViewChangeCompletion: false, hookViewChangingAndChanged: false); // Waiting for first view change completion WaitForEvent("Waiting for first view change completion", scrollPresenterViewChangeOperationEvent1); @@ -272,13 +273,13 @@ public void SuccessiveAdditionalZoomVelocities() WaitForEvent("Waiting for Loaded event", scrollPresenterLoadedEvent); // Add zoomFactor velocity with very small inertia decay rate - AddZoomVelocity(scrollPresenter, zoomFactorVelocity: 0.4f, inertiaDecayRate: 0.0001f, centerPointX: 0.0f, centerPointY: 0.0f, waitForViewChangeCompletion: false, hookViewChanged: false); + AddZoomVelocity(scrollPresenter, zoomFactorVelocity: 0.4f, inertiaDecayRate: 0.0001f, centerPointX: 0.0f, centerPointY: 0.0f, waitForViewChangeCompletion: false, hookViewChangingAndChanged: false); // Waiting for first view changed event WaitForEvent("Waiting for first ViewChanged event", scrollPresenterViewChangedEvent); // Add zoomFactor velocity with default inertia decay rate - AddZoomVelocity(scrollPresenter, zoomFactorVelocity: 0.6f, inertiaDecayRate: null, centerPointX: 0.0f, centerPointY: 0.0f, waitForViewChangeCompletion: false, hookViewChanged: false); + AddZoomVelocity(scrollPresenter, zoomFactorVelocity: 0.6f, inertiaDecayRate: null, centerPointX: 0.0f, centerPointY: 0.0f, waitForViewChangeCompletion: false, hookViewChangingAndChanged: false); // Waiting for first view change completion WaitForEvent("Waiting for first view change completion", scrollPresenterViewChangeOperationEvent1); @@ -525,6 +526,11 @@ public void OffsetsChangeWithCustomDuration() RunOnUIThread.Execute(() => { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -555,12 +561,14 @@ public void OffsetsChangeWithCustomDuration() RunOnUIThread.Execute(() => { Log.Comment($"Final HorizontalOffset={scrollPresenter.HorizontalOffset}, VerticalOffset={scrollPresenter.VerticalOffset}, ZoomFactor={scrollPresenter.ZoomFactor}"); + Log.Comment($"Final viewChangingCount={viewChangingCount}"); Log.Comment($"Final viewChangedCount={viewChangedCount}"); Verify.AreEqual(600.0, scrollPresenter.HorizontalOffset); Verify.AreEqual(400.0, scrollPresenter.VerticalOffset); Verify.AreEqual(1.0f, scrollPresenter.ZoomFactor); + Verify.AreEqual(0u, viewChangingCount); Verify.IsLessThanOrEqual(viewChangedCount, 2u); Verify.AreEqual(ScrollPresenterViewChangeResult.Completed, operation.Result); @@ -592,6 +600,11 @@ public void ZoomFactorChangeWithCustomDuration() RunOnUIThread.Execute(() => { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -623,13 +636,16 @@ public void ZoomFactorChangeWithCustomDuration() RunOnUIThread.Execute(() => { Log.Comment($"Final HorizontalOffset={scrollPresenter.HorizontalOffset}, VerticalOffset={scrollPresenter.VerticalOffset}, ZoomFactor={scrollPresenter.ZoomFactor}"); + Log.Comment($"Final viewChangingCount={viewChangingCount}"); Log.Comment($"Final viewChangedCount={viewChangedCount}"); Verify.IsLessThan(Math.Abs(scrollPresenter.HorizontalOffset - 700.0), 0.01); Verify.IsLessThan(Math.Abs(scrollPresenter.VerticalOffset - 1050.0), 0.01); Verify.AreEqual(8.0f, scrollPresenter.ZoomFactor); + Verify.AreEqual(0u, viewChangingCount); Verify.IsLessThanOrEqual(viewChangedCount, 2u); + Verify.AreEqual(ScrollPresenterViewChangeResult.Completed, operation.Result); }); } @@ -657,6 +673,11 @@ public void InterruptViewChangeWithUnloading() RunOnUIThread.Execute(() => { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -838,6 +859,11 @@ private void ConsecutiveOffsetJumps(bool waitForFirstCompletion) operations = new ScrollPresenterOperation[3]; + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -957,6 +983,11 @@ private void ConsecutiveZoomFactorJumps(bool isFirstZoomRelative, bool isSecondZ operations = new ScrollPresenterOperation[3]; + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1099,6 +1130,11 @@ private void ConsecutiveScrollAndZoomJumps(bool isScrollRelative, bool isZoomRel operations = new ScrollPresenterOperation[2]; + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1216,6 +1252,11 @@ private void ConsecutiveZoomAndScrollJumps(bool isZoomRelative, bool isScrollRel operations = new ScrollPresenterOperation[2]; + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1376,6 +1417,11 @@ private void ChangeOffsetsBeforeLoading(bool animate) SetupDefaultUI(scrollPresenter, rectangleScrollPresenterContent, scrollPresenterLoadedEvent, false /*setAsContentRoot*/); + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1424,6 +1470,11 @@ private void ChangeZoomFactorBeforeLoading(bool animate) SetupDefaultUI(scrollPresenter, rectangleScrollPresenterContent, scrollPresenterLoadedEvent, false /*setAsContentRoot*/); + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1464,7 +1515,7 @@ private void ScrollTo( double verticalOffset, ScrollingAnimationMode animationMode, ScrollingSnapPointsMode snapPointsMode, - bool hookViewChanged = true, + bool hookViewChangingAndChanged = true, bool? isAnimationsEnabledOverride = null, double? expectedFinalHorizontalOffset = null, double? expectedFinalVerticalOffset = null) @@ -1478,6 +1529,9 @@ private void ScrollTo( Log.Comment("Waiting for any pending ExpressionAnimation start/stop notifications to occur"); CompositionPropertySpy.SynchronouslyTickUIThread(6); + double? anticipatedHorizontalOffset = null; + double? anticipatedVerticalOffset = null; + float? anticipatedZoomFactor = null; float originalZoomFactor = 1.0f; AutoResetEvent scrollPresenterViewChangeOperationEvent = new AutoResetEvent(false); ScrollPresenterOperation operation = null; @@ -1486,8 +1540,16 @@ private void ScrollTo( { scrollPresenterTestHooksHelper.ResetExpressionAnimationStatusChanges(scrollPresenter); - if (hookViewChanged) + if (hookViewChangingAndChanged) { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + anticipatedHorizontalOffset = args.HorizontalOffset; + anticipatedVerticalOffset = args.VerticalOffset; + anticipatedZoomFactor = args.ZoomFactor; + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1520,6 +1582,7 @@ private void ScrollTo( RunOnUIThread.Execute(() => { Log.Comment($"Final HorizontalOffset={scrollPresenter.HorizontalOffset}, VerticalOffset={scrollPresenter.VerticalOffset}, ZoomFactor={scrollPresenter.ZoomFactor}"); + Log.Comment($"Final viewChangingCount={viewChangingCount}"); Log.Comment($"Final viewChangedCount={viewChangedCount}"); Verify.AreEqual(expectedFinalHorizontalOffset, scrollPresenter.HorizontalOffset); @@ -1529,11 +1592,19 @@ private void ScrollTo( if (GetEffectiveIsAnimationEnabled(animationMode, isAnimationsEnabledOverride)) { + Verify.AreEqual(0u, viewChangingCount); Verify.IsFalse(viewChangedCount == 1u); } else { + Verify.IsLessThanOrEqual(viewChangingCount, 1u); Verify.IsLessThanOrEqual(viewChangedCount, 1u); + if (anticipatedHorizontalOffset != null && anticipatedVerticalOffset != null && anticipatedZoomFactor != null) + { + Verify.IsLessThan(Math.Abs((double)anticipatedHorizontalOffset - (double)expectedFinalHorizontalOffset), 0.01); + Verify.IsLessThan(Math.Abs((double)anticipatedVerticalOffset - (double)expectedFinalVerticalOffset), 0.01); + Verify.AreEqual((float)anticipatedZoomFactor, originalZoomFactor); + } } }); @@ -1555,7 +1626,7 @@ private void ScrollBy( double verticalOffsetDelta, ScrollingAnimationMode animationMode, ScrollingSnapPointsMode snapPointsMode, - bool hookViewChanged = true, + bool hookViewChangingAndChanged = true, bool? isAnimationsEnabledOverride = null, double? expectedFinalHorizontalOffset = null, double? expectedFinalVerticalOffset = null) @@ -1569,6 +1640,9 @@ private void ScrollBy( Log.Comment("Waiting for any pending ExpressionAnimation start/stop notifications to occur"); CompositionPropertySpy.SynchronouslyTickUIThread(6); + double? anticipatedHorizontalOffset = null; + double? anticipatedVerticalOffset = null; + float? anticipatedZoomFactor = null; double originalHorizontalOffset = 0.0; double originalVerticalOffset = 0.0; float originalZoomFactor = 1.0f; @@ -1579,8 +1653,16 @@ private void ScrollBy( { scrollPresenterTestHooksHelper.ResetExpressionAnimationStatusChanges(scrollPresenter); - if (hookViewChanged) + if (hookViewChangingAndChanged) { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + anticipatedHorizontalOffset = args.HorizontalOffset; + anticipatedVerticalOffset = args.VerticalOffset; + anticipatedZoomFactor = args.ZoomFactor; + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1617,6 +1699,7 @@ private void ScrollBy( RunOnUIThread.Execute(() => { Log.Comment($"Final HorizontalOffset={scrollPresenter.HorizontalOffset}, VerticalOffset={scrollPresenter.VerticalOffset}, ZoomFactor={scrollPresenter.ZoomFactor}"); + Log.Comment($"Final viewChangingCount={viewChangingCount}"); Log.Comment($"Final viewChangedCount={viewChangedCount}"); Verify.AreEqual(expectedFinalHorizontalOffset, scrollPresenter.HorizontalOffset); @@ -1626,11 +1709,19 @@ private void ScrollBy( if (GetEffectiveIsAnimationEnabled(animationMode, isAnimationsEnabledOverride)) { + Verify.AreEqual(0u, viewChangingCount); Verify.IsGreaterThan(viewChangedCount, 1u); } else { + Verify.AreEqual(1u, viewChangingCount); Verify.AreEqual(1u, viewChangedCount); + if (anticipatedHorizontalOffset != null && anticipatedVerticalOffset != null && anticipatedZoomFactor != null) + { + Verify.IsLessThan(Math.Abs((double)anticipatedHorizontalOffset - (double)expectedFinalHorizontalOffset), 0.01); + Verify.IsLessThan(Math.Abs((double)anticipatedVerticalOffset - (double)expectedFinalVerticalOffset), 0.01); + Verify.AreEqual((float)anticipatedZoomFactor, originalZoomFactor); + } } }); @@ -1653,7 +1744,7 @@ private void AddScrollVelocity( float? horizontalInertiaDecayRate, float? verticalInertiaDecayRate, bool waitForViewChangeCompletion = true, - bool hookViewChanged = true) + bool hookViewChangingAndChanged = true) { using (ScrollPresenterTestHooksHelper scrollPresenterTestHooksHelper = new ScrollPresenterTestHooksHelper( enableAnchorNotifications: false, @@ -1673,8 +1764,13 @@ private void AddScrollVelocity( { scrollPresenterTestHooksHelper.ResetExpressionAnimationStatusChanges(scrollPresenter); - if (hookViewChanged) + if (hookViewChangingAndChanged) { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1745,6 +1841,7 @@ private ScrollPresenterOperation StartScrollTo( Log.Comment("ScrollTo - horizontalOffset={0}, verticalOffset={1}, animationMode={2}, snapPointsMode={3}", horizontalOffset, verticalOffset, animationMode, snapPointsMode); + viewChangingCount = 0u; viewChangedCount = 0u; ScrollPresenterOperation operation = new ScrollPresenterOperation(); @@ -1788,6 +1885,7 @@ private ScrollPresenterOperation StartScrollBy( Log.Comment("ScrollBy - horizontalOffsetDelta={0}, verticalOffsetDelta={1}, animationMode={2}, snapPointsMode={3}", horizontalOffsetDelta, verticalOffsetDelta, animationMode, snapPointsMode); + viewChangingCount = 0u; viewChangedCount = 0u; ScrollPresenterOperation operation = new ScrollPresenterOperation(); @@ -1838,6 +1936,7 @@ private ScrollPresenterOperation StartAddScrollVelocity( inertiaDecayRate = new Vector2((float)horizontalInertiaDecayRate, (float)verticalInertiaDecayRate); } + viewChangingCount = 0u; viewChangedCount = 0u; ScrollPresenterOperation operation = new ScrollPresenterOperation(); @@ -1876,7 +1975,7 @@ private void ZoomTo( float centerPointY, ScrollingAnimationMode animationMode, ScrollingSnapPointsMode snapPointsMode, - bool hookViewChanged = true, + bool hookViewChangingAndChanged = true, bool? isAnimationsEnabledOverride = null) { using (ScrollPresenterTestHooksHelper scrollPresenterTestHooksHelper = new ScrollPresenterTestHooksHelper( @@ -1885,13 +1984,24 @@ private void ZoomTo( enableExpressionAnimationStatusNotifications: true, isAnimationsEnabledOverride: isAnimationsEnabledOverride)) { + double? anticipatedHorizontalOffset = null; + double? anticipatedVerticalOffset = null; + float? anticipatedZoomFactor = null; AutoResetEvent scrollPresenterViewChangeOperationEvent = new AutoResetEvent(false); ScrollPresenterOperation operation = null; RunOnUIThread.Execute(() => { - if (hookViewChanged) + if (hookViewChangingAndChanged) { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + anticipatedHorizontalOffset = args.HorizontalOffset; + anticipatedVerticalOffset = args.VerticalOffset; + anticipatedZoomFactor = args.ZoomFactor; + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1913,6 +2023,7 @@ private void ZoomTo( RunOnUIThread.Execute(() => { Log.Comment($"Final HorizontalOffset={scrollPresenter.HorizontalOffset}, VerticalOffset={scrollPresenter.VerticalOffset}, ZoomFactor={scrollPresenter.ZoomFactor}"); + Log.Comment($"Final viewChangingCount={viewChangingCount}"); Log.Comment($"Final viewChangedCount={viewChangedCount}"); Verify.AreEqual(zoomFactor, scrollPresenter.ZoomFactor); @@ -1920,11 +2031,19 @@ private void ZoomTo( if (GetEffectiveIsAnimationEnabled(animationMode, isAnimationsEnabledOverride)) { + Verify.AreEqual(0u, viewChangingCount); Verify.IsGreaterThan(viewChangedCount, 1u); } else { + Verify.AreEqual(1u, viewChangingCount); Verify.AreEqual(1u, viewChangedCount); + if (anticipatedHorizontalOffset != null && anticipatedVerticalOffset != null && anticipatedZoomFactor != null) + { + Verify.IsLessThan(Math.Abs((double)anticipatedHorizontalOffset - scrollPresenter.HorizontalOffset), 0.01); + Verify.IsLessThan(Math.Abs((double)anticipatedVerticalOffset - scrollPresenter.VerticalOffset), 0.01); + Verify.IsLessThan(Math.Abs((float)anticipatedZoomFactor - scrollPresenter.ZoomFactor), 0.001f); + } } }); @@ -1947,7 +2066,7 @@ private void ZoomBy( float centerPointY, ScrollingAnimationMode animationMode, ScrollingSnapPointsMode snapPointsMode, - bool hookViewChanged = true, + bool hookViewChangingAndChanged = true, bool? isAnimationsEnabledOverride = null) { using (ScrollPresenterTestHooksHelper scrollPresenterTestHooksHelper = new ScrollPresenterTestHooksHelper( @@ -1956,14 +2075,25 @@ private void ZoomBy( enableExpressionAnimationStatusNotifications: true, isAnimationsEnabledOverride: isAnimationsEnabledOverride)) { + double? anticipatedHorizontalOffset = null; + double? anticipatedVerticalOffset = null; + float? anticipatedZoomFactor = null; float originalZoomFactor = 1.0f; AutoResetEvent scrollPresenterViewChangeOperationEvent = new AutoResetEvent(false); ScrollPresenterOperation operation = null; RunOnUIThread.Execute(() => { - if (hookViewChanged) + if (hookViewChangingAndChanged) { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + anticipatedHorizontalOffset = args.HorizontalOffset; + anticipatedVerticalOffset = args.VerticalOffset; + anticipatedZoomFactor = args.ZoomFactor; + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -1989,6 +2119,7 @@ private void ZoomBy( RunOnUIThread.Execute(() => { Log.Comment($"Final HorizontalOffset={scrollPresenter.HorizontalOffset}, VerticalOffset={scrollPresenter.VerticalOffset}, ZoomFactor={scrollPresenter.ZoomFactor}"); + Log.Comment($"Final viewChangingCount={viewChangingCount}"); Log.Comment($"Final viewChangedCount={viewChangedCount}"); Verify.AreEqual(zoomFactorDelta + originalZoomFactor, scrollPresenter.ZoomFactor); @@ -1996,11 +2127,19 @@ private void ZoomBy( if (GetEffectiveIsAnimationEnabled(animationMode, isAnimationsEnabledOverride)) { + Verify.AreEqual(0u, viewChangingCount); Verify.IsGreaterThan(viewChangedCount, 1u); } else { + Verify.AreEqual(1u, viewChangingCount); Verify.AreEqual(1u, viewChangedCount); + if (anticipatedHorizontalOffset != null && anticipatedVerticalOffset != null && anticipatedZoomFactor != null) + { + Verify.IsLessThan(Math.Abs((double)anticipatedHorizontalOffset - scrollPresenter.HorizontalOffset), 0.01); + Verify.IsLessThan(Math.Abs((double)anticipatedVerticalOffset - scrollPresenter.VerticalOffset), 0.01); + Verify.IsLessThan(Math.Abs((float)anticipatedZoomFactor - scrollPresenter.ZoomFactor), 0.001f); + } } }); @@ -2023,7 +2162,7 @@ private void AddZoomVelocity( float centerPointX, float centerPointY, bool waitForViewChangeCompletion = true, - bool hookViewChanged = true) + bool hookViewChangingAndChanged = true) { using (ScrollPresenterTestHooksHelper scrollPresenterTestHooksHelper = new ScrollPresenterTestHooksHelper( enableAnchorNotifications: false, @@ -2036,8 +2175,13 @@ private void AddZoomVelocity( RunOnUIThread.Execute(() => { - if (hookViewChanged) + if (hookViewChangingAndChanged) { + scrollPresenter.ViewChanging += (sender, args) => + { + Log.Comment($"ViewChanging viewChangingCount={++viewChangingCount} - HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + }; + scrollPresenter.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged viewChangedCount={++viewChangedCount} - HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); @@ -2100,6 +2244,7 @@ private ScrollPresenterOperation StartZoomTo( Log.Comment("ZoomTo - zoomFactor={0}, centerPoint=({1},{2}), animationMode={3}, snapPointsMode={4}", zoomFactor, centerPointX, centerPointY, animationMode, snapPointsMode); + viewChangingCount = 0u; viewChangedCount = 0u; ScrollPresenterOperation operation = new ScrollPresenterOperation(); @@ -2144,6 +2289,7 @@ private ScrollPresenterOperation StartZoomBy( Log.Comment("ZoomBy - zoomFactorDelta={0}, centerPoint=({1},{2}), animationMode={3}, snapPointsMode={4}", zoomFactorDelta, centerPointX, centerPointY, animationMode, snapPointsMode); + viewChangingCount = 0u; viewChangedCount = 0u; ScrollPresenterOperation operation = new ScrollPresenterOperation(); @@ -2187,6 +2333,7 @@ private ScrollPresenterOperation StartAddZoomVelocity( Log.Comment("AddZoomVelocity - zoomFactorVelocity={0}, inertiaDecayRate={1}, centerPoint=({2},{3})", zoomFactorVelocity, inertiaDecayRate, centerPointX, centerPointY); + viewChangingCount = 0u; viewChangedCount = 0u; ScrollPresenterOperation operation = new ScrollPresenterOperation(); diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenter.cpp b/src/controls/dev/ScrollPresenter/ScrollPresenter.cpp index 710b0cc3a2..bd3e28e39b 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenter.cpp +++ b/src/controls/dev/ScrollPresenter/ScrollPresenter.cpp @@ -15,6 +15,7 @@ #include "ScrollPresenterTestHooks.h" #include "Vector.h" #include "RegUtil.h" +#include "MuxcTraceLogging.h" // Change to 'true' to turn on debugging outputs in Output window bool ScrollPresenterTrace::s_IsDebugOutputEnabled{ false }; @@ -188,52 +189,81 @@ winrt::CompositionPropertySet ScrollPresenter::ExpressionAnimationSources() return m_expressionAnimationSources; } -double ScrollPresenter::HorizontalOffset() +double ScrollPresenter::HorizontalOffset() const { return m_zoomedHorizontalOffset; } -double ScrollPresenter::VerticalOffset() +double ScrollPresenter::VerticalOffset() const { return m_zoomedVerticalOffset; } -float ScrollPresenter::ZoomFactor() +float ScrollPresenter::ZoomFactor() const { return m_zoomFactor; } -double ScrollPresenter::ExtentWidth() +double ScrollPresenter::ExtentWidth() const { return m_unzoomedExtentWidth; } -double ScrollPresenter::ExtentHeight() +double ScrollPresenter::ExtentHeight() const { return m_unzoomedExtentHeight; } -double ScrollPresenter::ViewportWidth() +double ScrollPresenter::ViewportWidth() const { return m_viewportWidth; } -double ScrollPresenter::ViewportHeight() +double ScrollPresenter::ViewportHeight() const { return m_viewportHeight; } -double ScrollPresenter::ScrollableWidth() +double ScrollPresenter::ScrollableWidth() const { return std::max(0.0, GetZoomedExtentWidth() - ViewportWidth()); } -double ScrollPresenter::ScrollableHeight() +double ScrollPresenter::ScrollableHeight() const { return std::max(0.0, GetZoomedExtentHeight() - ViewportHeight()); } -winrt::IScrollController ScrollPresenter::HorizontalScrollController() +// AnticipatedZoomedHorizontalOffset, AnticipatedZoomedVerticalOffset() and AnticipatedZoomFactor() are +// used to evaluate the view for the ViewChanging event raised when a ScrollTo, ScrollBy, ZoomTo or ZoomBy +// request is handed off to the InteractionTracker. + +double ScrollPresenter::AnticipatedZoomedHorizontalOffset() const +{ + return isnan(m_anticipatedZoomedHorizontalOffset) ? m_zoomedHorizontalOffset : m_anticipatedZoomedHorizontalOffset; +} + +double ScrollPresenter::AnticipatedZoomedVerticalOffset() const +{ + return isnan(m_anticipatedZoomedVerticalOffset) ? m_zoomedVerticalOffset : m_anticipatedZoomedVerticalOffset; +} + +float ScrollPresenter::AnticipatedZoomFactor() const +{ + return isnan(m_anticipatedZoomFactor) ? m_zoomFactor : m_anticipatedZoomFactor; +} + +double ScrollPresenter::AnticipatedScrollableWidth() const +{ + return std::max(0.0, m_unzoomedExtentWidth * AnticipatedZoomFactor() - ViewportWidth()); +} + +double ScrollPresenter::AnticipatedScrollableHeight() const +{ + return std::max(0.0, m_unzoomedExtentHeight * AnticipatedZoomFactor() - ViewportHeight()); +} + +winrt::IScrollController ScrollPresenter::HorizontalScrollController() const { if (m_horizontalScrollController) { @@ -302,7 +332,7 @@ void ScrollPresenter::HorizontalScrollController(winrt::IScrollController const& } } -winrt::IScrollController ScrollPresenter::VerticalScrollController() +winrt::IScrollController ScrollPresenter::VerticalScrollController() const { if (m_verticalScrollController) { @@ -371,7 +401,7 @@ void ScrollPresenter::VerticalScrollController(winrt::IScrollController const& v } } -winrt::ScrollingInputKinds ScrollPresenter::IgnoredInputKinds() +winrt::ScrollingInputKinds ScrollPresenter::IgnoredInputKinds() const { // Workaround for Bug 17377013: XamlCompiler codegen for Enum CreateFromString always returns boxed int which is wrong for [flags] enums (should be uint) // Check if the boxed IgnoredInputKinds is an IReference first in which case we unbox as int. @@ -389,7 +419,7 @@ void ScrollPresenter::IgnoredInputKinds(winrt::ScrollingInputKinds const& value) SetValue(s_IgnoredInputKindsProperty, box_value(value)); } -winrt::ScrollingInteractionState ScrollPresenter::State() +winrt::ScrollingInteractionState ScrollPresenter::State() const { return m_state; } @@ -819,8 +849,8 @@ winrt::Size ScrollPresenter::ArrangeOverride(winrt::Size const& finalSize) { float unzoomedDelta = 0.0f; - if (newUnzoomedExtentWidth > m_unzoomedExtentWidth || // ExtentWidth grew - m_zoomedHorizontalOffset + m_viewportWidth > m_zoomFactor* m_unzoomedExtentWidth) // ExtentWidth shrank while overpanning + if (newUnzoomedExtentWidth > m_unzoomedExtentWidth || // ExtentWidth grew + m_zoomedHorizontalOffset + m_viewportWidth > m_zoomFactor * m_unzoomedExtentWidth) // ExtentWidth shrank while overpanning { // Perform horizontal offset adjustment due to edge anchoring unzoomedDelta = static_cast(newUnzoomedExtentWidth - m_unzoomedExtentWidth); @@ -843,8 +873,8 @@ winrt::Size ScrollPresenter::ArrangeOverride(winrt::Size const& finalSize) { float unzoomedDelta = 0.0f; - if (newUnzoomedExtentHeight > m_unzoomedExtentHeight || // ExtentHeight grew - m_zoomedVerticalOffset + m_viewportHeight > m_zoomFactor* m_unzoomedExtentHeight) // ExtentHeight shrank while overpanning + if (newUnzoomedExtentHeight > m_unzoomedExtentHeight || // ExtentHeight grew + m_zoomedVerticalOffset + m_viewportHeight > m_zoomFactor * m_unzoomedExtentHeight) // ExtentHeight shrank while overpanning { // Perform vertical offset adjustment due to edge anchoring unzoomedDelta = static_cast(newUnzoomedExtentHeight - m_unzoomedExtentHeight); @@ -1143,21 +1173,31 @@ void ScrollPresenter::ValuesChanged( if (isRightToLeftDirection) { - UpdateOffset(ScrollPresenterDimension::HorizontalScroll, maxPosition.x - args.Position().x); + UpdateOffset(ScrollPresenterDimension::HorizontalScroll, static_cast(maxPosition.x) - args.Position().x); } else { - UpdateOffset(ScrollPresenterDimension::HorizontalScroll, args.Position().x - minPosition.x); + UpdateOffset(ScrollPresenterDimension::HorizontalScroll, static_cast(args.Position().x) - minPosition.x); } - UpdateOffset(ScrollPresenterDimension::VerticalScroll, args.Position().y - minPosition.y); + UpdateOffset(ScrollPresenterDimension::VerticalScroll, static_cast(args.Position().y) - minPosition.y); if (oldZoomFactor != m_zoomFactor || oldZoomedHorizontalOffset != m_zoomedHorizontalOffset || oldZoomedVerticalOffset != m_zoomedVerticalOffset) { OnViewChanged(oldZoomedHorizontalOffset != m_zoomedHorizontalOffset /*horizontalOffsetChanged*/, - oldZoomedVerticalOffset != m_zoomedVerticalOffset /*verticalOffsetChanged*/); + oldZoomedVerticalOffset != m_zoomedVerticalOffset /*verticalOffsetChanged*/); } + TraceLoggingProviderWrite( + XamlTelemetryLogging, "ScrollPresenter_ValuesChanged", + TraceLoggingFloat64(m_zoomedHorizontalOffset, "HorizontalOffset"), + TraceLoggingFloat64(m_zoomedVerticalOffset, "VerticalOffset"), + TraceLoggingFloat32(m_zoomFactor, "ZoomFactor"), + TraceLoggingFloat64(oldZoomedHorizontalOffset, "OldHorizontalOffset"), + TraceLoggingFloat64(oldZoomedVerticalOffset, "OldVerticalOffset"), + TraceLoggingFloat32(oldZoomFactor, "OldZoomFactor"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + if (requestId != 0 && !m_interactionTrackerAsyncOperations.empty()) { CompleteInteractionTrackerOperations( @@ -2080,7 +2120,7 @@ void ScrollPresenter::SetupSnapPoints( //and will only shrink to accommodate other snap points which are positioned such that the midpoint between them is within the specified ApplicableRange. //Snap points which have ApplicableRangeType = Mandatory are mandatory snap points and their ActualApplicableRange will expand or shrink to ensure that there is no //space between it and its neighbors. If the neighbors are also mandatory, this point will be the midpoint between them. If the neighbors are optional then this -//point will fall on the midpoint or on the Optional neighbor's edge of ApplicableRange, whichever is furthest. +//point will fall on the midpoint or on the Optional neighbor's edge of ApplicableRange, whichever is furthest. template void ScrollPresenter::UpdateSnapPointsRanges( std::set>, SnapPointWrapperComparator>* snapPointsSet, @@ -4212,10 +4252,15 @@ void ScrollPresenter::OnCompositionTargetRendering(const winrt::IInspectable& /* CompleteViewChange(interactionTrackerAsyncOperation, ScrollPresenterViewChangeResult::Completed); if (m_translationAndZoomFactorAnimationsRestartTicksCountdown > 0) { - // Do not unhook the Rendering event when there is a pending restart of the Translation and Scale animations. + // Do not unhook the Rendering event when there is a pending restart of the Translation and Scale animations. unhookCompositionTargetRendering = false; } m_interactionTrackerAsyncOperations.remove(interactionTrackerAsyncOperation); + + if (m_interactionTrackerAsyncOperations.empty()) + { + ResetAnticipatedView(); + } } else { @@ -5416,6 +5461,39 @@ void ScrollPresenter::UpdateScrollAutomationPatternProperties() } } +void ScrollPresenter::UpdateAnticipatedOffset(ScrollPresenterDimension dimension, double zoomedOffset) +{ + if (dimension == ScrollPresenterDimension::HorizontalScroll) + { + if (m_anticipatedZoomedHorizontalOffset != zoomedOffset) + { + SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_STR_DBL, METH_NAME, this, L"anticipatedZoomedHorizontalOffset", zoomedOffset); + + m_anticipatedZoomedHorizontalOffset = zoomedOffset; + } + } + else + { + MUX_ASSERT(dimension == ScrollPresenterDimension::VerticalScroll); + if (m_anticipatedZoomedVerticalOffset != zoomedOffset) + { + SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_STR_DBL, METH_NAME, this, L"anticipatedZoomedVerticalOffset", zoomedOffset); + + m_anticipatedZoomedVerticalOffset = zoomedOffset; + } + } +} + +void ScrollPresenter::UpdateAnticipatedZoomFactor(float zoomFactor) +{ + if (m_anticipatedZoomFactor != zoomFactor) + { + SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_STR_FLT, METH_NAME, this, L"anticipatedZoomFactor", zoomFactor); + + m_anticipatedZoomFactor = zoomFactor; + } +} + void ScrollPresenter::UpdateOffset(ScrollPresenterDimension dimension, double zoomedOffset) { if (dimension == ScrollPresenterDimension::HorizontalScroll) @@ -5757,7 +5835,7 @@ void ScrollPresenter::ChangeOffsetsPrivate( optionsClone ? static_cast(*optionsClone) : static_cast(options)); } - std::shared_ptr interactionTrackerAsyncOperation( + std::shared_ptr interactionTrackerAsyncOperation( std::make_shared( operationType, operationTrigger, @@ -6184,6 +6262,9 @@ void ScrollPresenter::ProcessOffsetsChange( } } + double anticipatedZoomedHorizontalOffset{ DoubleUtil::NaN }; + double anticipatedZoomedVerticalOffset{ DoubleUtil::NaN }; + switch (offsetsChange->ViewKind()) { #ifdef ScrollPresenterViewKind_RelativeToEndOfInertiaView @@ -6197,10 +6278,14 @@ void ScrollPresenter::ProcessOffsetsChange( #endif case ScrollPresenterViewKind::RelativeToCurrentView: { + anticipatedZoomedHorizontalOffset = AnticipatedZoomedHorizontalOffset(); + anticipatedZoomedVerticalOffset = AnticipatedZoomedVerticalOffset(); + if (snapPointsMode == winrt::ScrollingSnapPointsMode::Default || animationMode == winrt::ScrollingAnimationMode::Enabled) { - zoomedHorizontalOffset += m_zoomedHorizontalOffset; - zoomedVerticalOffset += m_zoomedVerticalOffset; + // The new requested deltas are added to the prior deltas that have not been processed yet. + zoomedHorizontalOffset += anticipatedZoomedHorizontalOffset; + zoomedVerticalOffset += anticipatedZoomedVerticalOffset; } break; } @@ -6235,9 +6320,31 @@ void ScrollPresenter::ProcessOffsetsChange( L"TryUpdatePositionBy", TypeLogging::Float2ToString(winrt::float2(static_cast(zoomedHorizontalOffset), static_cast(zoomedVerticalOffset))).c_str()); + TraceLoggingProviderWrite( + XamlTelemetryLogging, "ScrollPresenter_TryUpdatePositionBy", + TraceLoggingFloat64(zoomedHorizontalOffset, "HorizontalOffset"), + TraceLoggingFloat64(zoomedVerticalOffset, "VerticalOffset"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + m_latestInteractionTrackerRequest = m_interactionTracker.TryUpdatePositionBy( winrt::float3(static_cast(zoomedHorizontalOffset), static_cast(zoomedVerticalOffset), 0.0f)); m_lastInteractionTrackerAsyncOperationType = InteractionTrackerAsyncOperationType::TryUpdatePositionBy; + + if (zoomedHorizontalOffset != 0.0) + { + double newAnticipatedZoomedHorizontalOffset = zoomedHorizontalOffset + anticipatedZoomedHorizontalOffset; + newAnticipatedZoomedHorizontalOffset = std::max(0.0, newAnticipatedZoomedHorizontalOffset); + newAnticipatedZoomedHorizontalOffset = std::min(AnticipatedScrollableWidth(), newAnticipatedZoomedHorizontalOffset); + UpdateAnticipatedOffset(ScrollPresenterDimension::HorizontalScroll, newAnticipatedZoomedHorizontalOffset); + } + + if (zoomedVerticalOffset != 0.0) + { + double newAnticipatedZoomedVerticalOffset = zoomedVerticalOffset + anticipatedZoomedVerticalOffset; + newAnticipatedZoomedVerticalOffset = std::max(0.0, newAnticipatedZoomedVerticalOffset); + newAnticipatedZoomedVerticalOffset = std::min(AnticipatedScrollableHeight(), newAnticipatedZoomedVerticalOffset); + UpdateAnticipatedOffset(ScrollPresenterDimension::VerticalScroll, newAnticipatedZoomedVerticalOffset); + } } else { @@ -6246,11 +6353,33 @@ void ScrollPresenter::ProcessOffsetsChange( SCROLLPRESENTER_TRACE_INFO_DBG(*this, TRACE_MSG_METH_METH_STR, METH_NAME, this, L"TryUpdatePosition", TypeLogging::Float2ToString(targetPosition).c_str()); + TraceLoggingProviderWrite( + XamlTelemetryLogging, "ScrollPresenter_TryUpdatePosition", + TraceLoggingFloat64(zoomedHorizontalOffset, "HorizontalOffset"), + TraceLoggingFloat64(zoomedVerticalOffset, "VerticalOffset"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + m_latestInteractionTrackerRequest = m_interactionTracker.TryUpdatePosition( winrt::float3(targetPosition, 0.0f)); m_lastInteractionTrackerAsyncOperationType = InteractionTrackerAsyncOperationType::TryUpdatePosition; + + double newAnticipatedZoomedHorizontalOffset = std::max(0.0, zoomedHorizontalOffset); + newAnticipatedZoomedHorizontalOffset = std::min(AnticipatedScrollableWidth(), newAnticipatedZoomedHorizontalOffset); + UpdateAnticipatedOffset(ScrollPresenterDimension::HorizontalScroll, newAnticipatedZoomedHorizontalOffset); + + double newAnticipatedZoomedVerticalOffset = std::max(0.0, zoomedVerticalOffset); + newAnticipatedZoomedVerticalOffset = std::min(AnticipatedScrollableHeight(), newAnticipatedZoomedVerticalOffset); + UpdateAnticipatedOffset(ScrollPresenterDimension::VerticalScroll, newAnticipatedZoomedVerticalOffset); } + RaiseViewChanging( +#ifdef DBG + offsetsChangeCorrelationId, +#endif // DBG + AnticipatedZoomedHorizontalOffset(), + AnticipatedZoomedVerticalOffset(), + AnticipatedZoomFactor()); + if (isForAsyncOperation) { HookCompositionTargetRendering(); @@ -6261,6 +6390,12 @@ void ScrollPresenter::ProcessOffsetsChange( { SCROLLPRESENTER_TRACE_INFO_DBG(*this, TRACE_MSG_METH_METH, METH_NAME, this, L"TryUpdatePositionWithAnimation"); + TraceLoggingProviderWrite( + XamlTelemetryLogging, "ScrollPresenter_TryUpdatePositionWithAnimation", + TraceLoggingFloat64(zoomedHorizontalOffset, "HorizontalOffset"), + TraceLoggingFloat64(zoomedVerticalOffset, "VerticalOffset"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + m_latestInteractionTrackerRequest = m_interactionTracker.TryUpdatePositionWithAnimation( GetPositionAnimation( zoomedHorizontalOffset, @@ -6268,6 +6403,8 @@ void ScrollPresenter::ProcessOffsetsChange( operationTrigger, offsetsChangeCorrelationId)); m_lastInteractionTrackerAsyncOperationType = InteractionTrackerAsyncOperationType::TryUpdatePositionWithAnimation; + + ResetAnticipatedView(); break; } } @@ -6334,9 +6471,17 @@ void ScrollPresenter::ProcessOffsetsChange( SCROLLPRESENTER_TRACE_INFO_DBG(*this, TRACE_MSG_METH_METH_STR, METH_NAME, this, L"TryUpdatePositionWithAdditionalVelocity", TypeLogging::Float2ToString(winrt::float2(offsetsVelocity)).c_str()); + TraceLoggingProviderWrite( + XamlTelemetryLogging, "ScrollPresenter_TryUpdatePositionWithAdditionalVelocity", + TraceLoggingFloat32(offsetsVelocity.x, "Velocity.X"), + TraceLoggingFloat32(offsetsVelocity.y, "Velocity.Y"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + m_latestInteractionTrackerRequest = m_interactionTracker.TryUpdatePositionWithAdditionalVelocity( winrt::float3(offsetsVelocity, 0.0f)); m_lastInteractionTrackerAsyncOperationType = InteractionTrackerAsyncOperationType::TryUpdatePositionWithAdditionalVelocity; + + ResetAnticipatedView(); } // Restores the default scroll inertia decay rate if no offset change with additional velocity operation is in progress. @@ -6398,7 +6543,8 @@ void ScrollPresenter::ProcessZoomFactorChange( #endif case ScrollPresenterViewKind::RelativeToCurrentView: { - zoomFactor += m_zoomFactor; + // The new requested delta is added to the prior deltas that have not been processed yet. + zoomFactor += AnticipatedZoomFactor(); break; } } @@ -6420,9 +6566,37 @@ void ScrollPresenter::ProcessZoomFactorChange( SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_METH_FLT_STR, METH_NAME, this, L"TryUpdateScale", zoomFactor, TypeLogging::Float2ToString(winrt::float2(centerPoint.x, centerPoint.y)).c_str()); + TraceLoggingProviderWrite( + XamlTelemetryLogging, "TryUpdateScale", + TraceLoggingFloat32(zoomFactor, "ZoomFactor"), + TraceLoggingFloat32(centerPoint.x, "Center.X"), + TraceLoggingFloat32(centerPoint.y, "Center.Y"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + m_latestInteractionTrackerRequest = m_interactionTracker.TryUpdateScale(zoomFactor, centerPoint); m_lastInteractionTrackerAsyncOperationType = InteractionTrackerAsyncOperationType::TryUpdateScale; + double newAnticipatedZoomedHorizontalOffset = zoomFactor / AnticipatedZoomFactor() * (AnticipatedZoomedHorizontalOffset() + centerPoint.x) - centerPoint.x; + double newAnticipatedZoomedVerticalOffset = zoomFactor / AnticipatedZoomFactor() * (AnticipatedZoomedVerticalOffset() + centerPoint.y) - centerPoint.y; + + UpdateAnticipatedZoomFactor(zoomFactor); + + newAnticipatedZoomedHorizontalOffset = std::max(0.0, newAnticipatedZoomedHorizontalOffset); + newAnticipatedZoomedHorizontalOffset = std::min(AnticipatedScrollableWidth(), newAnticipatedZoomedHorizontalOffset); + UpdateAnticipatedOffset(ScrollPresenterDimension::HorizontalScroll, newAnticipatedZoomedHorizontalOffset); + + newAnticipatedZoomedVerticalOffset = std::max(0.0, newAnticipatedZoomedVerticalOffset); + newAnticipatedZoomedVerticalOffset = std::min(AnticipatedScrollableHeight(), newAnticipatedZoomedVerticalOffset); + UpdateAnticipatedOffset(ScrollPresenterDimension::VerticalScroll, newAnticipatedZoomedVerticalOffset); + + RaiseViewChanging( +#ifdef DBG + zoomFactorChangeCorrelationId, +#endif // DBG + newAnticipatedZoomedHorizontalOffset, + newAnticipatedZoomedVerticalOffset, + zoomFactor); + HookCompositionTargetRendering(); break; } @@ -6430,10 +6604,19 @@ void ScrollPresenter::ProcessZoomFactorChange( { SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_METH, METH_NAME, this, L"TryUpdateScaleWithAnimation"); + TraceLoggingProviderWrite( + XamlTelemetryLogging, "TryUpdateScaleWithAnimation", + TraceLoggingFloat32(zoomFactor, "ZoomFactor"), + TraceLoggingFloat32(centerPoint.x, "Center.X"), + TraceLoggingFloat32(centerPoint.y, "Center.Y"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + m_latestInteractionTrackerRequest = m_interactionTracker.TryUpdateScaleWithAnimation( GetZoomFactorAnimation(zoomFactor, centerPoint2D, zoomFactorChangeCorrelationId), centerPoint); m_lastInteractionTrackerAsyncOperationType = InteractionTrackerAsyncOperationType::TryUpdateScaleWithAnimation; + + ResetAnticipatedView(); break; } } @@ -6477,10 +6660,19 @@ void ScrollPresenter::ProcessZoomFactorChange( SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_METH_FLT_STR, METH_NAME, this, L"TryUpdateScaleWithAdditionalVelocity", zoomFactorVelocity, TypeLogging::Float2ToString(winrt::float2(centerPoint.x, centerPoint.y)).c_str()); + TraceLoggingProviderWrite( + XamlTelemetryLogging, "TryUpdateScaleWithAdditionalVelocity", + TraceLoggingFloat32(zoomFactorVelocity, "Velocity"), + TraceLoggingFloat32(centerPoint.x, "Center.X"), + TraceLoggingFloat32(centerPoint.y, "Center.Y"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); + m_latestInteractionTrackerRequest = m_interactionTracker.TryUpdateScaleWithAdditionalVelocity( zoomFactorVelocity, centerPoint); m_lastInteractionTrackerAsyncOperationType = InteractionTrackerAsyncOperationType::TryUpdateScaleWithAdditionalVelocity; + + ResetAnticipatedView(); } // Restores the default zoomFactor inertia decay rate if no zoomFactor change with additional velocity operation is in progress. @@ -6506,6 +6698,17 @@ void ScrollPresenter::PostProcessZoomFactorChange( ResetZoomFactorInertiaDecayRate(); } +// Clears the last recorded anticipated view for the ViewChanging event. +// Called in two classes of circumstances: +// - all queued view change requested were completed, +// - an animated view change request is handed off to the InteractionTracker. +void ScrollPresenter::ResetAnticipatedView() +{ + UpdateAnticipatedOffset(ScrollPresenterDimension::HorizontalScroll, DoubleUtil::NaN); + UpdateAnticipatedOffset(ScrollPresenterDimension::VerticalScroll, DoubleUtil::NaN); + UpdateAnticipatedZoomFactor(FloatUtil::NaN); +} + // Restores the default scroll offset inertia decay rate. void ScrollPresenter::ResetOffsetsInertiaDecayRate() { @@ -6650,6 +6853,11 @@ void ScrollPresenter::CompleteInteractionTrackerOperations( m_interactionTrackerAsyncOperations.remove(interactionTrackerAsyncOperationRemoved); + if (m_interactionTrackerAsyncOperations.empty()) + { + ResetAnticipatedView(); + } + switch (interactionTrackerAsyncOperationRemoved->GetOperationType()) { case InteractionTrackerAsyncOperationType::TryUpdatePositionWithAdditionalVelocity: @@ -6683,6 +6891,11 @@ void ScrollPresenter::CompleteDelayedOperations() { CompleteViewChange(interactionTrackerAsyncOperation, ScrollPresenterViewChangeResult::Interrupted); m_interactionTrackerAsyncOperations.remove(interactionTrackerAsyncOperation); + + if (m_interactionTrackerAsyncOperations.empty()) + { + ResetAnticipatedView(); + } } } } @@ -7279,6 +7492,33 @@ void ScrollPresenter::RaiseStateChanged() } } +void ScrollPresenter::RaiseViewChanging( +#ifdef DBG + int32_t viewChangeCorrelationIdDbg, +#endif // DBG + double anticipatedHorizontalOffset, + double anticipatedVerticalOffset, + float anticipatedZoomFactor) +{ + if (m_viewChangingEventSource) + { + auto viewChangingEventArgs = winrt::make_self(); + +#ifdef DBG + SCROLLPRESENTER_TRACE_INFO(*this, TRACE_MSG_METH_INT, METH_NAME, this, viewChangeCorrelationIdDbg); + SCROLLPRESENTER_TRACE_INFO(*this, TRACE_MSG_METH_DBL_DBL, METH_NAME, this, anticipatedHorizontalOffset, anticipatedVerticalOffset); + SCROLLPRESENTER_TRACE_INFO(*this, TRACE_MSG_METH_FLT, METH_NAME, this, anticipatedZoomFactor); + + viewChangingEventArgs->SetCorrelationIdDbg(viewChangeCorrelationIdDbg); +#endif // DBG + + viewChangingEventArgs->SetHorizontalOffset(anticipatedHorizontalOffset); + viewChangingEventArgs->SetVerticalOffset(anticipatedVerticalOffset); + viewChangingEventArgs->SetZoomFactor(anticipatedZoomFactor); + m_viewChangingEventSource(*this, *viewChangingEventArgs); + } +} + void ScrollPresenter::RaiseViewChanged() { if (m_viewChangedEventSource) diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenter.h b/src/controls/dev/ScrollPresenter/ScrollPresenter.h index a4db561c79..1748450d70 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenter.h +++ b/src/controls/dev/ScrollPresenter/ScrollPresenter.h @@ -3,6 +3,7 @@ #pragma once +#include "DoubleUtil.h" #include "FloatUtil.h" #include "InteractionTrackerAsyncOperation.h" #include "ScrollingScrollAnimationStartingEventArgs.h" @@ -11,6 +12,7 @@ #include "ScrollingZoomCompletedEventArgs.h" #include "ScrollingBringingIntoViewEventArgs.h" #include "ScrollingAnchorRequestedEventArgs.h" +#include "ScrollingViewChangingEventArgs.h" #include "SnapPointWrapper.h" #include "ScrollPresenterTrace.h" #include "ViewChange.h" @@ -24,7 +26,7 @@ #include "ScrollPresenter.properties.h" class ScrollPresenter : - public ReferenceTracker, + public ReferenceTracker, public ScrollPresenterProperties { public: @@ -128,26 +130,26 @@ class ScrollPresenter : #pragma region IScrollPresenter winrt::CompositionPropertySet ExpressionAnimationSources(); - double HorizontalOffset(); - double VerticalOffset(); - float ZoomFactor(); - double ExtentWidth(); - double ExtentHeight(); - double ViewportWidth(); - double ViewportHeight(); - double ScrollableWidth(); - double ScrollableHeight(); - - winrt::IScrollController HorizontalScrollController(); + double HorizontalOffset() const; + double VerticalOffset() const; + float ZoomFactor() const; + double ExtentWidth() const; + double ExtentHeight() const; + double ViewportWidth() const; + double ViewportHeight() const; + double ScrollableWidth() const; + double ScrollableHeight() const; + + winrt::IScrollController HorizontalScrollController() const; void HorizontalScrollController(winrt::IScrollController const& value); - winrt::IScrollController VerticalScrollController(); + winrt::IScrollController VerticalScrollController() const; void VerticalScrollController(winrt::IScrollController const& value); - winrt::ScrollingInputKinds IgnoredInputKinds(); + winrt::ScrollingInputKinds IgnoredInputKinds() const; void IgnoredInputKinds(winrt::ScrollingInputKinds const& value); - winrt::ScrollingInteractionState State(); + winrt::ScrollingInteractionState State() const; winrt::IVector HorizontalSnapPoints(); @@ -281,6 +283,12 @@ class ScrollPresenter : static winrt::hstring DependencyPropertyToString(const winrt::IDependencyProperty& dependencyProperty); #endif + double AnticipatedZoomedHorizontalOffset() const; + double AnticipatedZoomedVerticalOffset() const; + float AnticipatedZoomFactor() const; + double AnticipatedScrollableWidth() const; + double AnticipatedScrollableHeight() const; + winrt::Size ArrangeContent( const winrt::UIElement& content, const winrt::Thickness& contentMargin, @@ -425,6 +433,8 @@ class ScrollPresenter : double viewportWidth, double viewportHeight); void UpdateScrollAutomationPatternProperties(); + void UpdateAnticipatedOffset(ScrollPresenterDimension dimension, double zoomedOffset); + void UpdateAnticipatedZoomFactor(float zoomFactor); void UpdateOffset(ScrollPresenterDimension dimension, double zoomedOffset); void UpdateScrollControllerIsScrollable(ScrollPresenterDimension dimension); void UpdateScrollControllerValues(ScrollPresenterDimension dimension); @@ -485,6 +495,7 @@ class ScrollPresenter : std::shared_ptr zoomFactorChangeWithAdditionalVelocity); void PostProcessZoomFactorChange( std::shared_ptr interactionTrackerAsyncOperation); + void ResetAnticipatedView(); void ResetOffsetsInertiaDecayRate(); void ResetZoomFactorInertiaDecayRate(); void CompleteViewChange( @@ -604,6 +615,13 @@ class ScrollPresenter : wstring_view const& propertyName); void RaiseExtentChanged(); void RaiseStateChanged(); + void RaiseViewChanging( +#ifdef DBG + int32_t viewChangeCorrelationIdDbg, +#endif // DBG + double anticipatedHorizontalOffset, + double anticipatedVerticalOffset, + float anticipatedZoomFactor); void RaiseViewChanged(); winrt::CompositionAnimation RaiseScrollAnimationStarting( const winrt::Vector3KeyFrameAnimation& positionAnimation, @@ -786,10 +804,13 @@ class ScrollPresenter : float m_animationRestartZoomFactor{ 1.0f }; float m_endOfInertiaZoomFactor{ 1.0f }; float m_zoomFactor{ 1.0f }; + float m_anticipatedZoomFactor{ FloatUtil::NaN }; float m_contentLayoutOffsetX{ 0.0f }; float m_contentLayoutOffsetY{ 0.0f }; double m_zoomedHorizontalOffset{ 0.0 }; double m_zoomedVerticalOffset{ 0.0 }; + double m_anticipatedZoomedHorizontalOffset{ DoubleUtil::NaN }; + double m_anticipatedZoomedVerticalOffset{ DoubleUtil::NaN }; double m_unzoomedExtentWidth{ 0.0 }; double m_unzoomedExtentHeight{ 0.0 }; double m_viewportWidth{ 0.0 }; diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenter.idl b/src/controls/dev/ScrollPresenter/ScrollPresenter.idl index 444f0f0850..d1986969fc 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenter.idl +++ b/src/controls/dev/ScrollPresenter/ScrollPresenter.idl @@ -167,4 +167,13 @@ runtimeclass ScrollingAnchorRequestedEventArgs Microsoft.UI.Xaml.UIElement AnchorElement { get; set; }; } +[MUX_PREVIEW] +[webhosthidden] +runtimeclass ScrollingViewChangingEventArgs +{ + Double HorizontalOffset { get; }; + Double VerticalOffset { get; }; + Single ZoomFactor{ get; }; +} + } diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenter.vcxitems b/src/controls/dev/ScrollPresenter/ScrollPresenter.vcxitems index e5c4279d9c..115ffd4998 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenter.vcxitems +++ b/src/controls/dev/ScrollPresenter/ScrollPresenter.vcxitems @@ -38,6 +38,7 @@ + @@ -66,6 +67,7 @@ + diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenterAnchoring.cpp b/src/controls/dev/ScrollPresenter/ScrollPresenterAnchoring.cpp index 974be422ec..3e35313d7e 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenterAnchoring.cpp +++ b/src/controls/dev/ScrollPresenter/ScrollPresenterAnchoring.cpp @@ -376,8 +376,8 @@ void ScrollPresenter::EnsureAnchorElementSelection() globalTestHooks->NotifyAnchorEvaluated(*this, requestedAnchorElement, viewportAnchorPointHorizontalOffset, viewportAnchorPointVerticalOffset); } - SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_PTR_STR, METH_NAME, this, m_anchorElement.get(), L"m_anchorElement set."); - SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_STR_STR, METH_NAME, this, TypeLogging::RectToString(m_anchorElementBounds).c_str(), L"m_anchorElementBounds set."); + SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_PTR_STR, METH_NAME, this, m_anchorElement.get(), L"m_anchorElement set from ScrollingAnchorRequestedEventArgs."); + SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_STR_STR, METH_NAME, this, TypeLogging::RectToString(m_anchorElementBounds).c_str(), L"m_anchorElementBounds set from ScrollingAnchorRequestedEventArgs."); return; } @@ -432,8 +432,10 @@ void ScrollPresenter::EnsureAnchorElementSelection() m_anchorElement.set(bestAnchorCandidate); m_anchorElementBounds = bestAnchorCandidateBounds; - SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_PTR_STR, METH_NAME, this, m_anchorElement.get(), L"m_anchorElement set."); - SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_STR_STR, METH_NAME, this, TypeLogging::RectToString(m_anchorElementBounds).c_str(), L"m_anchorElementBounds set."); + SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_PTR_STR, METH_NAME, this, m_anchorElement.get(), + anchorCandidates ? L"m_anchorElement set from anchorCandidates." : L"m_anchorElement set from m_anchorCandidates."); + SCROLLPRESENTER_TRACE_VERBOSE_DBG(*this, TRACE_MSG_METH_STR_STR, METH_NAME, this, TypeLogging::RectToString(m_anchorElementBounds).c_str(), + anchorCandidates ? L"m_anchorElementBounds set from anchorCandidates." : L"m_anchorElementBounds set from m_anchorCandidates."); } if (globalTestHooks && globalTestHooks->AreAnchorNotificationsRaised()) @@ -477,13 +479,13 @@ void ScrollPresenter::ProcessAnchorCandidate( if (!isnan(viewportAnchorPointHorizontalOffset)) { anchorCandidateDistance += std::pow(viewportAnchorPointHorizontalOffset - anchorCandidateBounds.X, 2); - anchorCandidateDistance += std::pow(viewportAnchorPointHorizontalOffset - (anchorCandidateBounds.X + anchorCandidateBounds.Width), 2); + anchorCandidateDistance += std::pow(viewportAnchorPointHorizontalOffset - (static_cast(anchorCandidateBounds.X) + static_cast(anchorCandidateBounds.Width)), 2); } if (!isnan(viewportAnchorPointVerticalOffset)) { anchorCandidateDistance += std::pow(viewportAnchorPointVerticalOffset - anchorCandidateBounds.Y, 2); - anchorCandidateDistance += std::pow(viewportAnchorPointVerticalOffset - (anchorCandidateBounds.Y + anchorCandidateBounds.Height), 2); + anchorCandidateDistance += std::pow(viewportAnchorPointVerticalOffset - (static_cast(anchorCandidateBounds.Y) + static_cast(anchorCandidateBounds.Height)), 2); } if (anchorCandidateDistance <= *bestAnchorCandidateDistance) diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenterPrimitives.idl b/src/controls/dev/ScrollPresenter/ScrollPresenterPrimitives.idl index 807cf01947..01123acadf 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenterPrimitives.idl +++ b/src/controls/dev/ScrollPresenter/ScrollPresenterPrimitives.idl @@ -345,6 +345,7 @@ unsealed runtimeclass ScrollPresenter : event Windows.Foundation.TypedEventHandler ExtentChanged; event Windows.Foundation.TypedEventHandler StateChanged; event Windows.Foundation.TypedEventHandler ViewChanged; + event Windows.Foundation.TypedEventHandler ScrollAnimationStarting; event Windows.Foundation.TypedEventHandler ZoomAnimationStarting; event Windows.Foundation.TypedEventHandler ScrollCompleted; @@ -352,6 +353,9 @@ unsealed runtimeclass ScrollPresenter : event Windows.Foundation.TypedEventHandler BringingIntoView; event Windows.Foundation.TypedEventHandler AnchorRequested; + [MUX_PREVIEW] + event Windows.Foundation.TypedEventHandler ViewChanging; + static Microsoft.UI.Xaml.DependencyProperty BackgroundProperty { get; }; static Microsoft.UI.Xaml.DependencyProperty ContentProperty { get; }; static Microsoft.UI.Xaml.DependencyProperty ContentOrientationProperty { get; }; diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenterPrivate.cpp b/src/controls/dev/ScrollPresenter/ScrollPresenterPrivate.cpp index e5cc68ab4d..11fa5efb36 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenterPrivate.cpp +++ b/src/controls/dev/ScrollPresenter/ScrollPresenterPrivate.cpp @@ -104,7 +104,7 @@ winrt::UIElement ScrollPresenter::AnchorElement() void ScrollPresenter::RegisterAnchorCandidate(winrt::UIElement const& element) { #ifdef DBG_VERBOSE - SCROLLPRESENTER_TRACE_VERBOSE(*this, TRACE_MSG_METH_PTR_DBL, METH_NAME, this, element, VerticalAnchorRatio()); + SCROLLPRESENTER_TRACE_VERBOSE(*this, TRACE_MSG_METH_PTR, METH_NAME, this, element); #endif if (!element) @@ -115,7 +115,7 @@ void ScrollPresenter::RegisterAnchorCandidate(winrt::UIElement const& element) if (!isnan(HorizontalAnchorRatio()) || !isnan(VerticalAnchorRatio())) { #ifdef DBG - // We should not be registring the same element twice. Even through it is functionally ok, + // We should not be registering the same element twice. Even through it is functionally ok, // we will end up spending more time during arrange than we must. // However checking if an element is already in the list every time a new element is registered is worse for perf. // So, I'm leaving an assert here to catch regression in our code but in release builds we run without the check. diff --git a/src/controls/dev/ScrollPresenter/ScrollPresenterTypeLogging.cpp b/src/controls/dev/ScrollPresenter/ScrollPresenterTypeLogging.cpp index 1b1db068d9..701d146f38 100644 --- a/src/controls/dev/ScrollPresenter/ScrollPresenterTypeLogging.cpp +++ b/src/controls/dev/ScrollPresenter/ScrollPresenterTypeLogging.cpp @@ -247,16 +247,19 @@ winrt::hstring InteractionTrackerAsyncOperationTypeToString(InteractionTrackerAs winrt::hstring InteractionTrackerAsyncOperationTriggerToString(InteractionTrackerAsyncOperationTrigger operationTrigger) { - switch (operationTrigger) + switch (static_cast(operationTrigger)) { - case InteractionTrackerAsyncOperationTrigger::DirectViewChange: + case static_cast(InteractionTrackerAsyncOperationTrigger::DirectViewChange): return L"DirectViewChange"; - case InteractionTrackerAsyncOperationTrigger::HorizontalScrollControllerRequest: + case static_cast(InteractionTrackerAsyncOperationTrigger::HorizontalScrollControllerRequest): return L"HorizontalScrollControllerRequest"; - case InteractionTrackerAsyncOperationTrigger::VerticalScrollControllerRequest: + case static_cast(InteractionTrackerAsyncOperationTrigger::VerticalScrollControllerRequest): return L"VerticalScrollControllerRequest"; - case InteractionTrackerAsyncOperationTrigger::BringIntoViewRequest: + case static_cast(InteractionTrackerAsyncOperationTrigger::BringIntoViewRequest): return L"BringIntoViewRequest"; + case static_cast(InteractionTrackerAsyncOperationTrigger::HorizontalScrollControllerRequest) | + static_cast(InteractionTrackerAsyncOperationTrigger::VerticalScrollControllerRequest): + return L"HorizontalScrollControllerRequest | VerticalScrollControllerRequest"; default: MUX_ASSERT(false); return L""; diff --git a/src/controls/dev/ScrollPresenter/ScrollingViewChangingEventArgs.cpp b/src/controls/dev/ScrollPresenter/ScrollingViewChangingEventArgs.cpp new file mode 100644 index 0000000000..7cc46e22c3 --- /dev/null +++ b/src/controls/dev/ScrollPresenter/ScrollingViewChangingEventArgs.cpp @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include "pch.h" +#include "ScrollingViewChangingEventArgs.h" + +double ScrollingViewChangingEventArgs::HorizontalOffset() const +{ + return m_horizontalOffset; +} + +void ScrollingViewChangingEventArgs::SetHorizontalOffset(double horizontalOffset) +{ + m_horizontalOffset = horizontalOffset; +} + +double ScrollingViewChangingEventArgs::VerticalOffset() const +{ + return m_verticalOffset; +} + +void ScrollingViewChangingEventArgs::SetVerticalOffset(double verticalOffset) +{ + m_verticalOffset = verticalOffset; +} + +float ScrollingViewChangingEventArgs::ZoomFactor() const +{ + return m_zoomFactor; +} + +void ScrollingViewChangingEventArgs::SetZoomFactor(float zoomFactor) +{ + m_zoomFactor = zoomFactor; +} + +#ifdef DBG +int32_t ScrollingViewChangingEventArgs::CorrelationIdDbg() const +{ + return m_correlationIdDbg; +} + +void ScrollingViewChangingEventArgs::SetCorrelationIdDbg(int32_t correlationIdDbg) +{ + m_correlationIdDbg = correlationIdDbg; +} +#endif // DBG diff --git a/src/controls/dev/ScrollPresenter/ScrollingViewChangingEventArgs.h b/src/controls/dev/ScrollPresenter/ScrollingViewChangingEventArgs.h new file mode 100644 index 0000000000..fc95967326 --- /dev/null +++ b/src/controls/dev/ScrollPresenter/ScrollingViewChangingEventArgs.h @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#pragma once + +#include "ScrollPresenter.h" +#include "ScrollingViewChangingEventArgs.g.h" + +class ScrollingViewChangingEventArgs : + public winrt::implementation::ScrollingViewChangingEventArgsT +{ +public: + ScrollingViewChangingEventArgs() + { + SCROLLPRESENTER_TRACE_VERBOSE(nullptr, TRACE_MSG_METH, METH_NAME, this); + } + + ~ScrollingViewChangingEventArgs() + { + SCROLLPRESENTER_TRACE_VERBOSE(nullptr, TRACE_MSG_METH, METH_NAME, this); + } + + // IScrollingViewChangingEventArgs overrides + double HorizontalOffset() const; + double VerticalOffset() const; + float ZoomFactor() const; + + void SetHorizontalOffset(double horizontalOffset); + void SetVerticalOffset(double verticalOffset); + void SetZoomFactor(float zoomFactor); + +#ifdef DBG + int32_t CorrelationIdDbg() const; + void SetCorrelationIdDbg(int32_t correlationIdDbg); +#endif // DBG + +private: + double m_horizontalOffset{}; + double m_verticalOffset{}; + float m_zoomFactor{}; + +#ifdef DBG + int32_t m_correlationIdDbg{ -1 }; +#endif // DBG +}; diff --git a/src/controls/dev/ScrollPresenter/TestUI/ScrollPresenterDynamicPage.xaml.cs b/src/controls/dev/ScrollPresenter/TestUI/ScrollPresenterDynamicPage.xaml.cs index 220a975584..b5bdb16bcf 100644 --- a/src/controls/dev/ScrollPresenter/TestUI/ScrollPresenterDynamicPage.xaml.cs +++ b/src/controls/dev/ScrollPresenter/TestUI/ScrollPresenterDynamicPage.xaml.cs @@ -114,6 +114,11 @@ private void ScrollPresenter_StateChanged(ScrollPresenter sender, object args) AppendAsyncEventMessage("StateChanged " + sender.State.ToString()); } + private void ScrollPresenter_ViewChanging(ScrollPresenter sender, ScrollingViewChangingEventArgs args) + { + AppendAsyncEventMessage("ViewChanging H=" + args.HorizontalOffset.ToString() + ", V=" + args.VerticalOffset + ", ZF=" + args.ZoomFactor); + } + private void ScrollPresenter_ViewChanged(ScrollPresenter sender, object args) { AppendAsyncEventMessage("ViewChanged H=" + sender.HorizontalOffset.ToString() + ", V=" + sender.VerticalOffset + ", ZF=" + sender.ZoomFactor); @@ -265,6 +270,7 @@ private void ChkLogScrollPresenterEvents_Checked(object sender, RoutedEventArgs { scrollPresenter.ExtentChanged += ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged += ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging += ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged += ScrollPresenter_ViewChanged; scrollPresenter.ScrollCompleted += ScrollPresenter_ScrollCompleted; scrollPresenter.ZoomCompleted += ScrollPresenter_ZoomCompleted; @@ -276,6 +282,7 @@ private void ChkLogScrollPresenterEvents_Unchecked(object sender, RoutedEventArg { scrollPresenter.ExtentChanged -= ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged -= ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging -= ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged -= ScrollPresenter_ViewChanged; scrollPresenter.ScrollCompleted -= ScrollPresenter_ScrollCompleted; scrollPresenter.ZoomCompleted -= ScrollPresenter_ZoomCompleted; @@ -2613,6 +2620,7 @@ private void UseScrollPresenter(ScrollPresenter s) { scrollPresenter.ExtentChanged -= ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged -= ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging -= ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged -= ScrollPresenter_ViewChanged; scrollPresenter.ScrollCompleted -= ScrollPresenter_ScrollCompleted; scrollPresenter.ZoomCompleted -= ScrollPresenter_ZoomCompleted; @@ -2662,6 +2670,7 @@ private void UseScrollPresenter(ScrollPresenter s) { scrollPresenter.ExtentChanged += ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged += ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging += ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged += ScrollPresenter_ViewChanged; scrollPresenter.ScrollCompleted += ScrollPresenter_ScrollCompleted; scrollPresenter.ZoomCompleted += ScrollPresenter_ZoomCompleted; diff --git a/src/controls/dev/ScrollView/ScrollView.cpp b/src/controls/dev/ScrollView/ScrollView.cpp index 4fae470c44..d7201c020a 100644 --- a/src/controls/dev/ScrollView/ScrollView.cpp +++ b/src/controls/dev/ScrollView/ScrollView.cpp @@ -39,7 +39,7 @@ ScrollView::~ScrollView() UnhookCompositionTargetRendering(); UnhookScrollPresenterEvents(true /*isForDestructor*/); UnhookScrollViewEvents(); - ResetHideIndicatorsTimer(true /*isForDestructor*/); + ResetHideIndicatorsTimer(); } #pragma region IScrollView @@ -909,7 +909,9 @@ void ScrollView::OnHideIndicatorsTimerTick( if (AreScrollControllersAutoHiding()) { - HideIndicators(); + // As this control may be in the process of being discarded, + // use tracker_ref's safe_get() instead of get() to avoid crashes. + HideIndicators(true /*useTransitions*/, true /*useSafeGet*/); } } @@ -969,6 +971,18 @@ void ScrollView::OnZoomAnimationStarting( } } +void ScrollView::OnScrollPresenterViewChanging( + const winrt::IInspectable& /*sender*/, + const winrt::ScrollingViewChangingEventArgs& args) +{ + if (m_viewChangingEventSource) + { + SCROLLVIEW_TRACE_VERBOSE(*this, TRACE_MSG_METH, METH_NAME, this); + + m_viewChangingEventSource(*this, args); + } +} + void ScrollView::OnScrollPresenterViewChanged( const winrt::IInspectable& /*sender*/, const winrt::IInspectable& args) @@ -1131,16 +1145,14 @@ void ScrollView::OnScrollPresenterPropertyChanged( } } -void ScrollView::ResetHideIndicatorsTimer(bool isForDestructor, bool restart) +void ScrollView::ResetHideIndicatorsTimer(bool restart) { - auto hideIndicatorsTimer = m_hideIndicatorsTimer.safe_get(isForDestructor /*useSafeGet*/); - - if (hideIndicatorsTimer && hideIndicatorsTimer.IsEnabled()) + if (m_hideIndicatorsTimer && m_hideIndicatorsTimer.IsEnabled()) { - hideIndicatorsTimer.Stop(); + m_hideIndicatorsTimer.Stop(); if (restart) { - hideIndicatorsTimer.Start(); + m_hideIndicatorsTimer.Start(); } } } @@ -1259,6 +1271,7 @@ void ScrollView::HookScrollPresenterEvents() MUX_ASSERT(m_scrollPresenterStateChangedToken.value == 0); MUX_ASSERT(m_scrollPresenterScrollAnimationStartingToken.value == 0); MUX_ASSERT(m_scrollPresenterZoomAnimationStartingToken.value == 0); + MUX_ASSERT(m_scrollPresenterViewChangingToken.value == 0); MUX_ASSERT(m_scrollPresenterViewChangedToken.value == 0); MUX_ASSERT(m_scrollPresenterScrollCompletedToken.value == 0); MUX_ASSERT(m_scrollPresenterZoomCompletedToken.value == 0); @@ -1279,6 +1292,13 @@ void ScrollView::HookScrollPresenterEvents() m_scrollPresenterBringingIntoViewToken = scrollPresenter.BringingIntoView({ this, &ScrollView::OnScrollPresenterBringingIntoView }); m_scrollPresenterAnchorRequestedToken = scrollPresenter.AnchorRequested({ this, &ScrollView::OnScrollPresenterAnchorRequested }); + const winrt::IScrollPresenter2 scrollPresenter2 = scrollPresenter.try_as(); + + if (scrollPresenter2) + { + m_scrollPresenterViewChangingToken = scrollPresenter2.ViewChanging({ this, &ScrollView::OnScrollPresenterViewChanging }); + } + const winrt::DependencyObject scrollPresenterAsDO = scrollPresenter.try_as(); m_scrollPresenterComputedHorizontalScrollModeChangedToken.value = scrollPresenterAsDO.RegisterPropertyChangedCallback( @@ -1326,6 +1346,18 @@ void ScrollView::UnhookScrollPresenterEvents(bool isForDestructor) m_scrollPresenterZoomAnimationStartingToken.value = 0; } + if (m_scrollPresenterViewChangingToken.value != 0) + { + const winrt::IScrollPresenter2 scrollPresenter2 = scrollPresenter.try_as(); + + if (scrollPresenter2) + { + scrollPresenter2.ViewChanging(m_scrollPresenterViewChangingToken); + } + + m_scrollPresenterViewChangingToken.value = 0; + } + if (m_scrollPresenterViewChangedToken.value != 0) { scrollPresenter.ViewChanged(m_scrollPresenterViewChangedToken); @@ -1650,10 +1682,13 @@ bool ScrollView::IsInputKindIgnored(winrt::ScrollingInputKinds const& inputKind) return (IgnoredInputKinds() & inputKind) == inputKind; } -bool ScrollView::AreAllScrollControllersCollapsed() const +bool ScrollView::AreAllScrollControllersCollapsed(bool useSafeGet) const { - return !SharedHelpers::IsAncestor(m_horizontalScrollControllerElement.try_as() /*child*/, static_cast(*this) /*parent*/, true /*checkVisibility*/) && - !SharedHelpers::IsAncestor(m_verticalScrollControllerElement.try_as() /*child*/, static_cast(*this) /*parent*/, true /*checkVisibility*/); + return + (m_horizontalScrollControllerElement.safe_get(useSafeGet) == nullptr || + !SharedHelpers::IsAncestor(m_horizontalScrollControllerElement.try_as() /*child*/, static_cast(*this) /*parent*/, true /*checkVisibility*/)) && + (m_verticalScrollControllerElement.safe_get(useSafeGet) == nullptr || + !SharedHelpers::IsAncestor(m_verticalScrollControllerElement.try_as() /*child*/, static_cast(*this) /*parent*/, true /*checkVisibility*/)); } bool ScrollView::AreBothScrollControllersVisible() const @@ -1668,13 +1703,14 @@ bool ScrollView::IsScrollControllersSeparatorVisible() const } void ScrollView::HideIndicators( - bool useTransitions) + bool useTransitions, + bool useSafeGet) { SCROLLVIEW_TRACE_VERBOSE(*this, TRACE_MSG_METH_INT_INT, METH_NAME, this, useTransitions, m_keepIndicatorsShowing); MUX_ASSERT(AreScrollControllersAutoHiding()); - if (!AreAllScrollControllersCollapsed() && !m_keepIndicatorsShowing) + if (!AreAllScrollControllersCollapsed(useSafeGet) && !m_keepIndicatorsShowing) { GoToState(s_noIndicatorStateName, useTransitions); @@ -1693,25 +1729,21 @@ void ScrollView::HideIndicatorsAfterDelay() if (!m_keepIndicatorsShowing && IsLoaded()) { - winrt::DispatcherTimer hideIndicatorsTimer = nullptr; - if (m_hideIndicatorsTimer) { - hideIndicatorsTimer = m_hideIndicatorsTimer.get(); - if (hideIndicatorsTimer.IsEnabled()) + if (m_hideIndicatorsTimer.IsEnabled()) { - hideIndicatorsTimer.Stop(); + m_hideIndicatorsTimer.Stop(); } } else { - hideIndicatorsTimer = winrt::DispatcherTimer(); - hideIndicatorsTimer.Interval(winrt::TimeSpan::duration(s_noIndicatorCountdown)); - hideIndicatorsTimer.Tick({ this, &ScrollView::OnHideIndicatorsTimerTick }); - m_hideIndicatorsTimer.set(hideIndicatorsTimer); + m_hideIndicatorsTimer = winrt::DispatcherTimer(); + m_hideIndicatorsTimer.Interval(winrt::TimeSpan::duration(s_noIndicatorCountdown)); + m_hideIndicatorsTimer.Tick({ this, &ScrollView::OnHideIndicatorsTimerTick }); } - hideIndicatorsTimer.Start(); + m_hideIndicatorsTimer.Start(); } } @@ -1759,7 +1791,7 @@ void ScrollView::UpdateScrollControllersVisualState( return; } - ResetHideIndicatorsTimer(false /*isForDestructor*/, true /*restart*/); + ResetHideIndicatorsTimer(true /*restart*/); // Mouse indicators dominate if they are already showing or if we have set the flag to prefer them. if (m_preferMouseIndicators || m_showingMouseIndicators || !areScrollControllersAutoHiding) diff --git a/src/controls/dev/ScrollView/ScrollView.h b/src/controls/dev/ScrollView/ScrollView.h index a0362266f0..d1c13066c6 100644 --- a/src/controls/dev/ScrollView/ScrollView.h +++ b/src/controls/dev/ScrollView/ScrollView.h @@ -176,6 +176,9 @@ class ScrollView : void OnZoomAnimationStarting( const winrt::IInspectable& sender, const winrt::ScrollingZoomAnimationStartingEventArgs& args); + void OnScrollPresenterViewChanging( + const winrt::IInspectable& sender, + const winrt::ScrollingViewChangingEventArgs& args); void OnScrollPresenterViewChanged( const winrt::IInspectable& sender, const winrt::IInspectable& args); @@ -198,7 +201,7 @@ class ScrollView : const winrt::IInspectable& sender, const winrt::IInspectable& args); - void ResetHideIndicatorsTimer(bool isForDestructor = false, bool restart = false); + void ResetHideIndicatorsTimer(bool restart = false); void HookUISettingsEvent(); void HookCompositionTargetRendering(); @@ -226,11 +229,11 @@ class ScrollView : bool IsInputKindIgnored(winrt::ScrollingInputKinds const& inputKind); - bool AreAllScrollControllersCollapsed() const; + bool AreAllScrollControllersCollapsed(bool useSafeGet = false) const; bool AreBothScrollControllersVisible() const; bool AreScrollControllersAutoHiding(); bool IsScrollControllersSeparatorVisible() const; - void HideIndicators(bool useTransitions = true); + void HideIndicators(bool useTransitions = true, bool useSafeGet = false); void HideIndicatorsAfterDelay(); void UpdateScrollControllersAutoHiding(bool forceUpdate = false); void UpdateVisualStates( @@ -282,7 +285,8 @@ class ScrollView : tracker_ref m_verticalScrollControllerElement{ this }; tracker_ref m_scrollControllersSeparatorElement{ this }; tracker_ref m_scrollPresenter{ this }; - tracker_ref m_hideIndicatorsTimer{ this }; + + winrt::DispatcherTimer m_hideIndicatorsTimer{ nullptr }; // Event Tokens winrt::event_token m_gettingFocusToken{}; @@ -293,6 +297,7 @@ class ScrollView : winrt::event_token m_scrollPresenterStateChangedToken{}; winrt::event_token m_scrollPresenterScrollAnimationStartingToken{}; winrt::event_token m_scrollPresenterZoomAnimationStartingToken{}; + winrt::event_token m_scrollPresenterViewChangingToken{}; winrt::event_token m_scrollPresenterViewChangedToken{}; winrt::event_token m_scrollPresenterScrollCompletedToken{}; winrt::event_token m_scrollPresenterZoomCompletedToken{}; @@ -365,7 +370,7 @@ class ScrollView : // Private constants // 2 seconds delay used to hide the indicators for example when OS animations are turned off. - static constexpr int64_t s_noIndicatorCountdown = 2000 * 10000; + static constexpr int64_t s_noIndicatorCountdown = 2000 * 10000; static constexpr std::wstring_view s_noIndicatorStateName{ L"NoIndicator"sv }; static constexpr std::wstring_view s_touchIndicatorStateName{ L"TouchIndicator"sv }; @@ -380,4 +385,4 @@ class ScrollView : }; extern template void std::default_delete::operator()(ScrollView::AutoHideScrollBarsState*) const noexcept; -extern template void std::default_delete::operator()(const ScrollView::AutoHideScrollBarsState*) const noexcept; \ No newline at end of file +extern template void std::default_delete::operator()(const ScrollView::AutoHideScrollBarsState*) const noexcept; diff --git a/src/controls/dev/ScrollView/ScrollView.idl b/src/controls/dev/ScrollView/ScrollView.idl index 7035bae701..1da02a0b27 100644 --- a/src/controls/dev/ScrollView/ScrollView.idl +++ b/src/controls/dev/ScrollView/ScrollView.idl @@ -133,6 +133,9 @@ unsealed runtimeclass ScrollView : Microsoft.UI.Xaml.Controls.Control event Windows.Foundation.TypedEventHandler BringingIntoView; event Windows.Foundation.TypedEventHandler AnchorRequested; + [MUX_PREVIEW] + event Windows.Foundation.TypedEventHandler ViewChanging; + static Microsoft.UI.Xaml.DependencyProperty ContentProperty { get; }; static Microsoft.UI.Xaml.DependencyProperty ScrollPresenterProperty { get; }; static Microsoft.UI.Xaml.DependencyProperty HorizontalScrollBarVisibilityProperty { get; }; diff --git a/src/controls/dev/ScrollView/TestUI/ScrollViewBlankPage.xaml.cs b/src/controls/dev/ScrollView/TestUI/ScrollViewBlankPage.xaml.cs index 4b63df94d1..680bfb3c4b 100644 --- a/src/controls/dev/ScrollView/TestUI/ScrollViewBlankPage.xaml.cs +++ b/src/controls/dev/ScrollView/TestUI/ScrollViewBlankPage.xaml.cs @@ -7,6 +7,10 @@ using ScrollPresenter = Microsoft.UI.Xaml.Controls.Primitives.ScrollPresenter; using ScrollView = Microsoft.UI.Xaml.Controls.ScrollView; +using ScrollingScrollOptions = Microsoft.UI.Xaml.Controls.ScrollingScrollOptions; +using ScrollingAnimationMode = Microsoft.UI.Xaml.Controls.ScrollingAnimationMode; +using ScrollingSnapPointsMode = Microsoft.UI.Xaml.Controls.ScrollingSnapPointsMode; +using ScrollingViewChangingEventArgs = Microsoft.UI.Xaml.Controls.ScrollingViewChangingEventArgs; using ScrollingScrollAnimationStartingEventArgs = Microsoft.UI.Xaml.Controls.ScrollingScrollAnimationStartingEventArgs; using ScrollingZoomAnimationStartingEventArgs = Microsoft.UI.Xaml.Controls.ScrollingZoomAnimationStartingEventArgs; using ScrollingScrollCompletedEventArgs = Microsoft.UI.Xaml.Controls.ScrollingScrollCompletedEventArgs; @@ -159,9 +163,14 @@ private void ScrollPresenter_StateChanged(ScrollPresenter sender, object args) AppendAsyncEventMessage($"ScrollPresenter.StateChanged {sender.State.ToString()}"); } + private void ScrollPresenter_ViewChanging(ScrollPresenter sender, ScrollingViewChangingEventArgs args) + { + AppendAsyncEventMessage($"ScrollPresenter.ViewChanging HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + } + private void ScrollPresenter_ViewChanged(ScrollPresenter sender, object args) { - AppendAsyncEventMessage($"ScrollPresenter.ViewChanged HorizontalOffset={sender.HorizontalOffset.ToString()}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); + AppendAsyncEventMessage($"ScrollPresenter.ViewChanged HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); } private void ScrollPresenter_ScrollAnimationStarting(ScrollPresenter sender, ScrollingScrollAnimationStartingEventArgs args) @@ -194,9 +203,14 @@ private void ScrollView_StateChanged(ScrollView sender, object args) AppendAsyncEventMessage($"ScrollView.StateChanged {sender.State.ToString()}"); } + private void ScrollView_ViewChanging(ScrollView sender, ScrollingViewChangingEventArgs args) + { + AppendAsyncEventMessage($"ScrollView.ViewChanging HorizontalOffset={args.HorizontalOffset}, VerticalOffset={args.VerticalOffset}, ZoomFactor={args.ZoomFactor}"); + } + private void ScrollView_ViewChanged(ScrollView sender, object args) { - AppendAsyncEventMessage($"ScrollView.ViewChanged HorizontalOffset={sender.HorizontalOffset.ToString()}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); + AppendAsyncEventMessage($"ScrollView.ViewChanged HorizontalOffset={sender.HorizontalOffset}, VerticalOffset={sender.VerticalOffset}, ZoomFactor={sender.ZoomFactor}"); } private void ScrollView_ScrollAnimationStarting(ScrollView sender, ScrollingScrollAnimationStartingEventArgs args) @@ -254,6 +268,7 @@ private void ChkLogScrollPresenterEvents_Checked(object sender, RoutedEventArgs scrollPresenter.SizeChanged += ScrollPresenter_SizeChanged; scrollPresenter.ExtentChanged += ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged += ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging += ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged += ScrollPresenter_ViewChanged; scrollPresenter.ScrollAnimationStarting += ScrollPresenter_ScrollAnimationStarting; scrollPresenter.ZoomAnimationStarting += ScrollPresenter_ZoomAnimationStarting; @@ -275,6 +290,7 @@ private void ChkLogScrollPresenterEvents_Unchecked(object sender, RoutedEventArg scrollPresenter.SizeChanged -= ScrollPresenter_SizeChanged; scrollPresenter.ExtentChanged -= ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged -= ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging -= ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged -= ScrollPresenter_ViewChanged; scrollPresenter.ScrollAnimationStarting -= ScrollPresenter_ScrollAnimationStarting; scrollPresenter.ZoomAnimationStarting -= ScrollPresenter_ZoomAnimationStarting; @@ -296,6 +312,7 @@ private void ChkLogScrollViewEvents_Checked(object sender, RoutedEventArgs e) scrollView.SizeChanged += ScrollView_SizeChanged; scrollView.ExtentChanged += ScrollView_ExtentChanged; scrollView.StateChanged += ScrollView_StateChanged; + scrollView.ViewChanging += ScrollView_ViewChanging; scrollView.ViewChanged += ScrollView_ViewChanged; scrollView.ScrollAnimationStarting += ScrollView_ScrollAnimationStarting; scrollView.ZoomAnimationStarting += ScrollView_ZoomAnimationStarting; @@ -316,6 +333,7 @@ private void ChkLogScrollViewEvents_Unchecked(object sender, RoutedEventArgs e) scrollView.SizeChanged -= ScrollView_SizeChanged; scrollView.ExtentChanged -= ScrollView_ExtentChanged; scrollView.StateChanged -= ScrollView_StateChanged; + scrollView.ViewChanging -= ScrollView_ViewChanging; scrollView.ViewChanged -= ScrollView_ViewChanged; scrollView.ScrollAnimationStarting -= ScrollView_ScrollAnimationStarting; scrollView.ZoomAnimationStarting -= ScrollView_ZoomAnimationStarting; diff --git a/src/controls/dev/ScrollView/TestUI/ScrollViewDynamicPage.xaml.cs b/src/controls/dev/ScrollView/TestUI/ScrollViewDynamicPage.xaml.cs index a6466ad1c6..b114f1b950 100644 --- a/src/controls/dev/ScrollView/TestUI/ScrollViewDynamicPage.xaml.cs +++ b/src/controls/dev/ScrollView/TestUI/ScrollViewDynamicPage.xaml.cs @@ -1893,6 +1893,7 @@ private void UseScrollView(ScrollView sv2) { scrollView.ExtentChanged -= ScrollView_ExtentChanged; scrollView.StateChanged -= ScrollView_StateChanged; + scrollView.ViewChanging -= ScrollView_ViewChanging; scrollView.ViewChanged -= ScrollView_ViewChanged; scrollView.ScrollAnimationStarting -= ScrollView_ScrollAnimationStarting; scrollView.ZoomAnimationStarting -= ScrollView_ZoomAnimationStarting; @@ -1908,6 +1909,7 @@ private void UseScrollView(ScrollView sv2) { scrollPresenter.ExtentChanged -= ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged -= ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging -= ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged -= ScrollPresenter_ViewChanged; scrollPresenter.ScrollAnimationStarting -= ScrollPresenter_ScrollAnimationStarting; scrollPresenter.ZoomAnimationStarting -= ScrollPresenter_ZoomAnimationStarting; @@ -1970,6 +1972,7 @@ private void UseScrollView(ScrollView sv2) { scrollView.ExtentChanged += ScrollView_ExtentChanged; scrollView.StateChanged += ScrollView_StateChanged; + scrollView.ViewChanging += ScrollView_ViewChanging; scrollView.ViewChanged += ScrollView_ViewChanged; scrollView.ScrollAnimationStarting += ScrollView_ScrollAnimationStarting; scrollView.ZoomAnimationStarting += ScrollView_ZoomAnimationStarting; @@ -1986,6 +1989,7 @@ private void UseScrollView(ScrollView sv2) { scrollPresenter.ExtentChanged += ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged += ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging += ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged += ScrollPresenter_ViewChanged; scrollPresenter.ScrollAnimationStarting += ScrollPresenter_ScrollAnimationStarting; scrollPresenter.ZoomAnimationStarting += ScrollPresenter_ZoomAnimationStarting; @@ -2095,6 +2099,11 @@ private void ScrollPresenter_StateChanged(ScrollPresenter sender, object args) AppendAsyncEventMessage("ScrollPresenter.StateChanged " + sender.State.ToString()); } + private void ScrollPresenter_ViewChanging(ScrollPresenter sender, ScrollingViewChangingEventArgs args) + { + AppendAsyncEventMessage("ScrollPresenter.ViewChanging H=" + args.HorizontalOffset.ToString() + ", V=" + args.VerticalOffset + ", ZF=" + args.ZoomFactor); + } + private void ScrollPresenter_ViewChanged(ScrollPresenter sender, object args) { AppendAsyncEventMessage("ScrollPresenter.ViewChanged H=" + sender.HorizontalOffset.ToString() + ", V=" + sender.VerticalOffset + ", ZF=" + sender.ZoomFactor); @@ -2125,6 +2134,11 @@ private void ScrollView_StateChanged(ScrollView sender, object args) AppendAsyncEventMessage("ScrollView.StateChanged " + sender.State.ToString()); } + private void ScrollView_ViewChanging(ScrollView sender, ScrollingViewChangingEventArgs args) + { + AppendAsyncEventMessage("ScrollView.ViewChanging H=" + args.HorizontalOffset.ToString() + ", V=" + args.VerticalOffset + ", ZF=" + args.ZoomFactor); + } + private void ScrollView_ViewChanged(ScrollView sender, object args) { AppendAsyncEventMessage("ScrollView.ViewChanged H=" + sender.HorizontalOffset.ToString() + ", V=" + sender.VerticalOffset + ", ZF=" + sender.ZoomFactor); @@ -2201,6 +2215,7 @@ private void ChkLogScrollPresenterEvents_Checked(object sender, RoutedEventArgs { scrollPresenter.ExtentChanged += ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged += ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging += ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged += ScrollPresenter_ViewChanged; scrollPresenter.ScrollAnimationStarting += ScrollPresenter_ScrollAnimationStarting; scrollPresenter.ZoomAnimationStarting += ScrollPresenter_ZoomAnimationStarting; @@ -2223,6 +2238,7 @@ private void ChkLogScrollPresenterEvents_Unchecked(object sender, RoutedEventArg { scrollPresenter.ExtentChanged -= ScrollPresenter_ExtentChanged; scrollPresenter.StateChanged -= ScrollPresenter_StateChanged; + scrollPresenter.ViewChanging -= ScrollPresenter_ViewChanging; scrollPresenter.ViewChanged -= ScrollPresenter_ViewChanged; scrollPresenter.ScrollAnimationStarting -= ScrollPresenter_ScrollAnimationStarting; scrollPresenter.ZoomAnimationStarting -= ScrollPresenter_ZoomAnimationStarting; @@ -2240,6 +2256,7 @@ private void ChkLogScrollViewEvents_Checked(object sender, RoutedEventArgs e) { scrollView.ExtentChanged += ScrollView_ExtentChanged; scrollView.StateChanged += ScrollView_StateChanged; + scrollView.ViewChanging += ScrollView_ViewChanging; scrollView.ViewChanged += ScrollView_ViewChanged; scrollView.ScrollAnimationStarting += ScrollView_ScrollAnimationStarting; scrollView.ZoomAnimationStarting += ScrollView_ZoomAnimationStarting; @@ -2257,6 +2274,7 @@ private void ChkLogScrollViewEvents_Unchecked(object sender, RoutedEventArgs e) { scrollView.ExtentChanged -= ScrollView_ExtentChanged; scrollView.StateChanged -= ScrollView_StateChanged; + scrollView.ViewChanging -= ScrollView_ViewChanging; scrollView.ViewChanged -= ScrollView_ViewChanged; scrollView.ScrollAnimationStarting -= ScrollView_ScrollAnimationStarting; scrollView.ZoomAnimationStarting -= ScrollView_ZoomAnimationStarting; diff --git a/src/controls/dev/SplitView/SplitView_themeresources.xaml b/src/controls/dev/SplitView/SplitView_themeresources.xaml index 9fff18bfa1..84cc5a983f 100644 --- a/src/controls/dev/SplitView/SplitView_themeresources.xaml +++ b/src/controls/dev/SplitView/SplitView_themeresources.xaml @@ -508,7 +508,8 @@ - + + diff --git a/src/controls/dev/SwipeControl/SwipeControl.cpp b/src/controls/dev/SwipeControl/SwipeControl.cpp index 7212394b6e..286e9bb608 100644 --- a/src/controls/dev/SwipeControl/SwipeControl.cpp +++ b/src/controls/dev/SwipeControl/SwipeControl.cpp @@ -743,8 +743,8 @@ void SwipeControl::DismissSwipeOnAnExternalTap(winrt::Point const& tapPoint) // If point is not within the item's bounds, close it. if (*this && tapPoint.X < transformedElementOrigin.X || tapPoint.Y < transformedElementOrigin.Y || - (tapPoint.X - transformedElementOrigin.X) > ActualWidth() || - (tapPoint.Y - transformedElementOrigin.Y) > ActualHeight()) + (static_cast(tapPoint.X) - transformedElementOrigin.X) > ActualWidth() || + (static_cast(tapPoint.Y) - transformedElementOrigin.Y) > ActualHeight()) { CloseIfNotRemainOpenExecuteItem(); } diff --git a/src/controls/dev/TabView/InteractionTests/TabViewTearOutTests.cs b/src/controls/dev/TabView/InteractionTests/TabViewTearOutTests.cs new file mode 100644 index 0000000000..2e07636c50 --- /dev/null +++ b/src/controls/dev/TabView/InteractionTests/TabViewTearOutTests.cs @@ -0,0 +1,371 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; +using Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests.Infra; +using Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests.Common; + +using WEX.TestExecution; +using WEX.TestExecution.Markup; +using WEX.Logging.Interop; + +using Microsoft.Windows.Apps.Test.Automation; +using Microsoft.Windows.Apps.Test.Foundation; +using Microsoft.Windows.Apps.Test.Foundation.Controls; +using Microsoft.Windows.Apps.Test.Foundation.Patterns; +using Microsoft.Windows.Apps.Test.Foundation.Waiters; +using MUXTestInfra.Shared.Infra; +using System.Linq; +using System.Collections.Generic; +using System; + +namespace Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests +{ + [TestClass] + public class TabViewTearOutTests + { + private static TestApplicationInfo _tabViewTearOutApp; + + public static TestApplicationInfo TabViewTearOutApp + { + get + { + if (_tabViewTearOutApp == null) + { + _tabViewTearOutApp = new TestApplicationInfo( + "TabViewTearOutApp_6f07fta6qpts2", + "Tab Tear-Out App", + Path.Combine("TabViewTearOutApp", "TabViewTearOutApp.exe")); + } + + return _tabViewTearOutApp; + } + } + + [ClassInitialize] + [TestProperty("RunAs", "User")] + [TestProperty("Classification", "Integration")] + [TestProperty("Platform", "Any")] + [TestProperty("IsolationLevel", "Method")] // These tests create and destroy windows, so we'll isolate each test to ensure we start with a known good state each time. + public static void ClassInitialize(TestContext testContext) + { + // These tests involve multiple windows, so don't bother maximizing the window at the start of tests. + testContext.Properties.Add("MaximizeWindowAtStart", false); + + TestEnvironment.Initialize(testContext, TabViewTearOutApp); + } + + [ClassCleanup] + public static void ClassCleanup() + { + TestEnvironment.AssemblyCleanupWorker(TabViewTearOutApp); + } + + [TestCleanup] + public static void TestCleanup() + { + var testAppProcess = TestEnvironment.Application.Process; + + if (testAppProcess != null && !testAppProcess.HasExited) + { + testAppProcess.Kill(); + } + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs enables the tearing out of tabs into new windows, and the rejoining of those tabs into existing windows.")] + public void CanTearOutAndRejoinTabs() + { + TabViewTearOutTestHelpers.CanTearOutAndRejoinTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs does not prevent internally reordering tabs.")] + [TestProperty("Ignore", "True")] // Task 50591398: Re-enable tests when we ingest the latest Microsoft.UI.Input.dll + public void CanReorderTabs() + { + TabViewTearOutTestHelpers.CanReorderTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs does not prevent selecting tabs.")] + public void CanSelectTabs() + { + TabViewTearOutTestHelpers.CanSelectTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + + private static readonly UICondition _windowCondition = + UICondition.CreateFromClassName("WinUIDesktopWin32WindowClass") + .AndWith(UICondition.CreateFromName(TabViewTearOutApp.TestAppMainWindowTitle)); + + private static readonly UICondition _tabViewCondition = + UICondition.CreateFromName("TearOutTabsTabView"); + + private static readonly UICondition _tabCondition = + UICondition.CreateFromClassName("ListViewItem"); + + private static List GetTabViewTearOutAppWindows() + { + return UIObject.Root.Children.FindMultiple(_windowCondition).Select(o => new Window(o)).ToList(); + } + + private static Tab GetTabViewFromWindow(Window window) + { + return new Tab(window.Descendants.Find(_tabViewCondition)); + } + + private static List GetTabsFromTabView(Tab tabView) + { + return tabView.Descendants.FindMultiple(_tabCondition).Select(o => new TabItem(o)).ToList(); + } + } + + public static class TabViewTearOutTestHelpers + { + public static void CanTearOutAndRejoinTabs( + Func> getTabViewTearOutAppWindowsFunc, + Func getTabViewFromWindowFunc, + Func> getTabsFromTabViewFunc) + { + try + { + Log.Comment("We should begin with only one window."); + + var windows = getTabViewTearOutAppWindowsFunc(); + + Verify.AreEqual(1, windows.Count); + + var window = windows.First(); + + var tabView = getTabViewFromWindowFunc(window); + var tabs = getTabsFromTabViewFunc(tabView); + + Log.Comment("The window should have three tabs in the order 1, 2, 3."); + + Verify.AreEqual(3, tabs.Count); + Verify.AreEqual("Item 1", tabs[0].Name); + Verify.AreEqual("Item 2", tabs[1].Name); + Verify.AreEqual("Item 3", tabs[2].Name); + + Log.Comment("Let's ensure the window is visible prior to dragging on it."); + + window.SetWindowVisualState(WindowVisualState.Normal); + + Log.Comment("Now we'll tear out the first tab."); + + InputHelper.MouseDragDistance(tabs[0], distance: 300, Direction.South, duration: 1000); + + Log.Comment("We should now have two windows: the first with two tabs in the order 2, 3; and the second with one tab that is 1."); + + windows = getTabViewTearOutAppWindowsFunc(); + Verify.AreEqual(2, windows.Count); + + // The new window is the one that contains Item 1. + var newWindow = windows.Where(w => w.Descendants.TryFind(UICondition.CreateFromName("Item 1"), out _)).First(); + var newWindowTabView = getTabViewFromWindowFunc(newWindow); + + tabs = getTabsFromTabViewFunc(tabView); + var newTabs = getTabsFromTabViewFunc(newWindowTabView); + + Verify.AreEqual(2, tabs.Count); + Verify.AreEqual("Item 2", tabs[0].Name); + Verify.AreEqual("Item 3", tabs[1].Name); + Verify.AreEqual(1, newTabs.Count); + Verify.AreEqual("Item 1", newTabs[0].Name); + + Log.Comment("Let's ensure the second window is visible prior to dragging on it."); + + newWindow.SetWindowVisualState(WindowVisualState.Normal); + + using (var closingWaiter = newWindow.GetWindowClosedWaiter()) + { + Log.Comment("Now we'll drag the torn out tab to the end of the original tab view. This should merge the tab to the end the original tab view and close the second window."); + + var addNewTabButton = tabView.Descendants.Find(UICondition.CreateFromName("Add New Tab")); + + InputHelper.MouseDragToTarget(newTabs[0], addNewTabButton); + closingWaiter.Wait(); + } + + Log.Comment("We should now have one windows with three tabs in the order 2, 3, 1."); + + windows = getTabViewTearOutAppWindowsFunc(); + tabs = getTabsFromTabViewFunc(tabView); + + Verify.AreEqual(1, windows.Count); + Verify.AreEqual(3, tabs.Count); + Verify.AreEqual("Item 2", tabs[0].Name); + Verify.AreEqual("Item 3", tabs[1].Name); + Verify.AreEqual("Item 1", tabs[2].Name); + } + finally + { + foreach (Window window in getTabViewTearOutAppWindowsFunc()) + { + using (var closingWaiter = window.GetWindowClosedWaiter()) + { + window.Close(); + closingWaiter.Wait(); + } + } + } + } + + public static void CanReorderTabs( + Func> getTabViewTearOutAppWindowsFunc, + Func getTabViewFromWindowFunc, + Func> getTabsFromTabViewFunc) + { + try + { + Log.Comment("We should begin with only one window."); + + var windows = getTabViewTearOutAppWindowsFunc(); + + Verify.AreEqual(1, windows.Count); + + var window = windows.First(); + + var tabView = getTabViewFromWindowFunc(window); + var tabs = getTabsFromTabViewFunc(tabView); + + Log.Comment("The window should have three tabs in the order 1, 2, 3."); + + Verify.AreEqual(3, tabs.Count); + Verify.AreEqual("Item 1", tabs[0].Name); + Verify.AreEqual("Item 2", tabs[1].Name); + Verify.AreEqual("Item 3", tabs[2].Name); + + Log.Comment("Let's ensure the window is visible prior to dragging on it."); + + window.SetWindowVisualState(WindowVisualState.Normal); + + Log.Comment("Now we'll drag tab 1 to the right side of tab 2."); + + InputHelper.MouseDragToTarget(tabs[0], tabs[1], 50); + + Log.Comment("We should still have only one window."); + + windows = getTabViewTearOutAppWindowsFunc(); + + Verify.AreEqual(1, windows.Count); + + tabs = getTabsFromTabViewFunc(tabView); + + Log.Comment("The window should now have three tabs in the order 2, 1, 3."); + + Verify.AreEqual(3, tabs.Count); + Verify.AreEqual("Item 2", tabs[0].Name); + Verify.AreEqual("Item 1", tabs[1].Name); + Verify.AreEqual("Item 3", tabs[2].Name); + + window.SetWindowVisualState(WindowVisualState.Normal); + + Log.Comment("Now we'll drag tab 3 to the left side of tab 2."); + + InputHelper.MouseDragToTarget(tabs[2], tabs[0], -50); + + Log.Comment("We should still have only one window."); + + windows = getTabViewTearOutAppWindowsFunc(); + + Verify.AreEqual(1, windows.Count); + + tabs = getTabsFromTabViewFunc(tabView); + + Log.Comment("The window should now have three tabs in the order 3, 2, 1."); + + Verify.AreEqual(3, tabs.Count); + Verify.AreEqual("Item 3", tabs[0].Name); + Verify.AreEqual("Item 2", tabs[1].Name); + Verify.AreEqual("Item 1", tabs[2].Name); + } + finally + { + foreach (Window window in getTabViewTearOutAppWindowsFunc()) + { + using (var closingWaiter = window.GetWindowClosedWaiter()) + { + window.Close(); + closingWaiter.Wait(); + } + } + } + } + public static void CanSelectTabs( + Func> getTabViewTearOutAppWindowsFunc, + Func getTabViewFromWindowFunc, + Func> getTabsFromTabViewFunc) + { + try + { + Log.Comment("We should begin with only one window."); + + var windows = getTabViewTearOutAppWindowsFunc(); + + Verify.AreEqual(1, windows.Count); + + var window = windows.First(); + + var tabView = getTabViewFromWindowFunc(windows[0]); + var tabs = getTabsFromTabViewFunc(tabView); + + Log.Comment("The window should have three tabs in the order 1, 2, 3."); + + Verify.AreEqual(3, tabs.Count); + Verify.AreEqual("Item 1", tabs[0].Name); + Verify.AreEqual("Item 2", tabs[1].Name); + Verify.AreEqual("Item 3", tabs[2].Name); + + Log.Comment("The first tab should be selected."); + + Verify.IsTrue(tabs[0].IsSelected); + Verify.IsFalse(tabs[1].IsSelected); + Verify.IsFalse(tabs[2].IsSelected); + + Log.Comment("Let's ensure the window is visible prior to clicking on it."); + + window.SetWindowVisualState(WindowVisualState.Normal); + + Log.Comment("Now we'll click on tab 2. It should be selected."); + + InputHelper.LeftClick(tabs[1]); + + Verify.IsFalse(tabs[0].IsSelected); + Verify.IsTrue(tabs[1].IsSelected); + Verify.IsFalse(tabs[2].IsSelected); + + window.SetWindowVisualState(WindowVisualState.Normal); + + Log.Comment("Now we'll click on tab 3. It should be selected."); + + InputHelper.LeftClick(tabs[2]); + + Verify.IsFalse(tabs[0].IsSelected); + Verify.IsFalse(tabs[1].IsSelected); + Verify.IsTrue(tabs[2].IsSelected); + + window.SetWindowVisualState(WindowVisualState.Normal); + + Log.Comment("Now we'll click on tab 1. It should be selected."); + + InputHelper.LeftClick(tabs[0]); + + Verify.IsTrue(tabs[0].IsSelected); + Verify.IsFalse(tabs[1].IsSelected); + Verify.IsFalse(tabs[2].IsSelected); + } + finally + { + foreach (Window window in getTabViewTearOutAppWindowsFunc()) + { + using (var closingWaiter = window.GetWindowClosedWaiter()) + { + window.Close(); + closingWaiter.Wait(); + } + } + } + } + } +} diff --git a/src/controls/dev/TabView/InteractionTests/TabViewTests.cs b/src/controls/dev/TabView/InteractionTests/TabViewTests.cs index 7b21fc2a24..9735303a5d 100644 --- a/src/controls/dev/TabView/InteractionTests/TabViewTests.cs +++ b/src/controls/dev/TabView/InteractionTests/TabViewTests.cs @@ -19,6 +19,7 @@ using Microsoft.Windows.Apps.Test.Foundation.Waiters; using Windows.Devices.Input; using MUXTestInfra.Shared.Infra; +using System.Linq; namespace Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests { @@ -1144,6 +1145,74 @@ public void VerifyScrollRepeatButtons() } } + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs enables the tearing out of tabs created for data items into new windows, and the rejoining of those tabs into existing windows.")] + [TestProperty("IsolationLevel", "Method")] // These tests create and destroy windows, so we'll isolate each test to ensure we start with a known good state each time. + public void CanTearOutAndRejoinTabsWithDataItems() + { + using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTearOutWindowWithDataItemsButton" })) + { + TabViewTearOutTestHelpers.CanTearOutAndRejoinTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs does not prevent internally reordering tabs created for items.")] + [TestProperty("IsolationLevel", "Method")] // These tests create and destroy windows, so we'll isolate each test to ensure we start with a known good state each time. + [TestProperty("Ignore", "True")] // Task 50591398: Re-enable tests when we ingest the latest Microsoft.UI.Input.dll + public void CanReorderTabsWithTabTearOutWithDataItems() + { + using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTearOutWindowWithDataItemsButton" })) + { + TabViewTearOutTestHelpers.CanReorderTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs does not prevent selecting tabs created for data items.")] + [TestProperty("IsolationLevel", "Method")] // These tests create and destroy windows, so we'll isolate each test to ensure we start with a known good state each time. + public void CanSelectTabsWithTabTearOutWithDataItems() + { + using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTearOutWindowWithDataItemsButton" })) + { + TabViewTearOutTestHelpers.CanSelectTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs enables the tearing out of tabs not created for data items into new windows, and the rejoining of those tabs into existing windows.")] + [TestProperty("IsolationLevel", "Method")] // These tests create and destroy windows, so we'll isolate each test to ensure we start with a known good state each time. + public void CanTearOutAndRejoinTabsWithoutDataItems() + { + using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTearOutWindowWithoutDataItemsButton" })) + { + TabViewTearOutTestHelpers.CanTearOutAndRejoinTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs does not prevent internally reordering tabs not created for data items.")] + [TestProperty("IsolationLevel", "Method")] // These tests create and destroy windows, so we'll isolate each test to ensure we start with a known good state each time. + [TestProperty("Ignore", "True")] // Task 50591398: Re-enable tests when we ingest the latest Microsoft.UI.Input.dll + public void CanReorderTabsWithTabTearOutWithoutDataItems() + { + using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTearOutWindowWithoutDataItemsButton" })) + { + TabViewTearOutTestHelpers.CanReorderTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + } + + [TestMethod] + [TestProperty("Description", "Verifies that CanTearOutTabs does not prevent selecting tabs backed not created for.")] + [TestProperty("IsolationLevel", "Method")] // These tests create and destroy windows, so we'll isolate each test to ensure we start with a known good state each time. + public void CanSelectTabsWithTabTearOutWithoutDataItems() + { + using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTearOutWindowWithoutDataItemsButton" })) + { + TabViewTearOutTestHelpers.CanSelectTabs(GetTabViewTearOutAppWindows, GetTabViewFromWindow, GetTabsFromTabView); + } + } + private void PressButtonAndVerifyText(String buttonName, String textBlockName, String expectedText) { Button button = FindElement.ByName - - + + - - - + + + - + diff --git a/src/controls/dev/TabView/TestUI/TabViewPage.xaml.cs b/src/controls/dev/TabView/TestUI/TabViewPage.xaml.cs index 2e100d9e51..bd29c11fa5 100644 --- a/src/controls/dev/TabView/TestUI/TabViewPage.xaml.cs +++ b/src/controls/dev/TabView/TestUI/TabViewPage.xaml.cs @@ -421,6 +421,20 @@ private void MultipleTabViewPageButton_Click(object sender, RoutedEventArgs e) this.Frame.Navigate(typeof(MultipleTabViewPage)); } + private void TabViewTearOutWindowWithDataItemsButton_Click(object sender, RoutedEventArgs e) + { + TabViewTearOutWindowWithDataItems newWindow = new(); + newWindow.AppWindow.Resize(new Windows.Graphics.SizeInt32(800, 300)); + newWindow.Activate(); + } + + private void TabViewTearOutWindowWithoutDataItemsButton_Click(object sender, RoutedEventArgs e) + { + TabViewTearOutWindowWithoutDataItems newWindow = new(); + newWindow.AppWindow.Resize(new Windows.Graphics.SizeInt32(800, 300)); + newWindow.Activate(); + } + private void ShortLongTextButton_Click(object sender, RoutedEventArgs e) { FirstTab.Header = "s"; diff --git a/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithDataItems.xaml b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithDataItems.xaml new file mode 100644 index 0000000000..3f84c1cbfe --- /dev/null +++ b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithDataItems.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithDataItems.xaml.cs b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithDataItems.xaml.cs new file mode 100644 index 0000000000..c5540ac1f7 --- /dev/null +++ b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithDataItems.xaml.cs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Navigation; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using Windows.Foundation.Collections; + +namespace MUXControlsTestApp +{ + public sealed partial class TabViewTearOutWindowWithDataItems : Window + { + public ObservableCollection StringList { get; set; } + + public TabViewTearOutWindowWithDataItems() + { + this.InitializeComponent(); + + StringList = [ + "Item 1", + "Item 2", + "Item 3", + ]; + + Title = "MUXControlsTestApp.Desktop - Secondary TabViewTearOutWindow"; + } + + // A user has begun interacting with a tab, such that they might want to tear it out into its own window. + // We'll create a hidden window with the tab's contents that will be shown if the user tears out the tab. + private void OnTabTearOutWindowRequested(TabView _, TabViewTabTearOutWindowRequestedEventArgs args) + { + TabViewTearOutWindowWithDataItems newWindow = new() { StringList = [.. args.Items] }; + newWindow.AppWindow.Hide(); + newWindow.AppWindow.Resize(new Windows.Graphics.SizeInt32(800, 300)); + args.NewWindowId = newWindow.AppWindow.Id; + } + + // A user has torn out a tab, so now is the time we need to remove the torn-out item from our item list. + private void OnTabTearOutRequested(TabView _, TabViewTabTearOutRequestedEventArgs args) + { + for (int i = 0; i < args.Items.Length; i++) + { + int index = StringList.IndexOf(args.Items[i]); + + if (index >= 0) + { + StringList.RemoveAt(index); + } + } + } + + // A tab being dragged from within this process has been dropped on another tab view. This gives the tab view + // the opportunity to check to see whether it actually want to accepts the new tab. In the case of this test app, + // however, we'll just always accept a dropped tab. + private void OnExternalTornOutTabsDropping(TabView _, TabViewExternalTornOutTabsDroppingEventArgs args) + { + args.AllowDrop = true; + } + + // The tab being dragged has now been dropped onto another tab view. We'll add its item to our item list. + // The tab view will take care of disposing of the window. + private void OnExternalTornOutTabsDropped(TabView _, TabViewExternalTornOutTabsDroppedEventArgs args) + { + for (int i = 0; i < args.Items.Length; i++) + { + int index = StringList.IndexOf(args.Items[i]); + + if (index >= 0) + { + StringList.RemoveAt(index); + } + } + + for (int i = 0; i < args.Items.Length; i++) + { + StringList.Insert(Math.Min(args.DropIndex + i, StringList.Count), args.Items[i]); + } + } + } +} diff --git a/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithoutDataItems.xaml b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithoutDataItems.xaml new file mode 100644 index 0000000000..61a4fc35a2 --- /dev/null +++ b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithoutDataItems.xaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithoutDataItems.xaml.cs b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithoutDataItems.xaml.cs new file mode 100644 index 0000000000..b20eb9ceb8 --- /dev/null +++ b/src/controls/dev/TabView/TestUI/TabViewTearOutWindowWithoutDataItems.xaml.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Reflection; +using Windows.Foundation.Collections; + +namespace MUXControlsTestApp +{ + public sealed partial class TabViewTearOutWindowWithoutDataItems : Window + { + TabViewTearOutWindowWithoutDataItems tearOutWindow; + + public TabViewTearOutWindowWithoutDataItems() + { + this.InitializeComponent(); + Title = "MUXControlsTestApp.Desktop - Secondary TabViewTearOutWindow"; + } + + // A user has begun interacting with a tab, such that they might want to tear it out into its own window. + // We'll create a hidden window with the tab's contents that will be shown if the user tears out the tab. + private void OnTabTearOutWindowRequested(TabView _, TabViewTabTearOutWindowRequestedEventArgs args) + { + tearOutWindow = new(); + tearOutWindow.TearOutTabsTabView.TabItems.Clear(); + tearOutWindow.AppWindow.Hide(); + tearOutWindow.AppWindow.Resize(new Windows.Graphics.SizeInt32(800, 300)); + args.NewWindowId = tearOutWindow.AppWindow.Id; + } + + // A user has torn out a tab, so now is the time we need to remove the torn-out item from our item list. + private void OnTabTearOutRequested(TabView tabView, TabViewTabTearOutRequestedEventArgs args) + { + foreach (var tab in args.Tabs.Cast()) + { + tabView.TabItems.Remove(tab); + tearOutWindow.TearOutTabsTabView.TabItems.Add(tab); + } + } + + // A tab being dragged from within this process has been dropped on another tab view. This gives the tab view + // the opportunity to check to see whether it actually want to accepts the new tab. In the case of this test app, + // however, we'll just always accept a dropped tab. + private void OnExternalTornOutTabsDropping(TabView _, TabViewExternalTornOutTabsDroppingEventArgs args) + { + args.AllowDrop = true; + } + + // The tab being dragged has now been dropped onto another tab view. We'll add its item to our item list. + // The tab view will take care of disposing of the window. + private void OnExternalTornOutTabsDropped(TabView tabView, TabViewExternalTornOutTabsDroppedEventArgs args) + { + int insertionIndex = args.DropIndex; + + foreach (var tab in args.Tabs.Cast()) + { + TabView otherTabView = null; + DependencyObject current = tab; + + while (otherTabView == null) + { + if (current is TabView foundTabView) + { + otherTabView = foundTabView; + } + + current = VisualTreeHelper.GetParent(current); + } + + otherTabView?.TabItems.Remove(tab); + tabView.TabItems.Insert(insertionIndex++, tab); + } + } + } +} diff --git a/src/controls/dev/TabView/TestUI/TabView_TestUI.projitems b/src/controls/dev/TabView/TestUI/TabView_TestUI.projitems index 74b4feed3b..212e19e37c 100644 --- a/src/controls/dev/TabView/TestUI/TabView_TestUI.projitems +++ b/src/controls/dev/TabView/TestUI/TabView_TestUI.projitems @@ -34,6 +34,14 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + @@ -54,5 +62,11 @@ TabViewTabClosingBehaviorPage.xaml + + TabViewTearOutWindowWithDataItems.xaml + + + TabViewTearOutWindowWithoutDataItems.xaml + \ No newline at end of file diff --git a/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTestPageElements.cs b/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTestPageElements.cs index d9226886f8..20ab26bc61 100644 --- a/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTestPageElements.cs +++ b/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTestPageElements.cs @@ -206,6 +206,12 @@ public Button GetRemoveTargetButton() } private Button removeTargetButton; + public Button GetSwitchTargetButton() + { + return GetElement(ref SwitchTargetButton, "SwitchTargetButton"); + } + private Button SwitchTargetButton; + public ComboBox GetIsLightDismissEnabledComboBox() { return GetElement(ref isLightDismissEnabledComboBox, "IsLightDismissEnabledComboBox"); diff --git a/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTests.cs b/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTests.cs index f7fc9ece60..11a9669455 100644 --- a/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTests.cs +++ b/src/controls/dev/TeachingTip/InteractionTests/TeachingTipTests.cs @@ -1194,6 +1194,26 @@ void EnableLightDismiss() } } + [TestMethod] + [TestProperty("TestSuite", "C")] + public void VerifyTeachingTipTargetChange() + { + using (var setup = new TestSetupHelper(new[] { "TeachingTip Tests", "TeachingTip Test" })) + { + elements = new TeachingTipTestPageElements(); + + OpenTeachingTip(); + + double oldYOffset = GetTipVerticalOffset(); + + elements.GetSwitchTargetButton().InvokeAndWait(); + + double newYOffset = GetTipVerticalOffset(); + + Verify.IsFalse(oldYOffset == newYOffset); + } + } + private void CloseOpenAndCloseWithJustKeyboardViaF6() { KeyboardHelper.PressKey(Key.F6); diff --git a/src/controls/dev/TeachingTip/TeachingTip.cpp b/src/controls/dev/TeachingTip/TeachingTip.cpp index 74b4ba92a0..c7aa0298b3 100644 --- a/src/controls/dev/TeachingTip/TeachingTip.cpp +++ b/src/controls/dev/TeachingTip/TeachingTip.cpp @@ -484,67 +484,67 @@ bool TeachingTip::PositionTargetedPopup() { case winrt::TeachingTipPlacementMode::Top: popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y - tipHeight - offset.Top); - popup.HorizontalOffset((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Width - tipWidth) / 2.0f)); + popup.HorizontalOffset((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Width - tipWidth) / 2.0)); break; case winrt::TeachingTipPlacementMode::Bottom: - popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y + m_currentTargetBoundsInCoreWindowSpace.Height + static_cast(offset.Bottom)); - popup.HorizontalOffset((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Width - tipWidth) / 2.0f)); + popup.VerticalOffset(static_cast(m_currentTargetBoundsInCoreWindowSpace.Y) + m_currentTargetBoundsInCoreWindowSpace.Height + offset.Bottom); + popup.HorizontalOffset((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Width - tipWidth) / 2.0)); break; case winrt::TeachingTipPlacementMode::Left: - popup.VerticalOffset(((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Height - tipHeight) / 2.0f); + popup.VerticalOffset(((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Height - tipHeight) / 2.0); popup.HorizontalOffset(m_currentTargetBoundsInCoreWindowSpace.X - tipWidth - offset.Left); break; case winrt::TeachingTipPlacementMode::Right: - popup.VerticalOffset(((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Height - tipHeight) / 2.0f); - popup.HorizontalOffset(m_currentTargetBoundsInCoreWindowSpace.X + m_currentTargetBoundsInCoreWindowSpace.Width + static_cast(offset.Right)); + popup.VerticalOffset(((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Height - tipHeight) / 2.0); + popup.HorizontalOffset(static_cast(m_currentTargetBoundsInCoreWindowSpace.X) + m_currentTargetBoundsInCoreWindowSpace.Width + offset.Right); break; case winrt::TeachingTipPlacementMode::TopRight: popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y - tipHeight - offset.Top); - popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0f) - MinimumTipEdgeToTailCenter())); + popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0) - MinimumTipEdgeToTailCenter())); break; case winrt::TeachingTipPlacementMode::TopLeft: popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y - tipHeight - offset.Top); - popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0f) - tipWidth + MinimumTipEdgeToTailCenter())); + popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0) - tipWidth + MinimumTipEdgeToTailCenter())); break; case winrt::TeachingTipPlacementMode::BottomRight: - popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y + m_currentTargetBoundsInCoreWindowSpace.Height + static_cast(offset.Bottom)); - popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0f) - MinimumTipEdgeToTailCenter())); + popup.VerticalOffset(static_cast(m_currentTargetBoundsInCoreWindowSpace.Y) + m_currentTargetBoundsInCoreWindowSpace.Height + offset.Bottom); + popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0) - MinimumTipEdgeToTailCenter())); break; case winrt::TeachingTipPlacementMode::BottomLeft: - popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y + m_currentTargetBoundsInCoreWindowSpace.Height + static_cast(offset.Bottom)); - popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0f) - tipWidth + MinimumTipEdgeToTailCenter())); + popup.VerticalOffset(static_cast(m_currentTargetBoundsInCoreWindowSpace.Y) + m_currentTargetBoundsInCoreWindowSpace.Height + offset.Bottom); + popup.HorizontalOffset(((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Width) / 2.0) - tipWidth + MinimumTipEdgeToTailCenter())); break; case winrt::TeachingTipPlacementMode::LeftTop: - popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0f) - tipHeight + MinimumTipEdgeToTailCenter()); + popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0) - tipHeight + MinimumTipEdgeToTailCenter()); popup.HorizontalOffset(m_currentTargetBoundsInCoreWindowSpace.X - tipWidth - offset.Left); break; case winrt::TeachingTipPlacementMode::LeftBottom: - popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0f) - MinimumTipEdgeToTailCenter()); + popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0) - MinimumTipEdgeToTailCenter()); popup.HorizontalOffset(m_currentTargetBoundsInCoreWindowSpace.X - tipWidth - offset.Left); break; case winrt::TeachingTipPlacementMode::RightTop: - popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0f) - tipHeight + MinimumTipEdgeToTailCenter()); - popup.HorizontalOffset(m_currentTargetBoundsInCoreWindowSpace.X + m_currentTargetBoundsInCoreWindowSpace.Width + static_cast(offset.Right)); + popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0) - tipHeight + MinimumTipEdgeToTailCenter()); + popup.HorizontalOffset(static_cast(m_currentTargetBoundsInCoreWindowSpace.X) + m_currentTargetBoundsInCoreWindowSpace.Width + offset.Right); break; case winrt::TeachingTipPlacementMode::RightBottom: - popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0f) - MinimumTipEdgeToTailCenter()); - popup.HorizontalOffset(m_currentTargetBoundsInCoreWindowSpace.X + m_currentTargetBoundsInCoreWindowSpace.Width + static_cast(offset.Right)); + popup.VerticalOffset((((m_currentTargetBoundsInCoreWindowSpace.Y * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Height) / 2.0) - MinimumTipEdgeToTailCenter()); + popup.HorizontalOffset(static_cast(m_currentTargetBoundsInCoreWindowSpace.X) + m_currentTargetBoundsInCoreWindowSpace.Width + offset.Right); break; case winrt::TeachingTipPlacementMode::Center: - popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y + (m_currentTargetBoundsInCoreWindowSpace.Height / 2.0f) - tipHeight - offset.Top); - popup.HorizontalOffset((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0f) + m_currentTargetBoundsInCoreWindowSpace.Width - tipWidth) / 2.0f)); + popup.VerticalOffset(m_currentTargetBoundsInCoreWindowSpace.Y + (m_currentTargetBoundsInCoreWindowSpace.Height / 2.0) - tipHeight - offset.Top); + popup.HorizontalOffset((((m_currentTargetBoundsInCoreWindowSpace.X * 2.0) + m_currentTargetBoundsInCoreWindowSpace.Width - tipWidth) / 2.0)); break; default: @@ -1487,14 +1487,20 @@ void TeachingTip::OnTargetChanged() auto const target = Target(); m_target.set(target); + bool isTargetLoaded = false; + if (target) { + // We need to check if the target is loaded before registering for its + // loaded event. This is because the act of registering for the loaded event + // will cause the target to report that it is not loaded. + isTargetLoaded = target.IsLoaded(); m_targetLoadedRevoker = target.Loaded(winrt::auto_revoke, { this, &TeachingTip::OnTargetLoaded }); } if (IsOpen()) { - if (target && target.IsLoaded()) + if (target && isTargetLoaded) { m_currentTargetBoundsInCoreWindowSpace = target.TransformToVisual(nullptr).TransformBounds({ 0.0, @@ -1506,7 +1512,7 @@ void TeachingTip::OnTargetChanged() } // if we have a target that is not yet loaded, skip positioning the flayout for now, that will happen once the target loads. - if (!target || (target && target.IsLoaded())) + if (!target || (target && isTargetLoaded)) { PositionPopup(); } @@ -2068,13 +2074,13 @@ std::tuple TeachingTip::DetermineSpaceAround const winrt::Thickness windowSpaceAroundTarget{ // Target.Left - Window.Left - m_currentTargetBoundsInCoreWindowSpace.X - /* 0 except with test window bounds */ windowBoundsInCoreWindowSpace.X, + static_cast(m_currentTargetBoundsInCoreWindowSpace.X) - /* 0 except with test window bounds */ windowBoundsInCoreWindowSpace.X, // Target.Top - Window.Top - m_currentTargetBoundsInCoreWindowSpace.Y - /* 0 except with test window bounds */ windowBoundsInCoreWindowSpace.Y, + static_cast(m_currentTargetBoundsInCoreWindowSpace.Y) - /* 0 except with test window bounds */ windowBoundsInCoreWindowSpace.Y, // Window.Right - Target.Right - (windowBoundsInCoreWindowSpace.X + windowBoundsInCoreWindowSpace.Width) - (m_currentTargetBoundsInCoreWindowSpace.X + m_currentTargetBoundsInCoreWindowSpace.Width), + (static_cast(windowBoundsInCoreWindowSpace.X) + windowBoundsInCoreWindowSpace.Width) - (static_cast(m_currentTargetBoundsInCoreWindowSpace.X) + m_currentTargetBoundsInCoreWindowSpace.Width), // Screen.Right - Target.Right - (windowBoundsInCoreWindowSpace.Y + windowBoundsInCoreWindowSpace.Height) - (m_currentTargetBoundsInCoreWindowSpace.Y + m_currentTargetBoundsInCoreWindowSpace.Height) }; + (static_cast(windowBoundsInCoreWindowSpace.Y) + windowBoundsInCoreWindowSpace.Height) - (static_cast(m_currentTargetBoundsInCoreWindowSpace.Y) + m_currentTargetBoundsInCoreWindowSpace.Height) }; const winrt::Thickness screenSpaceAroundTarget = [this, screenBoundsInCoreWindowSpace, windowSpaceAroundTarget]() @@ -2083,13 +2089,13 @@ std::tuple TeachingTip::DetermineSpaceAround { return winrt::Thickness{ // Target.Left - Screen.Left - m_currentTargetBoundsInCoreWindowSpace.X - screenBoundsInCoreWindowSpace.X, + static_cast(m_currentTargetBoundsInCoreWindowSpace.X) - screenBoundsInCoreWindowSpace.X, // Target.Top - Screen.Top - m_currentTargetBoundsInCoreWindowSpace.Y - screenBoundsInCoreWindowSpace.Y, + static_cast(m_currentTargetBoundsInCoreWindowSpace.Y) - screenBoundsInCoreWindowSpace.Y, // Screen.Right - Target.Right - (screenBoundsInCoreWindowSpace.X + screenBoundsInCoreWindowSpace.Width) - (m_currentTargetBoundsInCoreWindowSpace.X + m_currentTargetBoundsInCoreWindowSpace.Width), + (static_cast(screenBoundsInCoreWindowSpace.X) + screenBoundsInCoreWindowSpace.Width) - (static_cast(m_currentTargetBoundsInCoreWindowSpace.X) + m_currentTargetBoundsInCoreWindowSpace.Width), // Screen.Bottom - Target.Bottom - (screenBoundsInCoreWindowSpace.Y + screenBoundsInCoreWindowSpace.Height) - (m_currentTargetBoundsInCoreWindowSpace.Y + m_currentTargetBoundsInCoreWindowSpace.Height) }; + (static_cast(screenBoundsInCoreWindowSpace.Y) + screenBoundsInCoreWindowSpace.Height) - (static_cast(m_currentTargetBoundsInCoreWindowSpace.Y) + m_currentTargetBoundsInCoreWindowSpace.Height) }; } return windowSpaceAroundTarget; }(); @@ -2255,51 +2261,51 @@ void TeachingTip::OnPropertyChanged( winrt::get_self(sender.as())->OnPropertyChanged(args); } -float TeachingTip::TailLongSideActualLength() +double TeachingTip::TailLongSideActualLength() { if (auto&& tailPolygon = m_tailPolygon.get()) { - return static_cast(std::max(tailPolygon.ActualHeight(), tailPolygon.ActualWidth())); + return std::max(tailPolygon.ActualHeight(), tailPolygon.ActualWidth()); } return 0; } -float TeachingTip::TailLongSideLength() +double TeachingTip::TailLongSideLength() { - return static_cast(TailLongSideActualLength() - (2 * s_tailOcclusionAmount)); + return TailLongSideActualLength() - (2 * static_cast(s_tailOcclusionAmount)); } -float TeachingTip::TailShortSideLength() +double TeachingTip::TailShortSideLength() { if (auto&& tailPolygon = m_tailPolygon.get()) { - return static_cast(std::min(tailPolygon.ActualHeight(), tailPolygon.ActualWidth()) - s_tailOcclusionAmount); + return std::min(tailPolygon.ActualHeight(), tailPolygon.ActualWidth()) - s_tailOcclusionAmount; } return 0; } -float TeachingTip::MinimumTipEdgeToTailEdgeMargin() +double TeachingTip::MinimumTipEdgeToTailEdgeMargin() { if (auto&& tailOcclusionGrid = m_tailOcclusionGrid.get()) { return tailOcclusionGrid.ColumnDefinitions().Size() > 1 ? - static_cast(tailOcclusionGrid.ColumnDefinitions().GetAt(1).ActualWidth() + s_tailOcclusionAmount) - : 0.0f; + tailOcclusionGrid.ColumnDefinitions().GetAt(1).ActualWidth() + s_tailOcclusionAmount + : 0.0; } return 0; } -float TeachingTip::MinimumTipEdgeToTailCenter() +double TeachingTip::MinimumTipEdgeToTailCenter() { if (auto&& tailOcclusionGrid = m_tailOcclusionGrid.get()) { if (auto&& tailPolygon = m_tailPolygon.get()) { return tailOcclusionGrid.ColumnDefinitions().Size() > 1 ? - static_cast(tailOcclusionGrid.ColumnDefinitions().GetAt(0).ActualWidth() + - tailOcclusionGrid.ColumnDefinitions().GetAt(1).ActualWidth() + - (std::max(tailPolygon.ActualHeight(), tailPolygon.ActualWidth()) / 2)) - : 0.0f; + tailOcclusionGrid.ColumnDefinitions().GetAt(0).ActualWidth() + + tailOcclusionGrid.ColumnDefinitions().GetAt(1).ActualWidth() + + (std::max(tailPolygon.ActualHeight(), tailPolygon.ActualWidth()) / 2) + : 0.0; } } return 0; diff --git a/src/controls/dev/TeachingTip/TeachingTip.h b/src/controls/dev/TeachingTip/TeachingTip.h index 6403589498..b499a6436b 100644 --- a/src/controls/dev/TeachingTip/TeachingTip.h +++ b/src/controls/dev/TeachingTip/TeachingTip.h @@ -161,15 +161,15 @@ class TeachingTip : // The tail is designed as an 8x16 pixel shape, however it is actually a 10x20 shape which is partially occluded by the tip content. // This is done to get the border of the tip to follow the tail shape without drawing the border on the tip edge of the tail. - float TailLongSideActualLength(); - float TailLongSideLength(); - float TailShortSideLength(); - float MinimumTipEdgeToTailEdgeMargin(); - float MinimumTipEdgeToTailCenter(); + double TailLongSideActualLength(); + double TailLongSideLength(); + double TailShortSideLength(); + double MinimumTipEdgeToTailEdgeMargin(); + double MinimumTipEdgeToTailCenter(); winrt::CornerRadius GetTeachingTipCornerRadius(); - float TopLeftCornerRadius() { return static_cast(GetTeachingTipCornerRadius().TopLeft); } - float TopRightCornerRadius() { return static_cast(GetTeachingTipCornerRadius().TopRight); } + double TopLeftCornerRadius() { return GetTeachingTipCornerRadius().TopLeft; } + double TopRightCornerRadius() { return GetTeachingTipCornerRadius().TopRight; } tracker_ref m_container{ this }; @@ -258,22 +258,22 @@ class TeachingTip : } // These values are shifted by one because this is the 1px highlight that sits adjacent to the tip border. - inline winrt::Thickness BottomPlacementTopRightHighlightMargin(double width, double height) { return { (width / 2) + (TailShortSideLength() - 1.0f), 0, (TopRightCornerRadius() - 1.0f), 0 }; } - inline winrt::Thickness BottomRightPlacementTopRightHighlightMargin(double width, double height) { return { MinimumTipEdgeToTailEdgeMargin() + TailLongSideLength() - 1.0f, 0, (TopRightCornerRadius() - 1.0f), 0 }; } - inline winrt::Thickness BottomLeftPlacementTopRightHighlightMargin(double width, double height) { return { width - (MinimumTipEdgeToTailEdgeMargin() + 1.0f), 0, (TopRightCornerRadius() - 1.0f), 0 }; } + inline winrt::Thickness BottomPlacementTopRightHighlightMargin(double width, double height) { return { (width / 2) + (TailShortSideLength() - 1.0), 0, (TopRightCornerRadius() - 1.0), 0 }; } + inline winrt::Thickness BottomRightPlacementTopRightHighlightMargin(double width, double height) { return { MinimumTipEdgeToTailEdgeMargin() + TailLongSideLength() - 1.0, 0, (TopRightCornerRadius() - 1.0), 0 }; } + inline winrt::Thickness BottomLeftPlacementTopRightHighlightMargin(double width, double height) { return { width - (MinimumTipEdgeToTailEdgeMargin() + 1.0), 0, (TopRightCornerRadius() - 1.0), 0 }; } static inline winrt::Thickness constexpr OtherPlacementTopRightHighlightMargin(double width, double height) { return { 0, 0, 0, 0 }; } - inline winrt::Thickness BottomPlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0f), 0, (width / 2) + (TailShortSideLength() - 1.0f), 0 }; } - inline winrt::Thickness BottomRightPlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0f), 0, width - (MinimumTipEdgeToTailEdgeMargin() + 1.0f), 0 }; } - inline winrt::Thickness BottomLeftPlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0f), 0, MinimumTipEdgeToTailEdgeMargin() + TailLongSideLength() - 1.0f, 0 }; } - inline winrt::Thickness TopEdgePlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0f), 1, (TopRightCornerRadius() - 1.0f), 0 }; } + inline winrt::Thickness BottomPlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0), 0, (width / 2) + (TailShortSideLength() - 1.0), 0 }; } + inline winrt::Thickness BottomRightPlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0), 0, width - (MinimumTipEdgeToTailEdgeMargin() + 1.0), 0 }; } + inline winrt::Thickness BottomLeftPlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0), 0, MinimumTipEdgeToTailEdgeMargin() + TailLongSideLength() - 1.0, 0 }; } + inline winrt::Thickness TopEdgePlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0), 1, (TopRightCornerRadius() - 1.0), 0 }; } // Shifted by one since the tail edge's border is not accounted for automatically. - inline winrt::Thickness LeftEdgePlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0f), 1, (TopRightCornerRadius() - 2.0f), 0 }; } - inline winrt::Thickness RightEdgePlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 2.0f), 1, (TopRightCornerRadius() - 1.0f), 0 }; } + inline winrt::Thickness LeftEdgePlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 1.0), 1, (TopRightCornerRadius() - 2.0), 0 }; } + inline winrt::Thickness RightEdgePlacementTopLeftHighlightMargin(double width, double height) { return { (TopLeftCornerRadius() - 2.0), 1, (TopRightCornerRadius() - 1.0), 0 }; } static inline double constexpr UntargetedTipFarPlacementOffset(float farWindowCoordinateInCoreWindowSpace, double tipSize, double offset) { return farWindowCoordinateInCoreWindowSpace - (tipSize + s_untargetedTipWindowEdgeMargin + offset); } - static inline double constexpr UntargetedTipCenterPlacementOffset(float nearWindowCoordinateInCoreWindowSpace, float farWindowCoordinateInCoreWindowSpace, double tipSize, double nearOffset, double farOffset) { return ((nearWindowCoordinateInCoreWindowSpace + farWindowCoordinateInCoreWindowSpace) / 2) - (tipSize / 2) + nearOffset - farOffset; } - static inline double constexpr UntargetedTipNearPlacementOffset(float nearWindowCoordinateInCoreWindowSpace, double offset) { return s_untargetedTipWindowEdgeMargin + nearWindowCoordinateInCoreWindowSpace + offset; } + static inline double constexpr UntargetedTipCenterPlacementOffset(float nearWindowCoordinateInCoreWindowSpace, float farWindowCoordinateInCoreWindowSpace, double tipSize, double nearOffset, double farOffset) { return ((static_cast(nearWindowCoordinateInCoreWindowSpace) + static_cast(farWindowCoordinateInCoreWindowSpace)) / 2) - (tipSize / 2) + nearOffset - farOffset; } + static inline double constexpr UntargetedTipNearPlacementOffset(float nearWindowCoordinateInCoreWindowSpace, double offset) { return static_cast(s_untargetedTipWindowEdgeMargin) + nearWindowCoordinateInCoreWindowSpace + offset; } static constexpr wstring_view s_scaleTargetName{ L"Scale"sv }; static constexpr wstring_view s_translationTargetName{ L"Translation"sv }; diff --git a/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml b/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml index 05294055bf..96f26df4dd 100644 --- a/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml +++ b/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml @@ -70,6 +70,7 @@ + @@ -136,6 +137,8 @@ + + @@ -305,6 +308,9 @@ Text="{x:Bind BrushToString(CurrentCancelClosesCheckBox.Foreground),Mode=OneWay}" FontSize="8"/> + + + diff --git a/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml.cs b/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml.cs index 9e39fdfbb4..374d2fc625 100644 --- a/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml.cs +++ b/src/controls/dev/TeachingTip/TestUI/TeachingTipPage.xaml.cs @@ -946,6 +946,12 @@ private void OnPageThemeComboBoxSelectionChanged(object sender, SelectionChanged } } + public void OnSwitchTargetButtonClicked(object sender, RoutedEventArgs args) + { + var newTarget = getTeachingTip().Target == targetButton ? targetButton2 : targetButton; + getTeachingTip().Target = newTarget; + } + public Button ActionButton { get diff --git a/src/controls/dev/Telemetry/MuxcTraceLogging.h b/src/controls/dev/Telemetry/MuxcTraceLogging.h index e3d8abbdb8..76baa9e87c 100644 --- a/src/controls/dev/Telemetry/MuxcTraceLogging.h +++ b/src/controls/dev/Telemetry/MuxcTraceLogging.h @@ -65,6 +65,8 @@ #define TRACE_MSG_METH_STR_DBL_DBL L"%s[0x%p](%s, %lf, %lf)\n" #define TRACE_MSG_METH_STR_FLT L"%s[0x%p](%s, %f)\n" #define TRACE_MSG_METH_STR_INT L"%s[0x%p](%s, %d)\n" +#define TRACE_MSG_METH_STR_STR_PTR L"%s[0x%p](%s, %s, 0x%p)\n" +#define TRACE_MSG_METH_STR_STR_DBL L"%s[0x%p](%s, %s, %lf)\n" #define TRACE_MSG_METH_STR_STR_INT L"%s[0x%p](%s, %s, %d)\n" #define TRACE_MSG_METH_STR_STR_STR L"%s[0x%p](%s, %s, %s)\n" #define TRACE_MSG_METH_STR_INT_INT L"%s[0x%p](%s, %d, %d)\n" @@ -73,6 +75,7 @@ #define TRACE_MSG_METH_STR_STR_FLT_FLT_FLT_FLT L"%s[0x%p](%s, %s, %f, %f, %f, %f)\n" #define TRACE_MSG_METH_STR_STR_FLT L"%s[0x%p](%s, %s, %f)\n" #define TRACE_MSG_METH_STR_STR_INT_INT L"%s[0x%p](%s, %s, %d, %d)\n" +#define TRACE_MSG_METH_STR_STR_DBL_DBL L"%s[0x%p](%s, %s, %lf, %lf)\n" #define TRACE_MSG_METH_METH L"%s[0x%p] - calls %s()\n" #define TRACE_MSG_METH_METH_INT L"%s[0x%p] - calls %s(%d)\n" diff --git a/src/controls/dev/Telemetry/RuntimeProfiler.cpp b/src/controls/dev/Telemetry/RuntimeProfiler.cpp index d6ce8376ee..9b14bf8c55 100644 --- a/src/controls/dev/Telemetry/RuntimeProfiler.cpp +++ b/src/controls/dev/Telemetry/RuntimeProfiler.cpp @@ -208,7 +208,6 @@ namespace RuntimeProfiler { bool g_runtimeProfilerInitialized{ false }; PTP_TIMER g_pTimer{ nullptr }; - winrt::Application::Suspending_revoker g_applicationSuspendingRevoker{}; void UninitializeRuntimeProfiler() { @@ -225,11 +224,6 @@ namespace RuntimeProfiler { g_pTimer = nullptr; } - if (g_applicationSuspendingRevoker) - { - g_applicationSuspendingRevoker.revoke(); - } - g_runtimeProfilerInitialized = false; } @@ -254,23 +248,7 @@ namespace RuntimeProfiler { SetThreadpoolTimer(g_pTimer, &ftdueTime, (DWORD)(std::chrono::milliseconds(EventFrequency).count()), 60 * 1000); } - // Since MUX doesn't piggyback the WUX Extension suspend handler, - // we sign up for suspension notifications. - try - { - g_applicationSuspendingRevoker = winrt::Application::Current().Suspending(winrt::auto_revoke, [](auto&, auto&) - { - FireEvent(true); - } - ); - } - catch (winrt::hresult_error e) - { - // We might not have an Application instance object in XamlPresenter scenarios - // because we don't need it. - } - - g_runtimeProfilerInitialized = g_pTimer != nullptr && g_applicationSuspendingRevoker; + g_runtimeProfilerInitialized = g_pTimer != nullptr; } void RegisterMethod(ProfileGroup group, UINT16 uTypeIndex, UINT16 uMethodIndex, volatile LONG *pCount) noexcept diff --git a/src/controls/dev/Telemetry/RuntimeProfiler.h b/src/controls/dev/Telemetry/RuntimeProfiler.h index f01551ba79..27f8f0da9f 100644 --- a/src/controls/dev/Telemetry/RuntimeProfiler.h +++ b/src/controls/dev/Telemetry/RuntimeProfiler.h @@ -66,6 +66,7 @@ namespace RuntimeProfiler ProfId_AnnotatedScrollBar, ProfId_MapControl, ProfId_SelectorBar, + ProfId_TitleBar, ProfId_Size // ProfId_Size is the last always. } ProfilerClassId; diff --git a/src/controls/dev/TitleBar/TestUI/TitleBarPage.xaml b/src/controls/dev/TitleBar/TestUI/TitleBarPage.xaml index cede7e4813..8052da162c 100644 --- a/src/controls/dev/TitleBar/TestUI/TitleBarPage.xaml +++ b/src/controls/dev/TitleBar/TestUI/TitleBarPage.xaml @@ -12,12 +12,12 @@ - - - - - - + + + + + +