Compare commits

...

15 Commits

Author SHA1 Message Date
Kai Tao (from Dev Box)
b2d5b58267 wire up installer 2026-03-20 11:23:16 +08:00
vanzue
0e181a41f7 Fix Settings UI ARM64 AOT binding warnings 2026-03-17 14:45:50 +08:00
vanzue
9765107cd9 fix ut 2026-03-17 13:04:22 +08:00
vanzue
2509a8b8db xaml format 2026-03-16 22:49:17 +08:00
vanzue
82b5e1ad62 fix spell 2026-03-16 19:48:30 +08:00
vanzue
8b37edddd2 fix spell 2026-03-16 16:14:33 +08:00
vanzue
4f96329cb3 try setup installer for aot 2026-03-13 15:41:40 +08:00
vanzue
6dc6f25ee8 settings aot 2026-03-13 11:29:35 +08:00
vanzue
a3d8215c7b merge main 2026-03-12 20:18:16 +08:00
Shawn Yuan (from Dev Box)
ed29ab1717 fixed crash issue 2026-02-26 10:26:15 +08:00
Shawn Yuan (from Dev Box)
47dbb44a2c fixed icon missing issue 2026-02-11 17:14:00 +08:00
Shawn Yuan (from Dev Box)
ba1b97951c fix crash issue 2026-02-11 15:16:19 +08:00
Shawn Yuan (from Dev Box)
ad4a5cdfe7 fix compiling issue 2026-02-11 14:54:03 +08:00
Shawn Yuan (from Dev Box)
58f9b007a6 published settings aot 2026-02-11 11:37:22 +08:00
Shawn Yuan (from Dev Box)
1c538a781f init, need to resolve publish errors.
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2026-02-10 14:34:29 +08:00
136 changed files with 1745 additions and 464 deletions

View File

@@ -96,6 +96,7 @@
^\.github/workflows/spelling\d*\.yml$
^\.gitmodules$
^\Q.pipelines/ESRPSigning_core.json\E$
^\Qdoc/devdocs/development/settings-ui-aot.md\E$
^\Qdoc/devdocs/localization.md\E$
^\Qsrc/modules/MouseUtils/MouseJump.Common/NativeMethods/User32/UI/WindowsAndMessaging/User32.SYSTEM_METRICS_INDEX.cs\E$
^doc/devdocs/akaLinks\.md$
@@ -145,3 +146,4 @@ ignore$
src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage.cs
^src/modules/powerrename/unittests/testdata/avif_test\.avif$
^src/modules/powerrename/unittests/testdata/heif_test\.heic$
^\Qtools/build/build-installer.ps1\E$

View File

@@ -618,6 +618,7 @@ IGo
iid
Iindex
Ijwhost
Ilc
IMAGEHLP
IMAGERESIZERCONTEXTMENU
IMAGERESIZEREXT
@@ -2019,6 +2020,7 @@ Lbuttondown
LCh
lcid
lcl
llc
LEFTALIGN
leftclick
Lenovo

7
.gitignore vendored
View File

@@ -173,6 +173,7 @@ publish/
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
!src/settings-ui/Settings.UI/Properties/PublishProfiles/win-x64.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
@@ -351,6 +352,12 @@ src/common/Telemetry/*.etl
# Generated installer file for Monaco source files.
/installer/PowerToysSetupVNext/MonacoSRC.wxs
# CmdPal local build/versioning generated files
/src/modules/cmdpal/Directory.Build.props
/src/modules/cmdpal/Directory.Build.targets
/src/modules/cmdpal/**/BuildInfo.xml
/src/modules/cmdpal/**/GeneratedPackage*.appxmanifest
# MSBuildCache
/MSBuildCacheLogs/

View File

@@ -0,0 +1,138 @@
# Settings UI Native AOT
This document describes the current Native AOT status of the PowerToys Settings UI, the local publish workflow, and the formal packaging flow used to feed the installer without changing the installed layout.
## Current Status
As of March 13, 2026, the branch is at the following stage:
- Regular Settings builds succeed in Visual Studio.
- Native AOT publish for `src/settings-ui/Settings.UI/PowerToys.Settings.csproj` succeeds.
- The published `PowerToys.Settings.exe` can be launched as a standalone app with dummy pipe arguments and does not exit immediately.
- The installer pipeline can now stage Settings AOT publish output and normalize it back into `x64\Release\WinUI3Apps` before WiX harvest.
- The branch still has unresolved AOT follow-up work such as trimming/AOT warning cleanup and broader functional validation with the Runner.
## Build Requirements
- Visual Studio 2026 or Visual Studio 2022 with Native AOT support installed
- Windows App SDK prerequisites already available in the repo development environment
- A Visual Studio developer command prompt configured for the target architecture
Important:
- If you are publishing `win-x64`, use an x64 developer command prompt.
- On ARM64 developer machines, make sure the environment is configured for `-arch=x64`.
- If the environment is set up as x86 by mistake, Native AOT publish can fail at link time with hundreds of unresolved externals such as `wmainCRTStartup`, `CloseHandle`, or `CoInitializeEx`.
## Build Commands
### Standard Visual Studio build
The project builds successfully in Visual Studio without extra steps.
### Native AOT publish
Run this from a Visual Studio developer command prompt at the repository root:
```pwsh
msbuild src\settings-ui\Settings.UI\PowerToys.Settings.csproj /t:Publish /p:Configuration=Release /p:Platform=x64 /p:RuntimeIdentifier=win-x64 /m
```
If you are on an ARM64 machine and need the equivalent environment setup from a regular terminal, use:
```cmd
call "C:\Program Files\Microsoft Visual Studio\18\Enterprise\Common7\Tools\VsDevCmd.bat" -no_logo -arch=x64 -host_arch=arm64
```
Then run the same `msbuild` command.
## Publish Output
The published output is generated under:
```text
x64\Release\WinUI3Apps\win-x64\publish
```
The Native AOT executable is:
```text
x64\Release\WinUI3Apps\win-x64\publish\PowerToys.Settings.exe
```
## Run The Standalone AOT App
From the publish directory, run:
```pwsh
.\PowerToys.Settings.exe dummy_pipe_1 dummy_pipe_2 0 system false false false false false
```
These dummy arguments are sufficient to smoke test standalone startup of the published app.
## Formal Packaging Flow
For installer packaging, do not point WiX at `win-x64\publish` directly.
Instead, use the installer build pipeline with the Settings AOT switch:
```pwsh
.\tools\build\build-installer.ps1 -Platform x64 -Configuration Release -EnableSettingsAOT
```
That flow now does the following:
1. Builds the main solution, but skips the regular `PowerToys.Settings.csproj` build so that the non-AOT Settings app is not emitted into `WinUI3Apps`.
2. Publishes `PowerToys.Settings.csproj` with Native AOT into the staging directory:
```text
x64\Release\AotPublish\Settings
```
3. Cleans stale non-AOT Settings artifacts from `WinUI3Apps`.
4. Copies the AOT publish output back into the existing installer-facing layout:
```text
x64\Release\WinUI3Apps
```
This keeps the runner launch path and installer harvest path unchanged:
- installed executable: `[INSTALLFOLDER]\WinUI3Apps\PowerToys.Settings.exe`
- installed settings assets: `[INSTALLFOLDER]\WinUI3Apps\Assets\Settings\...`
- installed WinAppSDK/runtime files: still under `[INSTALLFOLDER]\WinUI3Apps\...`
The WiX responsibilities remain unchanged:
- `WinUI3Applications.wxs` packages the flattened `WinUI3Apps` executable/runtime tree.
- `Settings.wxs` packages `Assets\Settings` and the Settings helper scripts.
## How Settings Was Made AOT-Compatible
The current branch uses a combination of project-level and code-level changes:
1. AOT is enabled in [`src/settings-ui/Settings.UI/PowerToys.Settings.csproj`](/C:/PowerToys/src/settings-ui/Settings.UI/PowerToys.Settings.csproj) through the `EnableSettingsAOT` and `PublishAot` properties.
2. JSON serialization paths were moved to source-generated contexts in [`src/settings-ui/Settings.UI.Library/SettingsSerializationContext.cs`](/C:/PowerToys/src/settings-ui/Settings.UI.Library/SettingsSerializationContext.cs) and related callers.
3. Reflection-heavy code paths were replaced with compile-time type selection in places such as [`src/settings-ui/Settings.UI/Services/SearchIndexService.cs`](/C:/PowerToys/src/settings-ui/Settings.UI/Services/SearchIndexService.cs) and [`src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs`](/C:/PowerToys/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs).
4. Command bindings were updated to use AOT-safe command types in [`src/settings-ui/Settings.UI.Library/ICommand.cs`](/C:/PowerToys/src/settings-ui/Settings.UI.Library/ICommand.cs) and related relay command implementations.
5. Some XAML interaction patterns were replaced with direct event handlers where the original behavior was not AOT-friendly.
6. A local deep-link helper is used for the standalone AOT path in [`src/settings-ui/Settings.UI/Helpers/SettingsDeepLink.cs`](/C:/PowerToys/src/settings-ui/Settings.UI/Helpers/SettingsDeepLink.cs), avoiding dependency on the WPF-based implementation for that flow.
## Known Notes
- Native AOT publish currently emits `WMC1510` XAML compiler warnings for bindings that may still need stronger trimming annotations or `x:Bind` migration.
- Some intermediate `CsWinRTInvokeGuidPatcher` steps may report exit code `-1` in project logs, but they did not block the successful publish observed on this branch.
- The successful publish depends on using the correct developer prompt architecture.
- The installer pipeline currently enables Settings AOT packaging only for `x64 / win-x64`.
## Validation Performed On This Branch
The following checks were completed on March 12, 2026:
- `msbuild src\settings-ui\Settings.UI\PowerToys.Settings.csproj /t:Publish /p:Configuration=Release /p:Platform=x64 /p:RuntimeIdentifier=win-x64 /m`
- Standalone launch of the published AOT executable with dummy pipe arguments
Observed result:
- Publish succeeded with exit code `0`
- The standalone app started successfully and remained alive for at least 10 seconds during smoke validation

View File

@@ -76,7 +76,7 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs.bk""""
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform) -binRoot "$(InstallerBinDir)"
</Command>
<Message>Backing up original files and populating .NET and WPF Runtime dependencies for WiX3 based installer</Message>
</PreBuildEvent>

View File

@@ -24,14 +24,22 @@
<?define PowerToysPlatform="x64"?>
<?define PlatformProgramFiles="[ProgramFiles64Folder]"?>
<?define PlatformLK="x64" ?>
<?define BinDir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
<?if $(var.InstallerBinDir) != ""?>
<?define BinDir="$(var.InstallerBinDir)\" ?>
<?else?>
<?define BinDir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
<?endif?>
<?else?>
<!-- stable WIX 3 doesn't support ARM64, so we build installers as x86 -->
<?define PowerToysPlatform="ARM64"?>
<!--TODO: define to ARM64 Program files once it's available-->
<?define PlatformProgramFiles="[ProgramFiles6432Folder]"?>
<?define PlatformLK="arm64" ?>
<?define BinDir="$(var.RepoDir)ARM64\$(var.Configuration)\" ?>
<?if $(var.InstallerBinDir) != ""?>
<?define BinDir="$(var.InstallerBinDir)\" ?>
<?else?>
<?define BinDir="$(var.RepoDir)ARM64\$(var.Configuration)\" ?>
<?endif?>
<?endif?>
<?if $(var.PerUser) = "true"?>

View File

@@ -1,9 +1,10 @@
<Project Sdk="WixToolset.Sdk/5.0.2">
<PropertyGroup>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<InstallerBinDir Condition="'$(InstallerBinDir)' == ''"></InstallerBinDir>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>Version=$(Version)</DefineConstants>
<DefineConstants>Version=$(Version);InstallerBinDir=$(InstallerBinDir)</DefineConstants>
<Name>PowerToysVNextBootstrapper</Name>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' == 'true' ">
@@ -58,4 +59,4 @@
</ItemGroup>
</Target>
<Target Name="Restore" />
</Project>
</Project>

View File

@@ -2,9 +2,10 @@
<Import Project="..\..\src\CmdPalVersion.props" Condition="Exists('..\..\src\CmdPalVersion.props')" />
<PropertyGroup>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<InstallerBinDir Condition="'$(InstallerBinDir)' == ''"></InstallerBinDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' == 'x64'">
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\x64\$(Configuration)\Assets\Monaco\monacoSRC;CmdPalVersion=$(CmdPalVersion)</DefineConstants> <!-- THIS IS AN INNER LOOP OPTIMIZATION
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\x64\$(Configuration)\Assets\Monaco\monacoSRC;CmdPalVersion=$(CmdPalVersion);InstallerBinDir=$(InstallerBinDir)</DefineConstants> <!-- THIS IS AN INNER LOOP OPTIMIZATION
The build pipeline builds the Settings and Launcher projects for Publication
using a specific profile. If you're doing local installer builds, this will
simulate the build pipeline doing that for you. -->
@@ -17,7 +18,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' != 'x64'">
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\ARM64\$(Configuration)\Assets\Monaco\monacoSRC;CmdPalVersion=$(CmdPalVersion)</DefineConstants>
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\ARM64\$(Configuration)\Assets\Monaco\monacoSRC;CmdPalVersion=$(CmdPalVersion);InstallerBinDir=$(InstallerBinDir)</DefineConstants>
<PreBuildEvent>IF NOT DEFINED IsPipeline (
call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=arm64 -host_arch=amd64 -winsdk=10.0.19041.0 -vcvars_ver=$(VCToolsVersion)
SET PTRoot=$(SolutionDir)\..

View File

@@ -1,7 +1,10 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, Position = 1)]
[string]$platform
[string]$platform,
[Parameter(Mandatory = $False)]
[AllowEmptyString()]
[string]$binRoot
)
Function Generate-FileList() {
@@ -130,16 +133,24 @@ if ($platform -ceq "arm64") {
$platform = "ARM64"
}
$resolvedBinRoot = if ([string]::IsNullOrWhiteSpace($binRoot)) {
[System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\..\..\$platform\Release"))
} else {
[System.IO.Path]::GetFullPath($binRoot)
}
$winUI3AppsRoot = Join-Path $resolvedBinRoot "WinUI3Apps"
#BaseApplications
Generate-FileList -fileDepsJson "" -fileListName BaseApplicationsFiles -wxsFilePath $PSScriptRoot\BaseApplications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release"
Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSScriptRoot\BaseApplications.wxs
#WinUI3Applications
Generate-FileList -fileDepsJson "" -fileListName WinUI3ApplicationsFiles -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps"
Generate-FileList -fileDepsJson "" -fileListName WinUI3ApplicationsFiles -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -depsPath $winUI3AppsRoot
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs
#AdvancedPaste
Generate-FileList -fileDepsJson "" -fileListName AdvancedPasteAssetsFiles -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\AdvancedPaste"
Generate-FileList -fileDepsJson "" -fileListName AdvancedPasteAssetsFiles -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\AdvancedPaste")
Generate-FileComponents -fileListName "AdvancedPasteAssetsFiles" -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs
#AwakeFiles
@@ -151,7 +162,7 @@ Generate-FileList -fileDepsJson "" -fileListName ColorPickerAssetsFiles -wxsFile
Generate-FileComponents -fileListName "ColorPickerAssetsFiles" -wxsFilePath $PSScriptRoot\ColorPicker.wxs
#Environment Variables
Generate-FileList -fileDepsJson "" -fileListName EnvironmentVariablesAssetsFiles -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\EnvironmentVariables"
Generate-FileList -fileDepsJson "" -fileListName EnvironmentVariablesAssetsFiles -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\EnvironmentVariables")
Generate-FileComponents -fileListName "EnvironmentVariablesAssetsFiles" -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs
#FileExplorerAdd-ons
@@ -161,15 +172,15 @@ Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -w
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
#FileLocksmith
Generate-FileList -fileDepsJson "" -fileListName FileLocksmithAssetsFiles -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\FileLocksmith"
Generate-FileList -fileDepsJson "" -fileListName FileLocksmithAssetsFiles -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\FileLocksmith")
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs
#Hosts
Generate-FileList -fileDepsJson "" -fileListName HostsAssetsFiles -wxsFilePath $PSScriptRoot\Hosts.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Hosts"
Generate-FileList -fileDepsJson "" -fileListName HostsAssetsFiles -wxsFilePath $PSScriptRoot\Hosts.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\Hosts")
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs
#ImageResizer
Generate-FileList -fileDepsJson "" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\ImageResizer"
Generate-FileList -fileDepsJson "" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\ImageResizer")
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs
#KeyboardManager
@@ -181,19 +192,19 @@ Generate-FileList -fileDepsJson "" -fileListName LightSwitchFiles -wxsFilePath $
Generate-FileComponents -fileListName "LightSwitchFiles" -wxsFilePath $PSScriptRoot\LightSwitch.wxs
#New+
Generate-FileList -fileDepsJson "" -fileListName NewPlusAssetsFiles -wxsFilePath $PSScriptRoot\NewPlus.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\NewPlus"
Generate-FileList -fileDepsJson "" -fileListName NewPlusAssetsFiles -wxsFilePath $PSScriptRoot\NewPlus.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\NewPlus")
Generate-FileComponents -fileListName "NewPlusAssetsFiles" -wxsFilePath $PSScriptRoot\NewPlus.wxs
#Peek
Generate-FileList -fileDepsJson "" -fileListName PeekAssetsFiles -wxsFilePath $PSScriptRoot\Peek.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Peek\"
Generate-FileList -fileDepsJson "" -fileListName PeekAssetsFiles -wxsFilePath $PSScriptRoot\Peek.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\Peek")
Generate-FileComponents -fileListName "PeekAssetsFiles" -wxsFilePath $PSScriptRoot\Peek.wxs
#PowerRename
Generate-FileList -fileDepsJson "" -fileListName PowerRenameAssetsFiles -wxsFilePath $PSScriptRoot\PowerRename.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\PowerRename\"
Generate-FileList -fileDepsJson "" -fileListName PowerRenameAssetsFiles -wxsFilePath $PSScriptRoot\PowerRename.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\PowerRename")
Generate-FileComponents -fileListName "PowerRenameAssetsFiles" -wxsFilePath $PSScriptRoot\PowerRename.wxs
#RegistryPreview
Generate-FileList -fileDepsJson "" -fileListName RegistryPreviewAssetsFiles -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\RegistryPreview\"
Generate-FileList -fileDepsJson "" -fileListName RegistryPreviewAssetsFiles -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\RegistryPreview")
Generate-FileComponents -fileListName "RegistryPreviewAssetsFiles" -wxsFilePath $PSScriptRoot\RegistryPreview.wxs
#Run
@@ -307,11 +318,11 @@ Generate-FileList -fileDepsJson "" -fileListName ShortcutGuideSvgFiles -wxsFileP
Generate-FileComponents -fileListName "ShortcutGuideSvgFiles" -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs
#Settings
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\OOBE\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsFluentIconsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2IconsModelsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\Models\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\Settings")
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\Settings\Modules")
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\Settings\Modules\OOBE")
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsFluentIconsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\Settings\Icons")
Generate-FileList -fileDepsJson "" -fileListName SettingsV2IconsModelsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath (Join-Path $winUI3AppsRoot "Assets\Settings\Icons\Models")
Generate-FileComponents -fileListName "SettingsV2AssetsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2AssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs

View File

@@ -16,8 +16,8 @@ namespace ManagedCommon
{
public static void WaitForPowerToysRunner(int powerToysPID, Action act, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "")
{
var stackTrace = new StackTrace();
var assembly = Assembly.GetCallingAssembly().GetName();
// AOT-compatible: Use GetExecutingAssembly instead of GetCallingAssembly (not supported in AOT)
var assembly = Assembly.GetExecutingAssembly().GetName();
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{memberName}]WaitForPowerToysRunner waiting for Event powerToysPID={powerToysPID}" });
Task.Run(() =>
{

View File

@@ -216,7 +216,7 @@ namespace Microsoft.PowerToys.UITest
Rectangle bounds = new Rectangle(0, 0, screenWidth, screenHeight);
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format24bppRgb))
{
using (Graphics g = Graphics.FromImage(bitmap))
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);

View File

@@ -6,11 +6,14 @@
<OutputType>Library</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
<!-- UITestAutomation is a test library and should not use AOT -->
<PublishAot>false</PublishAot>
<InvariantGlobalization>false</InvariantGlobalization>
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<PublishTrimmed>false</PublishTrimmed>
<!-- Suppress code analysis warnings for test library -->
<NoWarn>$(NoWarn);CA1305;CA1310;CA2101</NoWarn>
</PropertyGroup>
<ItemGroup>
@@ -20,6 +23,7 @@
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="System.Text.RegularExpressions" />
<PackageReference Include="CoenM.ImageSharp.ImageHash" />
<PackageReference Include="System.Drawing.Common" />
</ItemGroup>
<ItemGroup>

View File

@@ -30,7 +30,7 @@
<!-- The following sections assume that the machine we're building on is always x64. That means we won't be able to run/inspect arm64 executables, therefore we must always execute x64 generator. -->
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64'">
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64' and '$(SkipSettingsDscSchemaPostBuild)' != 'true'">
<Exec Command="&quot;$(OutDir)$(AssemblyName).exe&quot; &quot;..\..\..\x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll&quot; $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
</Target>
</Project>

View File

@@ -63,11 +63,12 @@
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
<!-- Only enable Native AOT for Release builds to avoid System.Private.CoreLib.dll version conflicts during development -->
<!-- Temporarily disable Native AOT until C++ Desktop Development workload is installed -->
<!-- TODO: Re-enable after installing Desktop Development for C++ in Visual Studio -->
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
<PublishAot>true</PublishAot>
<PublishTrimmed>false</PublishTrimmed>
<PublishSingleFile>false</PublishSingleFile>
<PublishAot>false</PublishAot>
</PropertyGroup>
<!-- For Debug builds, use standard JIT compilation -->

View File

@@ -56,9 +56,11 @@
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="Shaders\GridShader.fx" />
</ItemGroup>
<ItemGroup>
<Content Include="Shaders\GridShader.fx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DependentUpon>Resources.resx</DependentUpon>

View File

@@ -3,6 +3,13 @@
<Import Project="$(RepoRoot)src\Common.Dotnet.CsWinRT.props" />
<Import Project="$(RepoRoot)src\Common.SelfContained.props" />
<!-- Force WebView2 to use Win32/WinForms mode instead of WinRT mode -->
<!-- Required because Settings.UI.Library has UseWinUI=true which triggers WebView2UseWinRT -->
<PropertyGroup>
<WebView2UseWinRT>false</WebView2UseWinRT>
<WebView2EnableCsWinRTProjection>false</WebView2EnableCsWinRTProjection>
</PropertyGroup>
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<UseWindowsForms>true</UseWindowsForms>

View File

@@ -3,6 +3,13 @@
<Import Project="$(RepoRoot)src\Common.Dotnet.CsWinRT.props" />
<Import Project="$(RepoRoot)src\Common.SelfContained.props" />
<!-- Force WebView2 to use Win32/WinForms mode instead of WinRT mode -->
<!-- Required because Settings.UI.Library has UseWinUI=true which triggers WebView2UseWinRT -->
<PropertyGroup>
<WebView2UseWinRT>false</WebView2UseWinRT>
<WebView2EnableCsWinRTProjection>false</WebView2EnableCsWinRTProjection>
</PropertyGroup>
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<UseWindowsForms>true</UseWindowsForms>

View File

@@ -2,6 +2,12 @@
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="$(RepoRoot)src\Common.Dotnet.CsWinRT.props" />
<!-- Force WebView2 to use Win32/WinForms mode for unit tests -->
<PropertyGroup>
<WebView2UseWinRT>false</WebView2UseWinRT>
<WebView2EnableCsWinRTProjection>false</WebView2EnableCsWinRTProjection>
</PropertyGroup>
<PropertyGroup>
<SelfContained>true</SelfContained>
<RuntimeIdentifier Condition="'$(Platform)' == 'x64'">win-x64</RuntimeIdentifier>

View File

@@ -1,6 +1,14 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup Condition="'$(MSBuildProjectName)' == 'PowerToys.Settings' and '$(SkipSettingsRegularBuildForAotPackaging)' == 'true'">
<BuildDependsOn>SkipSettingsRegularBuildForAotPackaging</BuildDependsOn>
</PropertyGroup>
<Target Name="SkipSettingsRegularBuildForAotPackaging" Condition="'$(MSBuildProjectName)' == 'PowerToys.Settings' and '$(SkipSettingsRegularBuildForAotPackaging)' == 'true'">
<Message Importance="high" Text="[Settings] Skipping regular Build because installer packaging will use Native AOT Publish output instead." />
</Target>
<Target Name="IncrementalClean" />
</Project>
</Project>

View File

@@ -5,7 +5,7 @@
using System; // For Action
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Microsoft.PowerToys.Settings.UI.Library;
namespace Microsoft.PowerToys.Settings.UI.Controls
{

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Windows.Input;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.UI.Xaml;

View File

@@ -24,8 +24,8 @@
<DataTemplate x:DataType="local:QuickAccessItem">
<local:FlyoutMenuButton
AutomationProperties.Name="{x:Bind Title}"
Command="{x:Bind Command}"
CommandParameter="{x:Bind CommandParameter}"
Click="FlyoutMenuButton_Click"
Tag="{x:Bind}"
Visibility="{x:Bind Visible, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<local:FlyoutMenuButton.Content>
<TextBlock

View File

@@ -22,5 +22,13 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
}
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(QuickAccessList), new PropertyMetadata(null));
private void FlyoutMenuButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button && button.Tag is QuickAccessItem item)
{
item.Command?.Execute(item.CommandParameter);
}
}
}
}

View File

@@ -9,6 +9,7 @@ using Microsoft.PowerToys.Settings.UI.Library.Helpers;
namespace Microsoft.PowerToys.Settings.UI.Library;
[WinRT.GeneratedBindableCustomProperty]
public sealed partial class AdvancedPasteAdditionalAction : Observable, IAdvancedPasteAction
{
private HotkeySettings _shortcut = new();

View File

@@ -10,7 +10,8 @@ using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
namespace Microsoft.PowerToys.Settings.UI.Library;
public sealed class AdvancedPasteCustomAction : Observable, IAdvancedPasteAction, ICloneable
[WinRT.GeneratedBindableCustomProperty]
public sealed partial class AdvancedPasteCustomAction : Observable, IAdvancedPasteAction, ICloneable
{
private int _id;
private string _name = string.Empty;

View File

@@ -9,7 +9,8 @@ using Microsoft.PowerToys.Settings.UI.Library.Helpers;
namespace Microsoft.PowerToys.Settings.UI.Library;
public sealed class AdvancedPastePasteAsFileAction : Observable, IAdvancedPasteAction
[WinRT.GeneratedBindableCustomProperty]
public sealed partial class AdvancedPastePasteAsFileAction : Observable, IAdvancedPasteAction
{
public static class PropertyNames
{

View File

@@ -9,7 +9,8 @@ using Microsoft.PowerToys.Settings.UI.Library.Helpers;
namespace Microsoft.PowerToys.Settings.UI.Library;
public sealed class AdvancedPasteTranscodeAction : Observable, IAdvancedPasteAction
[WinRT.GeneratedBindableCustomProperty]
public sealed partial class AdvancedPasteTranscodeAction : Observable, IAdvancedPasteAction
{
public static class PropertyNames
{

View File

@@ -71,7 +71,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.AlwaysOnTopProperties);
}
}
}

View File

@@ -9,7 +9,8 @@ using ManagedCommon;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class ColorFormatModel : INotifyPropertyChanged
[WinRT.GeneratedBindableCustomProperty]
public partial class ColorFormatModel : INotifyPropertyChanged
{
private string _name;
private string _format;

View File

@@ -570,7 +570,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.EnabledModules);
}
private static void LogTelemetryEvent(bool value, [CallerMemberName] string moduleName = null)

View File

@@ -160,7 +160,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
// converts the current to a json string.
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.FZConfigProperties);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.FindMyMouseSettingsIPCMessage);
}
}
}

View File

@@ -3,21 +3,58 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts
{
public class HotkeyConflictGroupData
public partial class HotkeyConflictGroupData : INotifyPropertyChanged
{
private bool _conflictIgnored;
private bool _isSystemConflict;
public HotkeyData Hotkey { get; set; }
public bool IsSystemConflict { get; set; }
public bool IsSystemConflict
{
get => _isSystemConflict;
set
{
if (_isSystemConflict != value)
{
_isSystemConflict = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShouldShowSysConflict));
}
}
}
public bool ConflictIgnored { get; set; }
public bool ConflictIgnored
{
get => _conflictIgnored;
set
{
if (_conflictIgnored != value)
{
_conflictIgnored = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ConflictVisible));
OnPropertyChanged(nameof(ShouldShowSysConflict));
}
}
}
public bool ConflictVisible => !ConflictIgnored;
public bool ShouldShowSysConflict => !ConflictIgnored && IsSystemConflict;
public List<ModuleHotkeyData> Modules { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.Settings.UI.Library
{
/// <summary>
/// ICommand interface for WinUI 3 applications, compatible with Native AOT.
/// Extends System.Windows.Input.ICommand which is also recognized by WinUI3 XAML bindings.
/// </summary>
public interface ICommand : System.Windows.Input.ICommand
{
}
}

View File

@@ -13,6 +13,7 @@ using Settings.UI.Library.Resources;
namespace Microsoft.PowerToys.Settings.UI.Library;
[WinRT.GeneratedBindableCustomProperty]
public partial class ImageSize : INotifyPropertyChanged, IHasId
{
public event PropertyChangedEventHandler PropertyChanged;
@@ -118,5 +119,5 @@ public partial class ImageSize : INotifyPropertyChanged, IHasId
[JsonIgnore]
public ImageSize AccessibleTextHelper => this;
public string ToJsonString() => JsonSerializer.Serialize(this);
public string ToJsonString() => JsonSerializer.Serialize(this, SettingsSerializationContext.Default.ImageSize);
}

View File

@@ -42,7 +42,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.KeyboardManagerProperties);
}
}
}

View File

@@ -13,7 +13,6 @@ using System.Management;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Windows.Input;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
@@ -313,7 +312,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.KeysDataModel);
}
}
}

View File

@@ -9,7 +9,8 @@ using System.Text.Json;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class LanguageModel
[WinRT.GeneratedBindableCustomProperty]
public partial class LanguageModel
{
public const string SettingsFilePath = "\\Microsoft\\PowerToys\\";
public const string SettingsFile = "language.json";
@@ -36,7 +37,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
inputStream.Close();
reader.Dispose();
return JsonSerializer.Deserialize<OutGoingLanguageSettings>(data).LanguageTag;
return JsonSerializer.Deserialize(data, SettingsSerializationContext.Default.OutGoingLanguageSettings).LanguageTag;
}
catch (Exception)
{

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.MouseHighlighterSettingsIPCMessage);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.MousePointerCrosshairsSettingsIPCMessage);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.PowerRenameSettingsIPCMessage);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.RemapKeysDataModel);
}
}
}

View File

@@ -5,6 +5,8 @@
<PropertyGroup>
<Description>PowerToys Settings UI Library</Description>
<AssemblyName>PowerToys.Settings.UI.Lib</AssemblyName>
<!-- Enable WinUI to access Microsoft.UI.Xaml.Input.ICommand for AOT-compatible command binding -->
<UseWinUI>true</UseWinUI>
</PropertyGroup>
<ItemGroup>
@@ -15,6 +17,7 @@
<ItemGroup>
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
</ItemGroup>
<ItemGroup>

View File

@@ -33,6 +33,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
{
WriteIndented = true,
TypeInfoResolver = SettingsSerializationContext.Default,
};
private SettingsBackupAndRestoreUtils()
@@ -1024,7 +1025,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
private static List<object> DeserializeArray(string json)
{
var result = JsonSerializer.Deserialize<List<object>>(json);
var result = JsonSerializer.Deserialize(json, SettingsSerializationContext.Default.ListObject);
var updates = new List<object>();
@@ -1053,12 +1054,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
return updates.OrderBy(x => JsonSerializer.Serialize(x)).ToList();
return updates.OrderBy(x => JsonSerializer.Serialize(x, _serializerOptions)).ToList();
}
private static Dictionary<string, object> Deserialize(string json)
{
var doc = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
var doc = JsonSerializer.Deserialize(json, SettingsSerializationContext.Default.DictionaryStringObject);
var updates = new Dictionary<string, object>();

View File

@@ -128,10 +128,13 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonSerializable(typeof(ColorFormatModel))]
[JsonSerializable(typeof(ImageSize))]
[JsonSerializable(typeof(KeysDataModel))]
[JsonSerializable(typeof(RemapKeysDataModel))]
[JsonSerializable(typeof(ShortcutsKeyDataModel))]
[JsonSerializable(typeof(EnabledModules))]
[JsonSerializable(typeof(GeneralSettingsCustomAction))]
[JsonSerializable(typeof(OutGoingGeneralSettings))]
[JsonSerializable(typeof(OutGoingLanguageSettings))]
[JsonSerializable(typeof(UpdatingSettings))]
[JsonSerializable(typeof(AdvancedPasteCustomActions))]
[JsonSerializable(typeof(AdvancedPasteAdditionalActions))]
[JsonSerializable(typeof(AdvancedPasteCustomAction))]
@@ -153,6 +156,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonSerializable(typeof(List<VcpValueInfo>))]
[JsonSerializable(typeof(SettingsUILibraryHelpers.SearchLocation))]
// Search Index Types (for AOT compatibility)
[JsonSerializable(typeof(SettingsUILibrary.SettingEntry))]
[JsonSerializable(typeof(SettingsUILibrary.SettingEntry[]))]
[JsonSerializable(typeof(SettingsUILibrary.EntryType))]
// IPC Message Types (for AOT compatibility)
[JsonSerializable(typeof(FindMyMouseSettingsIPCMessage))]
[JsonSerializable(typeof(MouseHighlighterSettingsIPCMessage))]
[JsonSerializable(typeof(MousePointerCrosshairsSettingsIPCMessage))]
[JsonSerializable(typeof(PowerRenameSettingsIPCMessage))]
[JsonSerializable(typeof(ShortcutGuideSettingsIPCMessage))]
// Collection Types (for AOT compatibility in backup/restore)
[JsonSerializable(typeof(List<object>))]
[JsonSerializable(typeof(Dictionary<string, object>))]
// AdvancedPaste AI Provider Types (for AOT compatibility)
[JsonSerializable(typeof(PasteAIConfiguration))]
[JsonSerializable(typeof(PasteAIProviderDefinition))]
@@ -169,13 +188,17 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonSerializable(typeof(SndAwakeSettings))]
[JsonSerializable(typeof(SndCursorWrapSettings))]
[JsonSerializable(typeof(SndFindMyMouseSettings))]
[JsonSerializable(typeof(SndImageResizerSettings))]
[JsonSerializable(typeof(SndKeyboardManagerSettings))]
[JsonSerializable(typeof(SndLightSwitchSettings))]
[JsonSerializable(typeof(SndMouseHighlighterSettings))]
[JsonSerializable(typeof(SndMouseJumpSettings))]
[JsonSerializable(typeof(SndMousePointerCrosshairsSettings))]
[JsonSerializable(typeof(SndPowerAccentSettings))]
[JsonSerializable(typeof(SndPowerOcrSettings))]
[JsonSerializable(typeof(SndPowerPreviewSettings))]
[JsonSerializable(typeof(SndPowerRenameSettings))]
[JsonSerializable(typeof(SndRegistryPreviewSettings))]
[JsonSerializable(typeof(SndShortcutGuideSettings))]
// IPC Message Generic Wrapper Types (SndModuleSettings<T>)

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.ShortcutGuideSettingsIPCMessage);
}
}
}

View File

@@ -27,7 +27,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.ShortcutsKeyDataModel);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndAwakeSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndCursorWrapSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndFindMyMouseSettings);
}
}
}

View File

@@ -19,7 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndImageResizerSettings);
}
}
}

View File

@@ -19,7 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndKeyboardManagerSettings);
}
}
}

View File

@@ -24,7 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndLightSwitchSettings);
}
}
}

View File

@@ -24,7 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.Options);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndMouseHighlighterSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndMouseJumpSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndMousePointerCrosshairsSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndPowerAccentSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndPowerOcrSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndPowerPreviewSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndPowerRenameSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndRegistryPreviewSettings);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.SndShortcutGuideSettings);
}
}
}

View File

@@ -108,7 +108,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
inputStream.Close();
reader.Dispose();
return JsonSerializer.Deserialize<UpdatingSettings>(data);
return JsonSerializer.Deserialize(data, SettingsSerializationContext.Default.UpdatingSettings);
}
catch (Exception)
{
@@ -120,7 +120,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.UpdatingSettings);
}
}
}

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Windows.Input;
using Microsoft.PowerToys.Settings.UI.Library;
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands
{

View File

@@ -2,32 +2,36 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Windows.Input;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands
{
public class RelayCommand : ICommand
// Preserve for AOT - ensure command execution methods are not trimmed
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)]
public class RelayCommand : Microsoft.PowerToys.Settings.UI.Library.ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
private readonly Func<bool>? _canExecute;
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;
public RelayCommand(Action execute)
: this(execute, null)
{
}
public RelayCommand(Action execute, Func<bool> canExecute)
public RelayCommand(Action execute, Func<bool>? canExecute)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute();
public bool CanExecute(object? parameter) => _canExecute == null || _canExecute();
public void Execute(object parameter) => _execute();
public void Execute(object? parameter) => _execute();
public void OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}

View File

@@ -2,33 +2,47 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Windows.Input;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands
{
public class RelayCommand<T> : ICommand
// Preserve for AOT - ensure command execution methods are not trimmed
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)]
public class RelayCommand<T> : Microsoft.PowerToys.Settings.UI.Library.ICommand
{
private readonly Action<T> execute;
private readonly Func<T, bool> canExecute;
private readonly Func<T, bool>? canExecute;
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
public RelayCommand(Action<T> execute, Func<T, bool> canExecute)
public RelayCommand(Action<T> execute, Func<T, bool>? canExecute)
{
this.execute = execute ?? throw new ArgumentNullException(nameof(execute));
this.canExecute = canExecute;
}
public bool CanExecute(object parameter) => canExecute == null || canExecute((T)parameter);
public bool CanExecute(object? parameter)
{
// AOT-friendly: no reflection, just direct cast
// The null-forgiving operator is safe here because we're just checking CanExecute
return canExecute == null || canExecute((T)parameter!);
}
public void Execute(object parameter) => execute((T)parameter);
public void Execute(object? parameter)
{
// AOT-friendly: simple cast, no reflection or type checking
// This matches the original main branch behavior exactly
execute((T)parameter!);
}
public void OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}

View File

@@ -31,7 +31,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.WorkspacesProperties);
}
}
}

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Windows;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml.Data;

View File

@@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml.Data;
@@ -30,7 +29,7 @@ public sealed partial class ImageResizerFitToStringConverter : IValueConverter
fitText;
}
return DependencyProperty.UnsetValue;
return Microsoft.UI.Xaml.DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)

View File

@@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml.Data;
@@ -38,7 +37,7 @@ public sealed partial class ImageResizerSizeToAccessibleTextConverter : IValueCo
{
(string presetName, string nameId) => FormatNameText(presetName, nameId),
(ImageSize preset, string _) => FormatDescriptionText(preset),
_ => DependencyProperty.UnsetValue,
_ => Microsoft.UI.Xaml.DependencyProperty.UnsetValue,
};
}
@@ -46,14 +45,14 @@ public sealed partial class ImageResizerSizeToAccessibleTextConverter : IValueCo
{
return AccessibilityFormats.TryGetValue(nameId, out string format) ?
string.Format(CultureInfo.CurrentCulture, format, presetName) :
DependencyProperty.UnsetValue;
Microsoft.UI.Xaml.DependencyProperty.UnsetValue;
}
private object FormatDescriptionText(ImageSize preset)
{
if (preset == null)
{
return DependencyProperty.UnsetValue;
return Microsoft.UI.Xaml.DependencyProperty.UnsetValue;
}
string fitText = _fitConverter.Convert(preset.Fit, typeof(string), null, null) as string;

View File

@@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml.Data;
@@ -31,7 +30,7 @@ public sealed partial class ImageResizerUnitToStringConverter : IValueConverter
unitText;
}
return DependencyProperty.UnsetValue;
return Microsoft.UI.Xaml.DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)

View File

@@ -20,7 +20,8 @@ namespace Microsoft.PowerToys.Settings.UI.Converters
}
else
{
return (Microsoft.UI.Xaml.Controls.InfoBarSeverity)Enum.Parse(typeof(Microsoft.UI.Xaml.Controls.InfoBarSeverity), (string)value, true);
// Use generic overload for AOT compatibility (IL2026)
return Enum.Parse<Microsoft.UI.Xaml.Controls.InfoBarSeverity>((string)value, ignoreCase: true);
}
}
catch

View File

@@ -2,34 +2,35 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Microsoft.PowerToys.Settings.UI.Helpers
{
internal sealed partial class AsyncCommand : ICommand
internal sealed partial class AsyncCommand : Microsoft.PowerToys.Settings.UI.Library.ICommand
{
private readonly Func<Task> _execute;
private readonly Func<bool> _canExecute;
private readonly Func<bool>? _canExecute;
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;
public AsyncCommand(Func<Task> execute, Func<bool> canExecute = null)
public AsyncCommand(Func<Task> execute, Func<bool>? canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
public bool CanExecute(object? parameter)
{
return _canExecute == null || _canExecute();
}
public async void Execute(object parameter)
public async void Execute(object? parameter)
{
await _execute();
}

View File

@@ -16,7 +16,8 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class CHOOSEFONT
{
public int lStructSize = Marshal.SizeOf(typeof(CHOOSEFONT));
// Use generic overload for AOT compatibility (IL3050)
public int lStructSize = Marshal.SizeOf<CHOOSEFONT>();
public IntPtr hwndOwner = IntPtr.Zero;
public IntPtr hDC = IntPtr.Zero;
public IntPtr lpLogFont = IntPtr.Zero;

View File

@@ -2,59 +2,60 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Windows.Input;
namespace Microsoft.PowerToys.Settings.UI.Helpers
{
public partial class RelayCommand : ICommand
public partial class RelayCommand : Microsoft.PowerToys.Settings.UI.Library.ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
private readonly Func<bool>? _canExecute;
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;
public RelayCommand(Action execute)
: this(execute, null)
{
}
public RelayCommand(Action execute, Func<bool> canExecute)
public RelayCommand(Action execute, Func<bool>? canExecute)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute();
public bool CanExecute(object? parameter) => _canExecute == null || _canExecute();
public void Execute(object parameter) => _execute();
public void Execute(object? parameter) => _execute();
public void OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "abstract T and abstract")]
public partial class RelayCommand<T> : ICommand
public partial class RelayCommand<T> : Microsoft.PowerToys.Settings.UI.Library.ICommand
{
private readonly Action<T> execute;
private readonly Func<T, bool> canExecute;
private readonly Func<T, bool>? canExecute;
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
public RelayCommand(Action<T> execute, Func<T, bool> canExecute)
public RelayCommand(Action<T> execute, Func<T, bool>? canExecute)
{
this.execute = execute ?? throw new ArgumentNullException(nameof(execute));
this.canExecute = canExecute;
}
public bool CanExecute(object parameter) => canExecute == null || canExecute((T)parameter);
public bool CanExecute(object? parameter) => canExecute == null || canExecute((T)parameter!);
public void Execute(object parameter) => execute((T)parameter);
public void Execute(object? parameter) => execute((T)parameter!);
public void OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}

View File

@@ -0,0 +1,161 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// This is a local copy of Common.UI.SettingsDeepLink for AOT compatibility.
// Common.UI cannot be referenced in AOT builds because it depends on WPF.
#if BUILD_INFO_PUBLISH_AOT
using System;
using System.Diagnostics;
using System.IO;
using ManagedCommon;
namespace Microsoft.PowerToys.Settings.UI.Helpers
{
public static class SettingsDeepLink
{
public enum SettingsWindow
{
Dashboard = 0,
Overview,
AlwaysOnTop,
Awake,
ColorPicker,
CmdNotFound,
LightSwitch,
FancyZones,
FileLocksmith,
Run,
ImageResizer,
KBM,
MouseUtils,
MouseWithoutBorders,
Peek,
PowerAccent,
PowerLauncher,
PowerPreview,
PowerRename,
FileExplorer,
ShortcutGuide,
Hosts,
MeasureTool,
PowerOCR,
Workspaces,
RegistryPreview,
CropAndLock,
EnvironmentVariables,
AdvancedPaste,
NewPlus,
CmdPal,
ZoomIt,
PowerDisplay,
}
private static string SettingsWindowNameToString(SettingsWindow value)
{
switch (value)
{
case SettingsWindow.Dashboard:
return "Dashboard";
case SettingsWindow.Overview:
return "Overview";
case SettingsWindow.AlwaysOnTop:
return "AlwaysOnTop";
case SettingsWindow.Awake:
return "Awake";
case SettingsWindow.ColorPicker:
return "ColorPicker";
case SettingsWindow.CmdNotFound:
return "CmdNotFound";
case SettingsWindow.LightSwitch:
return "LightSwitch";
case SettingsWindow.FancyZones:
return "FancyZones";
case SettingsWindow.FileLocksmith:
return "FileLocksmith";
case SettingsWindow.Run:
return "Run";
case SettingsWindow.ImageResizer:
return "ImageResizer";
case SettingsWindow.KBM:
return "KBM";
case SettingsWindow.MouseUtils:
return "MouseUtils";
case SettingsWindow.MouseWithoutBorders:
return "MouseWithoutBorders";
case SettingsWindow.Peek:
return "Peek";
case SettingsWindow.PowerAccent:
return "PowerAccent";
case SettingsWindow.PowerLauncher:
return "PowerLauncher";
case SettingsWindow.PowerPreview:
return "PowerPreview";
case SettingsWindow.PowerRename:
return "PowerRename";
case SettingsWindow.FileExplorer:
return "FileExplorer";
case SettingsWindow.ShortcutGuide:
return "ShortcutGuide";
case SettingsWindow.Hosts:
return "Hosts";
case SettingsWindow.MeasureTool:
return "MeasureTool";
case SettingsWindow.PowerOCR:
return "PowerOcr";
case SettingsWindow.Workspaces:
return "Workspaces";
case SettingsWindow.RegistryPreview:
return "RegistryPreview";
case SettingsWindow.CropAndLock:
return "CropAndLock";
case SettingsWindow.EnvironmentVariables:
return "EnvironmentVariables";
case SettingsWindow.AdvancedPaste:
return "AdvancedPaste";
case SettingsWindow.NewPlus:
return "NewPlus";
case SettingsWindow.CmdPal:
return "CmdPal";
case SettingsWindow.ZoomIt:
return "ZoomIt";
case SettingsWindow.PowerDisplay:
return "PowerDisplay";
default:
{
return string.Empty;
}
}
}
public static void OpenSettings(SettingsWindow window)
{
try
{
var exePath = Path.Combine(
PowerToysPathResolver.GetPowerToysInstallPath(),
"PowerToys.exe");
if (exePath == null || !File.Exists(exePath))
{
Logger.LogError($"Failed to find powertoys exe path, {exePath}");
return;
}
var args = "--open-settings=" + SettingsWindowNameToString(window);
Process.Start(new ProcessStartInfo
{
FileName = exePath,
Arguments = args,
UseShellExecute = false,
});
}
catch (Exception ex)
{
Logger.LogError(ex.Message);
}
}
}
}
#endif

View File

@@ -6,8 +6,9 @@ using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Windows.Management.Deployment;
using Windows.System;
@@ -16,7 +17,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
/// <summary>
/// Helper class to manage installation status and installation command for a Microsoft Store extension.
/// </summary>
public class StoreExtensionHelper : INotifyPropertyChanged
public partial class StoreExtensionHelper : INotifyPropertyChanged
{
private readonly string _packageFamilyName;
private readonly string _storeUri;

View File

@@ -1,12 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="$(RepoRoot)src\Common.Dotnet.CsWinRT.props" />
<Import Project="$(RepoRoot)src\Common.Dotnet.AotCompatibility.props" />
<Import Project="$(RepoRoot)src\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<RootNamespace>Microsoft.PowerToys.Settings.UI</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>true</UseWinUI>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<WindowsPackageType>None</WindowsPackageType>
@@ -19,6 +21,27 @@
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
<ProjectPriFileName>PowerToys.Settings.pri</ProjectPriFileName>
</PropertyGroup>
<!-- Settings Native AOT is enabled on this branch; packaging chooses whether to publish and normalize it. -->
<PropertyGroup>
<EnableSettingsAOT>true</EnableSettingsAOT>
</PropertyGroup>
<PropertyGroup Condition="'$(EnableSettingsAOT)' == 'true'">
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
<DisableRuntimeMarshalling>false</DisableRuntimeMarshalling>
<PublishAot>true</PublishAot>
<NormalizeSettingsAotOutput Condition="'$(NormalizeSettingsAotOutput)' == ''">false</NormalizeSettingsAotOutput>
<SettingsAotNormalizedOutputDir Condition="'$(SettingsAotNormalizedOutputDir)' == ''">$(OutputPath)</SettingsAotNormalizedOutputDir>
<!-- Use environmental tools to bypass VS version detection issue with VS 2026 -->
<IlcUseEnvironmentalTools>true</IlcUseEnvironmentalTools>
<!-- Trim is mandatory for AOT, but disable reflection removal to preserve WPF compatibility -->
<IlcDisableReflection>false</IlcDisableReflection>
<!-- Suppress trim/AOT warnings from third-party assemblies and XAML Command binding type checks -->
<NoWarn>$(NoWarn);IL2026;IL2060;IL2070;IL2071;IL2072;IL2075;IL2076;IL2104;IL3000;IL3002;IL3050;IL3053;WMC1121</NoWarn>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\Settings\Icons\Models\Azure.svg" />
<None Remove="Assets\Settings\Icons\Models\FoundryLocal.svg" />
@@ -59,9 +82,25 @@
</ItemGroup>
<ItemGroup>
<!-- Navigation Icons - PNG files (required for AOT publish) -->
<Content Include="Assets\Settings\Icons\*.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<!-- Module Images - PNG files (required for AOT publish) -->
<Content Include="Assets\Settings\Modules\*.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<!-- OOBE media is consumed directly by the installed app and must be present in AOT publish output. -->
<Content Include="Assets\Settings\Modules\OOBE\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<!-- AI Model Provider Icons - SVG files -->
<Content Include="Assets\Settings\Icons\Models\*.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
@@ -136,7 +175,7 @@
<!-- TODO: fix issues and reenable -->
<!-- These are caused by streamjsonrpc dependency on Microsoft.VisualStudio.Threading.Analyzers -->
<!-- We might want to add that to the project and fix the issues as well -->
<NoWarn>VSTHRD002;VSTHRD110;VSTHRD100;VSTHRD200;VSTHRD101</NoWarn>
<NoWarn>$(NoWarn);VSTHRD002;VSTHRD110;VSTHRD100;VSTHRD200;VSTHRD101</NoWarn>
</PropertyGroup>
<!-- Removed hard-coded resource exclusion. -->
@@ -155,24 +194,38 @@
<ItemGroup>
<None Update="Assets\Settings\icon.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<Content Update="Assets\Settings\*.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Update="Assets\Settings\Scripts\CheckCmdNotFoundRequirements.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<None Update="Assets\Settings\Scripts\InstallWinGetClientModule.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<None Update="Assets\Settings\Scripts\InstallPowerShell7.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<None Update="Assets\Settings\Scripts\EnableModule.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<None Update="Assets\Settings\Scripts\DisableModule.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<None Update="Assets\Settings\Scripts\UpgradeModule.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<Page Update="SettingsXAML\Controls\TitleBar\TitleBar.xaml">
<Generator>MSBuild:Compile</Generator>
@@ -210,4 +263,29 @@
<Message Importance="high" Text="[Settings] Building XamlIndexBuilder prior to compile. Views='$(MSBuildProjectDirectory)\SettingsXAML\Views' Out='$(GeneratedJsonFile)'" />
<MSBuild Projects="..\Settings.UI.XamlIndexBuilder\Settings.UI.XamlIndexBuilder.csproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Any CPU;TargetFramework=$(CoreTargetFramework);XamlViewsDir=$(MSBuildProjectDirectory)\SettingsXAML\Views;GeneratedJsonFile=$(GeneratedJsonFile)" />
</Target>
<Target Name="NormalizeSettingsAotPublishOutput" AfterTargets="_CopyAotSymbols" Condition="'$(PublishAot)' == 'true' and '$(NormalizeSettingsAotOutput)' == 'true'">
<PropertyGroup>
<_SettingsAotPublishDir>$([MSBuild]::EnsureTrailingSlash('$(PublishDir)'))</_SettingsAotPublishDir>
<_SettingsAotNormalizedOutputDir>$([MSBuild]::EnsureTrailingSlash('$(SettingsAotNormalizedOutputDir)'))</_SettingsAotNormalizedOutputDir>
</PropertyGroup>
<ItemGroup>
<_SettingsAotPublishFiles Include="$(_SettingsAotPublishDir)**\*" />
</ItemGroup>
<Message Importance="high" Text="[Settings] Normalizing Native AOT publish output from '$(_SettingsAotPublishDir)' to '$(_SettingsAotNormalizedOutputDir)'" />
<Copy SourceFiles="@(_SettingsAotPublishFiles)" DestinationFiles="@(_SettingsAotPublishFiles->'$(_SettingsAotNormalizedOutputDir)%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
</Target>
<!-- Build information for AOT -->
<PropertyGroup Condition=" '$(PublishAot)' == 'true' ">
<DefineConstants>$(DefineConstants);BUILD_INFO_PUBLISH_AOT</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(PublishTrimmed)' == 'true' ">
<DefineConstants>$(DefineConstants);BUILD_INFO_PUBLISH_TRIMMED</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(CIBuild)' == 'true' ">
<DefineConstants>$(DefineConstants);BUILD_INFO_CIBUILD</DefineConstants>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<PublishDir>$(RepoRoot)$(Platform)\$(Configuration)\WinUI3Apps\win-$(Platform)\publish\</PublishDir>
<RuntimeIdentifier>win-$(Platform)</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun>False</PublishReadyToRun>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
</Project>

View File

@@ -17,6 +17,7 @@ using System.Threading;
using System.Threading.Tasks;
using Common.Search.FuzzSearch;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.Windows.ApplicationModel.Resources;
using Settings.UI.Library;
@@ -33,7 +34,6 @@ namespace Microsoft.PowerToys.Settings.UI.Services
private static bool _isIndexBuilt;
private static bool _isIndexBuilding;
private const string PrebuiltIndexResourceName = "Microsoft.PowerToys.Settings.UI.Assets.search.index.json";
private static JsonSerializerOptions _serializerOptions = new() { PropertyNameCaseInsensitive = true };
public static ImmutableArray<SettingEntry> Index
{
@@ -121,7 +121,8 @@ namespace Microsoft.PowerToys.Settings.UI.Services
return;
}
metadataList = JsonSerializer.Deserialize<SettingEntry[]>(json, _serializerOptions);
// Use source-generated deserializer for AOT compatibility (IL2026/IL3050)
metadataList = JsonSerializer.Deserialize(json, SettingsSerializationContext.Default.SettingEntryArray);
}
catch (Exception ex)
{
@@ -262,6 +263,7 @@ namespace Microsoft.PowerToys.Settings.UI.Services
.ToList();
}
// AOT-compatible type lookup using switch expression instead of reflection (IL2026)
private static Type GetPageTypeFromName(string pageTypeName)
{
if (string.IsNullOrEmpty(pageTypeName))
@@ -276,8 +278,43 @@ namespace Microsoft.PowerToys.Settings.UI.Services
return cached;
}
var assembly = typeof(GeneralPage).Assembly;
var type = assembly.GetType($"Microsoft.PowerToys.Settings.UI.Views.{pageTypeName}");
// Use compile-time known types instead of Assembly.GetType for AOT compatibility
var type = pageTypeName switch
{
nameof(DashboardPage) => typeof(DashboardPage),
nameof(GeneralPage) => typeof(GeneralPage),
nameof(AdvancedPastePage) => typeof(AdvancedPastePage),
nameof(AlwaysOnTopPage) => typeof(AlwaysOnTopPage),
nameof(AwakePage) => typeof(AwakePage),
nameof(CmdNotFoundPage) => typeof(CmdNotFoundPage),
nameof(CmdPalPage) => typeof(CmdPalPage),
nameof(ColorPickerPage) => typeof(ColorPickerPage),
nameof(CropAndLockPage) => typeof(CropAndLockPage),
nameof(EnvironmentVariablesPage) => typeof(EnvironmentVariablesPage),
nameof(FancyZonesPage) => typeof(FancyZonesPage),
nameof(FileLocksmithPage) => typeof(FileLocksmithPage),
nameof(HostsPage) => typeof(HostsPage),
nameof(ImageResizerPage) => typeof(ImageResizerPage),
nameof(KeyboardManagerPage) => typeof(KeyboardManagerPage),
nameof(LightSwitchPage) => typeof(LightSwitchPage),
nameof(MeasureToolPage) => typeof(MeasureToolPage),
nameof(MouseUtilsPage) => typeof(MouseUtilsPage),
nameof(MouseWithoutBordersPage) => typeof(MouseWithoutBordersPage),
nameof(NewPlusPage) => typeof(NewPlusPage),
nameof(PeekPage) => typeof(PeekPage),
nameof(PowerAccentPage) => typeof(PowerAccentPage),
nameof(PowerLauncherPage) => typeof(PowerLauncherPage),
nameof(PowerOcrPage) => typeof(PowerOcrPage),
nameof(PowerPreviewPage) => typeof(PowerPreviewPage),
nameof(PowerRenamePage) => typeof(PowerRenamePage),
nameof(PowerDisplayPage) => typeof(PowerDisplayPage),
nameof(RegistryPreviewPage) => typeof(RegistryPreviewPage),
nameof(ShortcutGuidePage) => typeof(ShortcutGuidePage),
nameof(WorkspacesPage) => typeof(WorkspacesPage),
nameof(ZoomItPage) => typeof(ZoomItPage),
_ => null,
};
_pageTypeCache[pageTypeName] = type;
return type;
}

View File

@@ -301,7 +301,11 @@ namespace Microsoft.PowerToys.Settings.UI
});
#else
/* If we try to run Settings as a standalone app, it will start PowerToys.exe if not running and open Settings again through it in the Dashboard page. */
#if BUILD_INFO_PUBLISH_AOT
global::Microsoft.PowerToys.Settings.UI.Helpers.SettingsDeepLink.OpenSettings(global::Microsoft.PowerToys.Settings.UI.Helpers.SettingsDeepLink.SettingsWindow.Dashboard);
#else
global::Common.UI.SettingsDeepLink.OpenSettings(global::Common.UI.SettingsDeepLink.SettingsWindow.Dashboard);
#endif
Exit();
#endif
}

View File

@@ -9,7 +9,9 @@
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:Microsoft.PowerToys.Settings.UI.Library"
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
x:DataType="models:ColorFormatModel"
mc:Ignorable="d">
<UserControl.Resources>
<converters:ColorFormatConverter x:Key="ColorFormatConverter" />

View File

@@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Security.Cryptography;
using System.Windows.Input;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;

View File

@@ -2,6 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Services;
using Microsoft.PowerToys.Settings.UI.Views;
@@ -9,11 +11,36 @@ using Microsoft.UI.Xaml.Controls;
namespace Microsoft.PowerToys.Settings.UI.Controls
{
public sealed partial class CheckUpdateControl : UserControl
public sealed partial class CheckUpdateControl : UserControl, INotifyPropertyChanged
{
public bool UpdateAvailable { get; set; }
private bool _updateAvailable;
private UpdatingSettings _updateSettingsConfig;
public UpdatingSettings UpdateSettingsConfig { get; set; }
public bool UpdateAvailable
{
get => _updateAvailable;
set
{
if (_updateAvailable != value)
{
_updateAvailable = value;
OnPropertyChanged();
}
}
}
public UpdatingSettings UpdateSettingsConfig
{
get => _updateSettingsConfig;
set
{
if (_updateSettingsConfig != value)
{
_updateSettingsConfig = value;
OnPropertyChanged();
}
}
}
public CheckUpdateControl()
{
@@ -26,5 +53,12 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
{
NavigationService.Navigate(typeof(GeneralPage));
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -113,10 +113,14 @@
x:Name="CachedModelsComboBox"
Grid.Column="0"
HorizontalAlignment="Stretch"
DisplayMemberPath="Name"
ItemsSource="{x:Bind CachedModels, Mode=OneWay}"
SelectedItem="{x:Bind SelectedModel, Mode=TwoWay}"
SelectionChanged="CachedModelsComboBox_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="models:ModelDetails">
<TextBlock Text="{x:Bind Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.Header>
<TextBlock>
<Run x:Uid="AdvancedPaste_FL_LocalModel" /><LineBreak /><Run

View File

@@ -137,8 +137,7 @@
x:Name="CopyStyleToCustom"
x:Uid="MouseUtils_MouseJump_CopyStyle"
Margin="20,0,0,0"
Click="CopyStyleToCustom_Click"
IsEnabled="{Binding SelectedIndex, ElementName=PreviewTypeSetting}" />
Click="CopyStyleToCustom_Click" />
</StackPanel>
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard x:Name="MouseUtils_MouseJump_BackgroundColor1" x:Uid="MouseUtils_MouseJump_BackgroundColor1">

View File

@@ -225,12 +225,11 @@
<tkcontrols:SettingsExpander
Name="PasteAsFile"
x:Uid="PasteAsFile"
DataContext="{x:Bind ViewModel.AdditionalActions.PasteAsFile, Mode=OneWay}"
HeaderIcon="{ui:FontIcon Glyph=&#xEC50;}"
IsExpanded="{Binding IsShown, Mode=OneWay}">
IsExpanded="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
<tkcontrols:SettingsExpander.Content>
<ToggleSwitch
IsOn="{Binding IsShown, Mode=TwoWay}"
IsOn="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=TwoWay}"
OffContent=""
OnContent="" />
</tkcontrols:SettingsExpander.Content>
@@ -240,21 +239,21 @@
<tkcontrols:SettingsCard
Name="PasteAsTxtFile"
x:Uid="PasteAsTxtFile"
DataContext="{Binding PasteAsTxtFile, Mode=TwoWay}"
DataContext="{x:Bind ViewModel.AdditionalActions.PasteAsFile.PasteAsTxtFile, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
Name="PasteAsPngFile"
x:Uid="PasteAsPngFile"
DataContext="{Binding PasteAsPngFile, Mode=TwoWay}"
DataContext="{x:Bind ViewModel.AdditionalActions.PasteAsFile.PasteAsPngFile, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
Name="PasteAsHtmlFile"
x:Uid="PasteAsHtmlFile"
DataContext="{Binding PasteAsHtmlFile, Mode=TwoWay}"
DataContext="{x:Bind ViewModel.AdditionalActions.PasteAsFile.PasteAsHtmlFile, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
@@ -265,12 +264,11 @@
<tkcontrols:SettingsExpander
Name="Transcode"
x:Uid="Transcode"
DataContext="{x:Bind ViewModel.AdditionalActions.Transcode, Mode=OneWay}"
HeaderIcon="{ui:FontIcon Glyph=&#xEA69;}"
IsExpanded="{Binding IsShown, Mode=OneWay}">
IsExpanded="{x:Bind ViewModel.AdditionalActions.Transcode.IsShown, Mode=OneWay}">
<tkcontrols:SettingsExpander.Content>
<ToggleSwitch
IsOn="{Binding IsShown, Mode=TwoWay}"
IsOn="{x:Bind ViewModel.AdditionalActions.Transcode.IsShown, Mode=TwoWay}"
OffContent=""
OnContent="" />
</tkcontrols:SettingsExpander.Content>
@@ -280,14 +278,14 @@
<tkcontrols:SettingsCard
Name="TranscodeToMp3"
x:Uid="TranscodeToMp3"
DataContext="{Binding TranscodeToMp3, Mode=TwoWay}"
DataContext="{x:Bind ViewModel.AdditionalActions.Transcode.TranscodeToMp3, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.Transcode.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
Name="TranscodeToMp4"
x:Uid="TranscodeToMp4"
DataContext="{Binding TranscodeToMp4, Mode=TwoWay}"
DataContext="{x:Bind ViewModel.AdditionalActions.Transcode.TranscodeToMp4, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.Transcode.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
@@ -400,6 +398,7 @@
x:Name="CustomActionDialog"
x:Uid="CustomActionDialog"
Closed="CustomActionDialog_Closed"
x:DataType="models:AdvancedPasteCustomAction"
IsPrimaryButtonEnabled="{Binding IsValid, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
IsSecondaryButtonEnabled="True"
PrimaryButtonStyle="{ThemeResource AccentButtonStyle}">

View File

@@ -10,7 +10,6 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using LanguageModelProvider;
using Microsoft.PowerToys.Settings.UI.Controls;
@@ -681,7 +680,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
await LoadFoundryLocalModelsAsync();
}
private sealed class FoundryDownloadableModel : INotifyPropertyChanged
private sealed partial class FoundryDownloadableModel : INotifyPropertyChanged
{
private readonly List<string> _deviceTags;
private double _progress;

View File

@@ -55,14 +55,14 @@
Glyph="&#xEC61;" />
<HyperlinkButton
x:Uid="CmdNotFound_UninstallButton"
Command="{x:Bind ViewModel.UninstallModuleEventHandler}"
Click="UninstallButton_Click"
IsEnabled="{x:Bind ViewModel.IsModuleGpoEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
</StackPanel>
</tkcontrols:Case>
<tkcontrols:Case Value="False">
<Button
x:Uid="CmdNotFound_InstallButton"
Command="{x:Bind ViewModel.InstallModuleEventHandler}"
Click="InstallButton_Click"
IsEnabled="{x:Bind ViewModel.IsModuleGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
Style="{StaticResource AccentButtonStyle}" />
</tkcontrols:Case>
@@ -76,7 +76,7 @@
IsClosable="False"
IsOpen="True">
<InfoBar.ActionButton>
<HyperlinkButton x:Uid="CmdNotFound_CheckCompatibility" Command="{x:Bind ViewModel.CheckRequirementsEventHandler}">
<HyperlinkButton x:Uid="CmdNotFound_CheckCompatibility" Click="CheckRequirementsButton_Click">
<ToolTipService.ToolTip>
<TextBlock x:Uid="CmdNotFound_CheckCompatibilityTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
@@ -112,7 +112,7 @@
Glyph="&#xEB90;" />
<Button
x:Uid="CmdNotFound_InstallButton"
Command="{x:Bind ViewModel.InstallPowerShell7EventHandler}"
Click="InstallPowerShell7Button_Click"
IsEnabled="{x:Bind ViewModel.IsModuleGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
</StackPanel>
</tkcontrols:Case>
@@ -145,7 +145,7 @@
Glyph="&#xEB90;" />
<Button
x:Uid="CmdNotFound_InstallButton"
Command="{x:Bind ViewModel.InstallWinGetClientModuleEventHandler}"
Click="InstallWinGetButton_Click"
IsEnabled="{x:Bind ViewModel.IsModuleGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
</StackPanel>
</tkcontrols:Case>

View File

@@ -18,5 +18,30 @@ namespace Microsoft.PowerToys.Settings.UI.Views
DataContext = ViewModel;
InitializeComponent();
}
private void UninstallButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
ViewModel.UninstallModuleEventHandler?.Execute(null);
}
private void InstallButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
ViewModel.InstallModuleEventHandler?.Execute(null);
}
private void CheckRequirementsButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
ViewModel.CheckRequirementsEventHandler?.Execute(null);
}
private void InstallPowerShell7Button_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
ViewModel.InstallPowerShell7EventHandler?.Execute(null);
}
private void InstallWinGetButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
ViewModel.InstallWinGetClientModuleEventHandler?.Execute(null);
}
}
}

View File

@@ -93,16 +93,23 @@
<ComboBox
x:Name="ColorPicker_ComboBox"
MinWidth="{StaticResource SettingActionControlMinWidth}"
DisplayMemberPath="Value"
ItemsSource="{Binding ColorFormatsPreview, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{x:Bind ViewModel.ColorFormats, Mode=OneWay}"
Loaded="ColorPicker_ComboBox_Loaded"
SelectedIndex="{Binding ColorFormatsPreviewIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding SelectedColorRepresentationValue, Mode=TwoWay}"
SelectedValuePath="Key" />
SelectedIndex="{x:Bind ViewModel.ColorFormatsPreviewIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="models:ColorFormatModel">
<TextBlock>
<Run Text="{x:Bind Name}" />
<Run Text=" - " />
<Run Text="{x:Bind Example}" />
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard Name="ColorPickerShowColorName" x:Uid="ColorPicker_ShowColorName">
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{Binding ShowColorName, Mode=TwoWay}" />
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.ShowColorName, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<!--
Disabling this until we have a safer way to reset cursor as
@@ -131,9 +138,9 @@
<ItemsControl
x:Name="ColorFormats"
HorizontalAlignment="Stretch"
AutomationProperties.Name="{Binding ElementName=ColorFormatsSetting, Path=Header}"
AutomationProperties.Name="{x:Bind ColorFormatsSetting.Header, Mode=OneWay}"
IsTabStop="False"
ItemsSource="{Binding ColorFormats, Mode=TwoWay}">
ItemsSource="{x:Bind ViewModel.ColorFormats, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:ColorFormatModel">
<tkcontrols:SettingsCard
@@ -196,7 +203,9 @@
x:Name="ColorFormatDialog"
x:Uid="ColorFormatDialog"
Closed="ColorFormatDialog_Closed"
x:DataType="models:ColorFormatModel"
IsPrimaryButtonEnabled="{Binding IsValid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PrimaryButtonClick="ColorFormatDialog_PrimaryButtonClick"
PrimaryButtonStyle="{ThemeResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:ColorFormatModel />
@@ -220,4 +229,4 @@
<controls:PageLink Link="https://medium.com/@Niels9001/a-fluent-color-meter-for-powertoys-20407ededf0c" Text="Niels Laute's UX concept" />
</controls:SettingsPageControl.SecondaryLinks>
</controls:SettingsPageControl>
</local:NavigablePage>
</local:NavigablePage>

View File

@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Windows.Input;
using CommunityToolkit.WinUI.Controls;
using Microsoft.PowerToys.Settings.UI.Helpers;
@@ -25,6 +24,15 @@ namespace Microsoft.PowerToys.Settings.UI.Views
private ResourceLoader resourceLoader = ResourceLoaderInstance.ResourceLoader;
private enum DialogActionMode
{
None,
Add,
Update,
}
private DialogActionMode _dialogActionMode = DialogActionMode.None;
public ColorPickerPage()
{
var settingsUtils = SettingsUtils.Default;
@@ -129,7 +137,9 @@ namespace Microsoft.PowerToys.Settings.UI.Views
ColorFormatDialog.Tag = string.Empty;
ColorFormatDialog.PrimaryButtonText = resourceLoader.GetString("ColorFormatSave");
ColorFormatDialog.PrimaryButtonCommand = AddCommand;
// Use Click event instead of Command for AOT compatibility
_dialogActionMode = DialogActionMode.Add;
await ColorFormatDialog.ShowAsync();
}
@@ -142,7 +152,9 @@ namespace Microsoft.PowerToys.Settings.UI.Views
ColorFormatDialog.Tag = new KeyValuePair<string, string>(colorFormatModel.Name, colorFormatModel.Format);
ColorFormatDialog.PrimaryButtonText = resourceLoader.GetString("ColorFormatUpdate");
ColorFormatDialog.PrimaryButtonCommand = UpdateCommand;
// Use Click event instead of Command for AOT compatibility
_dialogActionMode = DialogActionMode.Update;
await ColorFormatDialog.ShowAsync();
}
@@ -156,6 +168,18 @@ namespace Microsoft.PowerToys.Settings.UI.Views
ViewModel.RefreshEnabledState();
}
private void ColorFormatDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
if (_dialogActionMode == DialogActionMode.Add)
{
Add();
}
else if (_dialogActionMode == DialogActionMode.Update)
{
Update();
}
}
private void ColorFormatDialog_Closed(ContentDialog sender, ContentDialogClosedEventArgs args)
{
if (args.Result != ContentDialogResult.Primary && ColorFormatDialog.Tag is KeyValuePair<string, string>)

View File

@@ -29,9 +29,7 @@
x:Name="ValueComboBox"
x:Uid="PowerDisplay_CustomMappingEditor_ValueComboBox"
HorizontalAlignment="Stretch"
DisplayMemberPath="DisplayName"
ItemsSource="{x:Bind AvailableValues, Mode=OneWay}"
SelectedValuePath="Value"
SelectionChanged="ValueComboBox_SelectionChanged" />
<!-- Custom Value Input (shown when "Custom value" is selected) -->
@@ -65,9 +63,7 @@
x:Name="MonitorComboBox"
x:Uid="PowerDisplay_CustomMappingEditor_SelectMonitor"
HorizontalAlignment="Stretch"
DisplayMemberPath="DisplayName"
ItemsSource="{x:Bind AvailableMonitors, Mode=OneWay}"
SelectedValuePath="Id"
SelectionChanged="MonitorComboBox_SelectionChanged"
Visibility="{x:Bind ShowMonitorSelector, Mode=OneWay}" />
</StackPanel>

View File

@@ -40,6 +40,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
public string DisplayName { get; set; } = string.Empty;
public bool IsCustomOption => Value == CustomValueMarker;
public override string ToString() => DisplayName;
}
/// <summary>
@@ -50,6 +52,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
public string Id { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public override string ToString() => DisplayName;
}
private readonly IEnumerable<MonitorInfo>? _monitors;

View File

@@ -26,7 +26,7 @@
Name="EnvironmentVariablesLaunchButtonControl"
x:Uid="EnvironmentVariables_LaunchButtonControl"
ActionIcon="{ui:FontIcon Glyph=&#xE8A7;}"
Command="{x:Bind ViewModel.LaunchEventHandler}"
Click="LaunchButton_Click"
HeaderIcon="{ui:FontIcon Glyph=&#xEA37;}"
IsClickEnabled="True" />
<tkcontrols:SettingsCard

View File

@@ -24,5 +24,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{
ViewModel.RefreshEnabledState();
}
private void LaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
ViewModel.LaunchEventHandler?.Execute(null);
}
}
}

View File

@@ -32,7 +32,7 @@
x:Uid="FancyZones_LaunchEditorButtonControl"
ActionIcon="{ui:FontIcon Glyph=&#xE8A7;}"
AutomationProperties.AutomationId="LaunchLayoutEditorButton"
Command="{x:Bind ViewModel.LaunchEditorEventHandler}"
Click="LaunchEditorButton_Click"
HeaderIcon="{ui:FontIcon Glyph=&#xEB3C;}"
IsClickEnabled="True" />

View File

@@ -31,5 +31,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{
ViewModel.RefreshEnabledState();
}
private void LaunchEditorButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
ViewModel.LaunchEditorEventHandler?.Execute(null);
}
}
}

View File

@@ -7,6 +7,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:Microsoft.PowerToys.Settings.UI.Library"
xmlns:ptcontrols="using:Microsoft.PowerToys.Common.UI.Controls"
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
xmlns:ui="using:CommunityToolkit.WinUI"
@@ -52,9 +53,9 @@
<Button
x:Uid="GeneralPage_CheckForUpdates"
HorizontalAlignment="Right"
Command="{Binding CheckForUpdatesEventHandler}"
IsEnabled="{Binding IsDownloadAllowed}"
Visibility="{Binding Mode=OneWay, Path=IsNewVersionDownloading, Converter={StaticResource BoolNegationConverter}}" />
Command="{x:Bind ViewModel.CheckForUpdatesEventHandler, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.IsDownloadAllowed, Mode=OneWay}"
Visibility="{x:Bind ViewModel.IsNewVersionDownloading, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
</Grid>
<tkcontrols:SettingsExpander.ItemsHeader>
<InfoBar
@@ -116,9 +117,9 @@
<Button
x:Uid="General_DownloadAndInstall"
Margin="0,0,0,16"
Command="{Binding UpdateNowButtonEventHandler}"
IsEnabled="{Binding IsDownloadAllowed}"
Visibility="{Binding Mode=OneWay, Path=IsNewVersionDownloading, Converter={StaticResource BoolNegationConverter}}" />
Command="{x:Bind ViewModel.UpdateNowButtonEventHandler, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.IsDownloadAllowed, Mode=OneWay}"
Visibility="{x:Bind ViewModel.IsNewVersionDownloading, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
<!-- In progress panel -->
<StackPanel
@@ -138,7 +139,7 @@
<HyperlinkButton
x:Uid="SeeWhatsNew"
HorizontalAlignment="Right"
NavigateUri="{Binding PowerToysNewAvailableVersionLink, Mode=OneWay}"
NavigateUri="{x:Bind ViewModel.PowerToysNewAvailableVersionUri, Mode=OneWay}"
Style="{StaticResource TextButtonStyle}" />
</InfoBar.ActionButton>
</InfoBar>
@@ -155,14 +156,14 @@
<Button
x:Uid="General_InstallNow"
Margin="0,0,0,16"
Command="{Binding UpdateNowButtonEventHandler}"
IsEnabled="{Binding IsDownloadAllowed}" />
Command="{x:Bind ViewModel.UpdateNowButtonEventHandler, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.IsDownloadAllowed, Mode=OneWay}" />
</InfoBar.Content>
<InfoBar.ActionButton>
<HyperlinkButton
x:Uid="SeeWhatsNew"
HorizontalAlignment="Right"
NavigateUri="{Binding PowerToysNewAvailableVersionLink, Mode=OneWay}"
NavigateUri="{x:Bind ViewModel.PowerToysNewAvailableVersionUri, Mode=OneWay}"
Style="{StaticResource TextButtonStyle}" />
</InfoBar.ActionButton>
</InfoBar>
@@ -179,9 +180,9 @@
<StackPanel Spacing="16">
<Button
x:Uid="General_TryAgainToDownloadAndInstall"
Command="{Binding UpdateNowButtonEventHandler}"
IsEnabled="{Binding IsDownloadAllowed}"
Visibility="{Binding Mode=OneWay, Path=IsNewVersionDownloading, Converter={StaticResource BoolNegationConverter}}" />
Command="{x:Bind ViewModel.UpdateNowButtonEventHandler, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.IsDownloadAllowed, Mode=OneWay}"
Visibility="{x:Bind ViewModel.IsNewVersionDownloading, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
<!-- In progress panel -->
<StackPanel
@@ -201,7 +202,7 @@
<HyperlinkButton
x:Uid="SeeWhatsNew"
HorizontalAlignment="Right"
NavigateUri="{Binding PowerToysNewAvailableVersionLink, Mode=OneWay}"
NavigateUri="{x:Bind ViewModel.PowerToysNewAvailableVersionUri, Mode=OneWay}"
Style="{StaticResource TextButtonStyle}" />
</InfoBar.ActionButton>
</InfoBar>
@@ -220,8 +221,8 @@
</tkcontrols:SettingsExpander.Description>
<Button
x:Uid="GeneralPage_RestartAsAdmin_Button"
Command="{Binding RestartElevatedButtonEventHandler}"
IsEnabled="{Binding IsAdminButtonEnabled}" />
Command="{x:Bind ViewModel.RestartElevatedButtonEventHandler, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.IsAdminButtonEnabled, Mode=OneWay}" />
<tkcontrols:SettingsExpander.Items>
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind ViewModel.IsElevated, Mode=OneWay}">
<ptcontrols:CheckBoxWithDescriptionControl x:Uid="GeneralSettings_AlwaysRunAsAdminText" IsChecked="{x:Bind ViewModel.RunElevated, Mode=TwoWay}" />
@@ -241,10 +242,15 @@
<ComboBox
x:Name="Languages_ComboBox"
MinWidth="{StaticResource SettingActionControlMinWidth}"
AutomationProperties.Name="{Binding ElementName=LanguageHeader, Path=Header}"
DisplayMemberPath="Language"
ItemsSource="{Binding Languages, Mode=TwoWay}"
SelectedIndex="{Binding LanguagesIndex, Mode=TwoWay}" />
AutomationProperties.Name="{x:Bind LanguageHeader.Header, Mode=OneWay}"
ItemsSource="{x:Bind ViewModel.Languages, Mode=OneWay}"
SelectedIndex="{x:Bind ViewModel.LanguagesIndex, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="models:LanguageModel">
<TextBlock Text="{x:Bind Language}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</tkcontrols:SettingsCard>
<InfoBar
x:Uid="LanguageRestartInfo"
@@ -330,8 +336,8 @@
x:Uid="General_SettingsBackupAndRestore"
HeaderIcon="{ui:FontIcon Glyph=&#xE777;}">
<StackPanel Orientation="Horizontal" Spacing="8">
<Button x:Uid="General_SettingsBackupAndRestore_ButtonBackup" Command="{Binding BackupConfigsEventHandler}" />
<Button x:Uid="General_SettingsBackupAndRestore_ButtonRestore" Command="{Binding RestoreConfigsEventHandler}" />
<Button x:Uid="General_SettingsBackupAndRestore_ButtonBackup" Command="{x:Bind ViewModel.BackupConfigsEventHandler, Mode=OneWay}" />
<Button x:Uid="General_SettingsBackupAndRestore_ButtonRestore" Command="{x:Bind ViewModel.RestoreConfigsEventHandler, Mode=OneWay}" />
</StackPanel>
<tkcontrols:SettingsExpander.Items>
<tkcontrols:SettingsCard Name="GeneralSettingsBackupAndRestoreLocationText" x:Uid="General_SettingsBackupAndRestoreLocationText">
@@ -348,17 +354,17 @@
Text="{x:Bind ViewModel.SettingsBackupAndRestoreDir, Mode=TwoWay}"
TextWrapping="Wrap">
<ToolTipService.ToolTip>
<ToolTip IsEnabled="{Binding IsTextTrimmed, ElementName=pathTextBlock, Mode=OneWay}">
<ToolTip IsEnabled="{x:Bind pathTextBlock.IsTextTrimmed, Mode=OneWay}">
<TextBlock Text="{x:Bind ViewModel.SettingsBackupAndRestoreDir, Mode=TwoWay}" />
</ToolTip>
</ToolTipService.ToolTip>
</TextBlock>
<Button
x:Uid="General_SettingsBackupAndRestore_ButtonSelectFolder"
Grid.Column="1"
Command="{Binding SelectSettingBackupDirEventHandler}"
Content="&#xe8da;"
FontFamily="{ThemeResource SymbolThemeFontFamily}">
<Button
x:Uid="General_SettingsBackupAndRestore_ButtonSelectFolder"
Grid.Column="1"
Command="{x:Bind ViewModel.SelectSettingBackupDirEventHandler, Mode=OneWay}"
Content="&#xe8da;"
FontFamily="{ThemeResource SymbolThemeFontFamily}">
<ToolTipService.ToolTip>
<ToolTip>
<TextBlock x:Uid="General_SettingsBackupAndRestore_ButtonSelectLocation" />

Some files were not shown because too many files have changed in this diff Show More