diff --git a/src/Benchmarks/Benchmarks.Wasm/Benchmarks.Wasm.sln b/src/Benchmarks/Benchmarks.Wasm/Benchmarks.Wasm.sln
new file mode 100644
index 0000000..98583ec
--- /dev/null
+++ b/src/Benchmarks/Benchmarks.Wasm/Benchmarks.Wasm.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks.Wasm", "Benchmarks.Wasm.csproj", "{C139918E-4E50-FEAE-94DB-E16E9D622EA5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C139918E-4E50-FEAE-94DB-E16E9D622EA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C139918E-4E50-FEAE-94DB-E16E9D622EA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C139918E-4E50-FEAE-94DB-E16E9D622EA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C139918E-4E50-FEAE-94DB-E16E9D622EA5}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DB80F2C1-3FAF-489D-B214-5E86D1F3712D}
+ EndGlobalSection
+EndGlobal
diff --git a/src/dopes/Uno-dotnet6/DopeTestUno/DopeTestUno.Skia.Gtk/DopeTestUno.Skia.Gtk.csproj b/src/dopes/Uno-dotnet6/DopeTestUno/DopeTestUno.Skia.Gtk/DopeTestUno.Skia.Gtk.csproj
index 04eb153..9d219be 100644
--- a/src/dopes/Uno-dotnet6/DopeTestUno/DopeTestUno.Skia.Gtk/DopeTestUno.Skia.Gtk.csproj
+++ b/src/dopes/Uno-dotnet6/DopeTestUno/DopeTestUno.Skia.Gtk/DopeTestUno.Skia.Gtk.csproj
@@ -12,7 +12,7 @@
-
+ are
diff --git a/src/dopesbench/.editorconfig b/src/dopesbench/.editorconfig
new file mode 100644
index 0000000..ee73562
--- /dev/null
+++ b/src/dopesbench/.editorconfig
@@ -0,0 +1,167 @@
+; This file is for unifying the coding style for different editors and IDEs.
+; More information at http://editorconfig.org
+
+# This file is the top-most EditorConfig file
+root = true
+
+##########################################
+# Common Settings
+##########################################
+
+[*]
+indent_style = space
+end_of_line = crlf
+trim_trailing_whitespace = true
+insert_final_newline = true
+charset = utf-8
+
+##########################################
+# File Extension Settings
+##########################################
+
+[*.{yml,yaml}]
+indent_size = 2
+
+[.vsconfig]
+indent_size = 2
+end_of_line = lf
+
+[*.sln]
+indent_style = tab
+indent_size = 2
+
+[*.{csproj,proj,projitems,shproj}]
+indent_size = 4
+
+[*.{json,slnf}]
+indent_size = 2
+end_of_line = lf
+
+[*.{props,targets}]
+indent_size = 4
+
+[*.xaml]
+indent_size = 4
+charset = utf-8-bom
+
+[*.xml]
+indent_size = 4
+end_of_line = lf
+
+[*.plist]
+indent_size = 4
+indent_style = tab
+end_of_line = lf
+
+[*.manifest]
+indent_size = 4
+
+[*.appxmanifest]
+indent_size = 4
+
+[*.{json,css,webmanifest}]
+indent_size = 2
+end_of_line = lf
+
+[web.config]
+indent_size = 4
+end_of_line = lf
+
+[*.sh]
+indent_size = 2
+end_of_line = lf
+
+[*.cs]
+# EOL should be normalized by Git. See https://github.com/dotnet/format/issues/1099
+end_of_line = unset
+
+# See https://github.com/dotnet/roslyn/issues/20356#issuecomment-310143926
+trim_trailing_whitespace = false
+
+tab_width = 4
+indent_size = 4
+
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+
+# Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_event = false:suggestion
+
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+
+csharp_indent_labels = one_less_than_current
+csharp_using_directive_placement = outside_namespace:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_prefer_braces = true:silent
+csharp_style_namespace_declarations = file_scoped:warning
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_primary_constructors = true:suggestion
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
diff --git a/src/dopesbench/.gitignore b/src/dopesbench/.gitignore
new file mode 100644
index 0000000..3860b21
--- /dev/null
+++ b/src/dopesbench/.gitignore
@@ -0,0 +1,412 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+[Aa][Rr][Mm]64[Ee][Cc]/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Approval Tests result files
+*.received.*
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.idb
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+# but not Directory.Build.rsp, as it configures directory-level build defaults
+!Directory.Build.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# 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
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# AWS SAM Build and Temporary Artifacts folder
+.aws-sam
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Single Target Config
+solution-config.props
+# Publish Profiles
+!**/Properties/PublishProfiles/*.pubxml
\ No newline at end of file
diff --git a/src/dopesbench/.run/Readme.md b/src/dopesbench/.run/Readme.md
new file mode 100644
index 0000000..6e72638
--- /dev/null
+++ b/src/dopesbench/.run/Readme.md
@@ -0,0 +1,3 @@
+# About the `.run` folder
+
+This folder is present to add support for the [Rider IDE](https://aka.platform.uno/rider-getstarted). You can remove this folder safely if you're not using Rider.
diff --git a/src/dopesbench/.run/dopesbench.run.xml b/src/dopesbench/.run/dopesbench.run.xml
new file mode 100644
index 0000000..4241677
--- /dev/null
+++ b/src/dopesbench/.run/dopesbench.run.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/.vscode/extensions.json b/src/dopesbench/.vscode/extensions.json
new file mode 100644
index 0000000..a63ad40
--- /dev/null
+++ b/src/dopesbench/.vscode/extensions.json
@@ -0,0 +1,5 @@
+{
+ "recommendations": [
+ "unoplatform.vscode"
+ ],
+}
diff --git a/src/dopesbench/.vscode/launch.json b/src/dopesbench/.vscode/launch.json
new file mode 100644
index 0000000..b8be34d
--- /dev/null
+++ b/src/dopesbench/.vscode/launch.json
@@ -0,0 +1,77 @@
+{
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Uno Platform Mobile Debug",
+ "type": "Uno",
+ "request": "launch",
+ // any Uno* task will do, this is simply to satisfy vscode requirement when a launch.json is present
+ "preLaunchTask": "Uno: android | Debug | android-x64"
+ },
+ {
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "name": "Uno Platform WebAssembly Debug (Chrome)",
+ "type": "chrome",
+ "request": "launch",
+ "url": "http://localhost:5000",
+ "webRoot": "${workspaceFolder}/dopesbench",
+ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
+ "timeout": 30000,
+ "preLaunchTask": "build-wasm",
+ "server": {
+ "runtimeExecutable": "dotnet",
+ "program": "run",
+ "args": ["--no-build","-f","net9.0-browserwasm","--launch-profile", "dopesbench (WebAssembly)"],
+ "outputCapture": "std",
+ "timeout": 30000,
+ "cwd": "${workspaceFolder}/dopesbench"
+ }
+ },
+ {
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "name": "Uno Platform WebAssembly Debug (Edge)",
+ "type": "msedge",
+ "request": "launch",
+ "url": "http://localhost:5000",
+ "webRoot": "${workspaceFolder}/dopesbench",
+ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
+ "timeout": 30000,
+ "preLaunchTask": "build-wasm",
+ "server": {
+ "runtimeExecutable": "dotnet",
+ "program": "run",
+ "args": ["--no-build","-f","net9.0-browserwasm","--launch-profile", "dopesbench (WebAssembly)"],
+ "outputCapture": "std",
+ "timeout": 30000,
+ "cwd": "${workspaceFolder}/dopesbench"
+ }
+ },
+ {
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "name": "Uno Platform Desktop Debug",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build-desktop",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/dopesbench/bin/Debug/net9.0-desktop/dopesbench.dll",
+ "args": [],
+ "launchSettingsProfile": "dopesbench (Desktop)",
+ "env": {
+ "DOTNET_MODIFIABLE_ASSEMBLIES": "debug"
+ },
+ "cwd": "${workspaceFolder}/dopesbench",
+ // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
+ ]
+}
diff --git a/src/dopesbench/.vscode/settings.json b/src/dopesbench/.vscode/settings.json
new file mode 100644
index 0000000..3405922
--- /dev/null
+++ b/src/dopesbench/.vscode/settings.json
@@ -0,0 +1,10 @@
+{
+ "explorer.fileNesting.enabled": true,
+ "explorer.fileNesting.expand": false,
+ "explorer.fileNesting.patterns": {
+ "*.xaml": "$(capture).xaml.cs"
+ },
+ "files.associations": {
+ "global.json": "jsonc"
+ }
+}
diff --git a/src/dopesbench/.vscode/tasks.json b/src/dopesbench/.vscode/tasks.json
new file mode 100644
index 0000000..ae90e9f
--- /dev/null
+++ b/src/dopesbench/.vscode/tasks.json
@@ -0,0 +1,57 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build-wasm",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/dopesbench/dopesbench.csproj",
+ "/property:GenerateFullPaths=true",
+ "/property:TargetFramework=net9.0-browserwasm",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish-wasm",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/dopesbench/dopesbench.csproj",
+ "/property:GenerateFullPaths=true",
+ "/property:TargetFramework=net9.0-browserwasm",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "build-desktop",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/dopesbench/dopesbench.csproj",
+ "/property:GenerateFullPaths=true",
+ "/property:TargetFramework=net9.0-desktop",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish-desktop",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/dopesbench/dopesbench.csproj",
+ "/property:GenerateFullPaths=true",
+ "/property:TargetFramework=net9.0-desktop",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
diff --git a/src/dopesbench/.vsconfig b/src/dopesbench/.vsconfig
new file mode 100644
index 0000000..f6ff391
--- /dev/null
+++ b/src/dopesbench/.vsconfig
@@ -0,0 +1,30 @@
+{
+ "version": "1.0",
+ "components": [
+ "Microsoft.VisualStudio.Component.CoreEditor",
+ "Microsoft.VisualStudio.Workload.CoreEditor",
+ "Microsoft.NetCore.Component.SDK",
+ "Microsoft.NetCore.Component.DevelopmentTools",
+ "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
+ "Microsoft.VisualStudio.Component.TextTemplating",
+ "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
+ "Microsoft.NetCore.Component.Web",
+ "Microsoft.VisualStudio.Component.IISExpress",
+ "Component.Microsoft.Web.LibraryManager",
+ "Microsoft.VisualStudio.ComponentGroup.Web",
+ "Microsoft.VisualStudio.Component.Web",
+ "Microsoft.VisualStudio.ComponentGroup.Web.Client",
+ "Microsoft.VisualStudio.Workload.NetWeb",
+ "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.TemplateEngine",
+ "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
+ "Microsoft.VisualStudio.Component.Debugger.JustInTime",
+ "Microsoft.VisualStudio.Workload.ManagedDesktop",
+ "Component.Xamarin.RemotedSimulator",
+ "Microsoft.VisualStudio.Component.MonoDebugger",
+ "Microsoft.VisualStudio.ComponentGroup.Maui.All",
+ "Component.Android.SDK34",
+ "Component.OpenJDK",
+ "Microsoft.VisualStudio.Workload.NetCrossPlat",
+ "Microsoft.VisualStudio.Workload.NetCoreTools"
+ ]
+}
diff --git a/src/dopesbench/Directory.Build.props b/src/dopesbench/Directory.Build.props
new file mode 100644
index 0000000..8daf569
--- /dev/null
+++ b/src/dopesbench/Directory.Build.props
@@ -0,0 +1,15 @@
+
+
+ enable
+ enable
+ true
+
+
+ $(NoWarn);NU1507;NETSDK1201;PRI257
+
+
diff --git a/src/dopesbench/Directory.Build.targets b/src/dopesbench/Directory.Build.targets
new file mode 100644
index 0000000..f75adf7
--- /dev/null
+++ b/src/dopesbench/Directory.Build.targets
@@ -0,0 +1,2 @@
+
+
diff --git a/src/dopesbench/Directory.Packages.props b/src/dopesbench/Directory.Packages.props
new file mode 100644
index 0000000..f366262
--- /dev/null
+++ b/src/dopesbench/Directory.Packages.props
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/dopesbench/dopesbench.sln b/src/dopesbench/dopesbench.sln
new file mode 100644
index 0000000..6775273
--- /dev/null
+++ b/src/dopesbench/dopesbench.sln
@@ -0,0 +1,90 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.2.32210.308
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dopesbench", "dopesbench\dopesbench.csproj", "{F1EDEBA3-4A34-4935-8218-8230A27DCB72}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BADA71DC-7FFD-4EDC-9F28-FB74AEADC713}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ .gitignore = .gitignore
+ .vsconfig = .vsconfig
+ Directory.Build.props = Directory.Build.props
+ Directory.Build.targets = Directory.Build.targets
+ Directory.Packages.props = Directory.Packages.props
+ global.json = global.json
+ EndProjectSection
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Benchmarks.Shared", "dopesbench\Benchmarks.Shared\Benchmarks.Shared.shproj", "{6279C845-92F8-4333-AB99-3D213163593C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|iPhone = Debug|iPhone
+ Debug|iPhoneSimulator = Debug|iPhoneSimulator
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|iPhone = Release|iPhone
+ Release|iPhoneSimulator = Release|iPhoneSimulator
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|ARM.Build.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|ARM.Deploy.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|ARM64.Deploy.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|x64.Build.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|x64.Deploy.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|x86.Build.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Debug|x86.Deploy.0 = Debug|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|ARM.ActiveCfg = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|ARM.Build.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|ARM.Deploy.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|ARM64.Build.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|ARM64.Deploy.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|iPhone.Build.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|iPhone.Deploy.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|x64.ActiveCfg = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|x64.Build.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|x64.Deploy.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|x86.ActiveCfg = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|x86.Build.0 = Release|Any CPU
+ {F1EDEBA3-4A34-4935-8218-8230A27DCB72}.Release|x86.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {55CBD133-33C2-4412-9634-A5983D990F39}
+ EndGlobalSection
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ dopesbench\Benchmarks.Shared\Benchmarks.Shared.projitems*{6279c845-92f8-4333-ab99-3d213163593c}*SharedItemsImports = 13
+ EndGlobalSection
+EndGlobal
diff --git a/src/dopesbench/dopesbench/App.xaml b/src/dopesbench/dopesbench/App.xaml
new file mode 100644
index 0000000..daffb58
--- /dev/null
+++ b/src/dopesbench/dopesbench/App.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/App.xaml.cs b/src/dopesbench/dopesbench/App.xaml.cs
new file mode 100644
index 0000000..0963a5d
--- /dev/null
+++ b/src/dopesbench/dopesbench/App.xaml.cs
@@ -0,0 +1,122 @@
+using System;
+using Microsoft.Extensions.Logging;
+using Uno.Resizetizer;
+
+namespace dopesbench;
+
+public partial class App : Application
+{
+ public static Window MainAppWindow { get; private set; }
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ protected Window? MainWindow { get; private set; }
+
+ protected override void OnLaunched(LaunchActivatedEventArgs args)
+ {
+ MainWindow = new Window();
+ MainAppWindow = MainWindow;
+#if DEBUG
+ MainWindow.UseStudio();
+#endif
+
+
+ if (MainWindow.Content is not Components.AppBar shell)
+ {
+ shell = new Components.AppBar();
+ MainWindow.Content = shell;
+ }
+
+ shell.Navigate(typeof(HomePage), args.Arguments);
+
+ MainWindow.SetWindowIcon();
+ // Ensure the current window is active
+ MainWindow.Activate();
+ }
+
+ ///
+ /// Invoked when Navigation to a certain page fails
+ ///
+ /// The Frame which failed navigation
+ /// Details about the navigation failure
+ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ throw new InvalidOperationException($"Failed to load {e.SourcePageType.FullName}: {e.Exception}");
+ }
+
+ ///
+ /// Configures global Uno Platform logging
+ ///
+ public static void InitializeLogging()
+ {
+#if DEBUG
+ // Logging is disabled by default for release builds, as it incurs a significant
+ // initialization cost from Microsoft.Extensions.Logging setup. If startup performance
+ // is a concern for your application, keep this disabled. If you're running on the web or
+ // desktop targets, you can use URL or command line parameters to enable it.
+ //
+ // For more performance documentation: https://platform.uno/docs/articles/Uno-UI-Performance.html
+
+ var factory = LoggerFactory.Create(builder =>
+ {
+#if __WASM__
+ builder.AddProvider(new global::Uno.Extensions.Logging.WebAssembly.WebAssemblyConsoleLoggerProvider());
+#elif __IOS__
+ builder.AddProvider(new global::Uno.Extensions.Logging.OSLogLoggerProvider());
+
+ // Log to the Visual Studio Debug console
+ builder.AddConsole();
+#else
+ builder.AddConsole();
+#endif
+
+ // Exclude logs below this level
+ builder.SetMinimumLevel(LogLevel.Information);
+
+ // Default filters for Uno Platform namespaces
+ builder.AddFilter("Uno", LogLevel.Warning);
+ builder.AddFilter("Windows", LogLevel.Warning);
+ builder.AddFilter("Microsoft", LogLevel.Warning);
+
+ // Generic Xaml events
+ // builder.AddFilter("Microsoft.UI.Xaml", LogLevel.Debug );
+ // builder.AddFilter("Microsoft.UI.Xaml.VisualStateGroup", LogLevel.Debug );
+ // builder.AddFilter("Microsoft.UI.Xaml.StateTriggerBase", LogLevel.Debug );
+ // builder.AddFilter("Microsoft.UI.Xaml.UIElement", LogLevel.Debug );
+ // builder.AddFilter("Microsoft.UI.Xaml.FrameworkElement", LogLevel.Trace );
+
+ // Layouter specific messages
+ // builder.AddFilter("Microsoft.UI.Xaml.Controls", LogLevel.Debug );
+ // builder.AddFilter("Microsoft.UI.Xaml.Controls.Layouter", LogLevel.Debug );
+ // builder.AddFilter("Microsoft.UI.Xaml.Controls.Panel", LogLevel.Debug );
+
+ // builder.AddFilter("Windows.Storage", LogLevel.Debug );
+
+ // Binding related messages
+ // builder.AddFilter("Microsoft.UI.Xaml.Data", LogLevel.Debug );
+ // builder.AddFilter("Microsoft.UI.Xaml.Data", LogLevel.Debug );
+
+ // Binder memory references tracking
+ // builder.AddFilter("Uno.UI.DataBinding.BinderReferenceHolder", LogLevel.Debug );
+
+ // DevServer and HotReload related
+ // builder.AddFilter("Uno.UI.RemoteControl", LogLevel.Information);
+
+ // Debug JS interop
+ // builder.AddFilter("Uno.Foundation.WebAssemblyRuntime", LogLevel.Debug );
+ });
+
+ global::Uno.Extensions.LogExtensionPoint.AmbientLoggerFactory = factory;
+
+#if HAS_UNO
+ global::Uno.UI.Adapter.Microsoft.Extensions.Logging.LoggingAdapter.Initialize();
+#endif
+#endif
+ }
+}
diff --git a/src/dopesbench/dopesbench/Assets/Icons/icon.svg b/src/dopesbench/dopesbench/Assets/Icons/icon.svg
new file mode 100644
index 0000000..a15af53
--- /dev/null
+++ b/src/dopesbench/dopesbench/Assets/Icons/icon.svg
@@ -0,0 +1,42 @@
+
+
diff --git a/src/dopesbench/dopesbench/Assets/Icons/icon_foreground.svg b/src/dopesbench/dopesbench/Assets/Icons/icon_foreground.svg
new file mode 100644
index 0000000..8ffc41a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Assets/Icons/icon_foreground.svg
@@ -0,0 +1,137 @@
+
+
diff --git a/src/dopesbench/dopesbench/Assets/SharedAssets.md b/src/dopesbench/dopesbench/Assets/SharedAssets.md
new file mode 100644
index 0000000..b1cc4e7
--- /dev/null
+++ b/src/dopesbench/dopesbench/Assets/SharedAssets.md
@@ -0,0 +1,32 @@
+# Shared Assets
+
+See documentation about assets here: https://github.com/unoplatform/uno/blob/master/doc/articles/features/working-with-assets.md
+
+## Here is a cheat sheet
+
+1. Add the image file to the `Assets` directory of a shared project.
+2. Set the build action to `Content`.
+3. (Recommended) Provide an asset for various scales/dpi
+
+### Examples
+
+```text
+\Assets\Images\logo.scale-100.png
+\Assets\Images\logo.scale-200.png
+\Assets\Images\logo.scale-400.png
+
+\Assets\Images\scale-100\logo.png
+\Assets\Images\scale-200\logo.png
+\Assets\Images\scale-400\logo.png
+```
+
+### Table of scales
+
+| Scale | WinUI | iOS | Android |
+|-------|:-----------:|:---------------:|:-------:|
+| `100` | scale-100 | @1x | mdpi |
+| `125` | scale-125 | N/A | N/A |
+| `150` | scale-150 | N/A | hdpi |
+| `200` | scale-200 | @2x | xhdpi |
+| `300` | scale-300 | @3x | xxhdpi |
+| `400` | scale-400 | N/A | xxxhdpi |
diff --git a/src/dopesbench/dopesbench/Assets/Splash/splash_screen.svg b/src/dopesbench/dopesbench/Assets/Splash/splash_screen.svg
new file mode 100644
index 0000000..8ffc41a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Assets/Splash/splash_screen.svg
@@ -0,0 +1,137 @@
+
+
diff --git a/src/dopesbench/dopesbench/Assets/wallpaper_uno.jpg b/src/dopesbench/dopesbench/Assets/wallpaper_uno.jpg
new file mode 100644
index 0000000..1c92f79
Binary files /dev/null and b/src/dopesbench/dopesbench/Assets/wallpaper_uno.jpg differ
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/App.xaml b/src/dopesbench/dopesbench/Benchmarks.Shared/App.xaml
new file mode 100644
index 0000000..13ea103
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/App.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/App.xaml.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/App.xaml.cs
new file mode 100644
index 0000000..eaf0c58
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/App.xaml.cs
@@ -0,0 +1,172 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Uno.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Uno.Foundation;
+using Windows.Foundation.Collections;
+using Uno.UI.Xaml;
+using Uno.UI.Xaml.Controls;
+using Uno.UI.Xaml.Input;
+using Uno.UI.Xaml.Media;
+
+namespace Benchmarks
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public sealed partial class App : Application
+ {
+ private Window _window;
+
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ InitializeLogging();
+
+ this.InitializeComponent();
+
+#if HAS_UNO || NETFX_CORE
+ this.Suspending += OnSuspending;
+#endif
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
+ {
+#if DEBUG
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // this.DebugSettings.EnableFrameRateCounter = true;
+ }
+#endif
+
+#if NET5_0 && WINDOWS
+ _window = new Window();
+ _window.Activate();
+#else
+
+#endif
+
+ var rootFrame = _window.Content as Frame;
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active
+ if (rootFrame == null)
+ {
+ // Create a Frame to act as the navigation context and navigate to the first page
+ rootFrame = new Frame();
+
+ rootFrame.NavigationFailed += OnNavigationFailed;
+
+ // Place the frame in the current Window
+ _window.Content = rootFrame;
+ }
+
+ // Remove the problematic PrelaunchActivated check
+ if (rootFrame.Content == null)
+ {
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter
+ rootFrame.Navigate(typeof(MainPage), args.Arguments);
+ }
+ // Ensure the current window is active
+ _window.Activate();
+ }
+
+ ///
+ /// Invoked when Navigation to a certain page fails
+ ///
+ /// The Frame which failed navigation
+ /// Details about the navigation failure
+ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ throw new InvalidOperationException($"Failed to load {e.SourcePageType.FullName}: {e.Exception}");
+ }
+
+ ///
+ /// Invoked when application execution is being suspended. Application state is saved
+ /// without knowing whether the application will be terminated or resumed with the contents
+ /// of memory still intact.
+ ///
+ /// The source of the suspend request.
+ /// Details about the suspend request.
+ private void OnSuspending(object sender, SuspendingEventArgs e)
+ {
+ var deferral = e.SuspendingOperation.GetDeferral();
+ // TODO: Save application state and stop any background activity
+ deferral.Complete();
+ }
+
+ ///
+ /// Configures global Uno Platform logging
+ ///
+ private static void InitializeLogging()
+ {
+ var factory = LoggerFactory.Create(builder =>
+ {
+#if __WASM__
+ builder.AddProvider(new global::Uno.Extensions.Logging.WebAssembly.WebAssemblyConsoleLoggerProvider());
+#elif __IOS__
+ builder.AddProvider(new global::Uno.Extensions.Logging.OSLogLoggerProvider());
+#elif NETFX_CORE
+ builder.AddDebug();
+#else
+ builder.AddConsole();
+#endif
+
+ // Exclude logs below this level
+ builder.SetMinimumLevel(LogLevel.Information);
+
+ // Default filters for Uno Platform namespaces
+ builder.AddFilter("Uno", LogLevel.Warning);
+ builder.AddFilter("Windows", LogLevel.Warning);
+ builder.AddFilter("Microsoft", LogLevel.Warning);
+
+ // Generic Xaml events
+ // builder.AddFilter("Windows.UI.Xaml", LogLevel.Debug );
+ // builder.AddFilter("Windows.UI.Xaml.VisualStateGroup", LogLevel.Debug );
+ // builder.AddFilter("Windows.UI.Xaml.StateTriggerBase", LogLevel.Debug );
+ // builder.AddFilter("Windows.UI.Xaml.UIElement", LogLevel.Debug );
+ // builder.AddFilter("Windows.UI.Xaml.FrameworkElement", LogLevel.Trace );
+
+ // Layouter specific messages
+ // builder.AddFilter("Windows.UI.Xaml.Controls", LogLevel.Debug );
+ // builder.AddFilter("Windows.UI.Xaml.Controls.Layouter", LogLevel.Debug );
+ // builder.AddFilter("Windows.UI.Xaml.Controls.Panel", LogLevel.Debug );
+
+ // builder.AddFilter("Windows.Storage", LogLevel.Debug );
+
+ // Binding related messages
+ // builder.AddFilter("Windows.UI.Xaml.Data", LogLevel.Debug );
+ // builder.AddFilter("Windows.UI.Xaml.Data", LogLevel.Debug );
+
+ // Binder memory references tracking
+ // builder.AddFilter("Uno.UI.DataBinding.BinderReferenceHolder", LogLevel.Debug );
+
+ // RemoteControl and HotReload related
+ // builder.AddFilter("Uno.UI.RemoteControl", LogLevel.Information);
+
+ // Debug JS interop
+ // builder.AddFilter("Uno.Foundation.WebAssemblyRuntime", LogLevel.Debug );
+ });
+
+ global::Uno.Extensions.LogExtensionPoint.AmbientLoggerFactory = factory;
+
+#if HAS_UNO
+ global::Uno.UI.Adapter.Microsoft.Extensions.Logging.LoggingAdapter.Initialize();
+#endif
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Assets/SharedAssets.md b/src/dopesbench/dopesbench/Benchmarks.Shared/Assets/SharedAssets.md
new file mode 100644
index 0000000..6d84997
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Assets/SharedAssets.md
@@ -0,0 +1,34 @@
+See documentation about assets here : https://github.com/unoplatform/uno/blob/master/doc/articles/features/working-with-assets.md
+
+# Here is a cheat sheet:
+
+1. Add the image file to the `Assets` directory of a shared project.
+2. Set the build action to `Content`.
+3. (Recommended) Provide an asset for various scales/dpi
+
+## Examples
+
+```
+\Assets\Images\logo.scale-100.png
+\Assets\Images\logo.scale-200.png
+\Assets\Images\logo.scale-400.png
+
+\Assets\Images\scale-100\logo.png
+\Assets\Images\scale-200\logo.png
+\Assets\Images\scale-400\logo.png
+```
+
+## Table of scales
+
+| Scale | UWP | iOS | Android |
+|-------|:-----------:|:--------:|:-------:|
+| `100` | scale-100 | @1x | mdpi |
+| `125` | scale-125 | N/A | N/A |
+| `150` | scale-150 | N/A | hdpi |
+| `200` | scale-200 | @2x | xhdpi |
+| `300` | scale-300 | @3x | xxhdpi |
+| `400` | scale-400 | N/A | xxxhdpi |
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarking/IAsyncUIBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarking/IAsyncUIBenchmark.cs
new file mode 100644
index 0000000..5cca154
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarking/IAsyncUIBenchmark.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace Benchmarks.Shared.Benchmarking
+{
+ internal interface IAsyncUIBenchmark
+ {
+ Task BenchmarkAsync();
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarking/IAsyncUIBenchmarkSetup.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarking/IAsyncUIBenchmarkSetup.cs
new file mode 100644
index 0000000..f3b1ecd
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarking/IAsyncUIBenchmarkSetup.cs
@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+
+namespace Benchmarks.Shared.Benchmarking
+{
+ internal interface IAsyncUIBenchmarkSetup
+ {
+ Task SetupAsync();
+ Task TeardownAsync();
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarks.Shared.projitems b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarks.Shared.projitems
new file mode 100644
index 0000000..f0f0f2a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarks.Shared.projitems
@@ -0,0 +1,63 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ 6279c845-92f8-4333-ab99-3d213163593c
+
+
+ Benchmarks
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+ App.xaml
+
+
+ MainPage.xaml
+
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+
+
+
+
+
+
+
+ <_Globbled_Page Include="$(MSBuildThisFileDirectory)**/*.xaml" Exclude="@(Page);@(ApplicationDefinition)">
+ Designer
+ MSBuild:Compile
+
+
+
+ <_Globbed_Compile Include="$(MSBuildThisFileDirectory)**/*.xaml.cs" Exclude="@(Compile)">
+ %(Filename)
+
+ <_Globbed_Compile Include="$(MSBuildThisFileDirectory)**/*.cs" Exclude="@(Compile);@(_Globbed_Compile)" />
+
+
+ <_Globbed_PRIResource Include="$(MSBuildThisFileDirectory)**/*.resw" Exclude="@(PRIResource)" />
+
+
+ <_Globbed_Content Include="$(MSBuildThisFileDirectory)Assets/**/*.*" Exclude="@(Content)" />
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarks.Shared.shproj b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarks.Shared.shproj
new file mode 100644
index 0000000..fbfc375
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Benchmarks.Shared.shproj
@@ -0,0 +1,13 @@
+
+
+
+ 6279c845-92f8-4333-ab99-3d213163593c
+ 14.0
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkControl.xaml b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkControl.xaml
new file mode 100644
index 0000000..c4a1c04
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkControl.xaml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkControl.xaml.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkControl.xaml.cs
new file mode 100644
index 0000000..28ef580
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkControl.xaml.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using Windows.UI.Core;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Documents;
+
+using Benchmarks.Shared.Benchmarking;
+
+namespace Benchmarks.Shared.Controls
+{
+ public sealed partial class AsyncUIBenchmarkControl : UserControl
+ {
+ public AsyncUIBenchmarkControl()
+ {
+ InitializeComponent();
+ }
+
+ private void RunBenchmarks_Click(object sender, RoutedEventArgs e)
+ {
+ _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => await RunBenchmarks());
+ }
+
+ private IEnumerable EnumerateBenchmarks() =>
+ GetType()
+ .Assembly
+ .GetTypes()
+ .Where(t => !t.IsGenericType && t.GetInterfaces().Contains(typeof(IAsyncUIBenchmark)));
+
+ private async Task RunBenchmarks()
+ {
+ try
+ {
+ AsyncUIBenchmarkHost.Root = FindName("UIHost") as ContentControl;
+
+ Status.Text = "Running...";
+
+ foreach (var benchmark in EnumerateBenchmarks())
+ {
+ var times = new List();
+
+ for (int x = 0; x < 10; x++)
+ {
+ var instance = (IAsyncUIBenchmark)Activator.CreateInstance(benchmark);
+ var setupTeardown = instance as IAsyncUIBenchmarkSetup;
+
+ await (setupTeardown?.SetupAsync() ?? Task.CompletedTask);
+
+ var sw = Stopwatch.StartNew();
+ await instance.BenchmarkAsync();
+ sw.Stop();
+
+ await (setupTeardown?.TeardownAsync() ?? Task.CompletedTask);
+
+ GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
+
+ times.Add(sw.ElapsedTicks);
+ }
+
+ WriteLog($"{benchmark.FullName}: Min {times.Min()} / Max {times.Max()} / Avg {times.Average()}");
+ }
+
+ Status.Text = "Finished.";
+ }
+ catch (Exception exception)
+ {
+ WriteLog(exception.ToString());
+
+ Status.Text = "Failed.";
+ }
+ finally
+ {
+ AsyncUIBenchmarkHost.Root = null;
+ }
+ }
+
+ private void WriteLog(string message)
+ {
+ Log.Inlines.Add(new Run() { Text = message });
+ Log.Inlines.Add(new LineBreak());
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkHost.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkHost.cs
new file mode 100644
index 0000000..dcf1a5a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/AsyncUIBenchmarkHost.cs
@@ -0,0 +1,9 @@
+using Microsoft.UI.Xaml.Controls;
+
+namespace Benchmarks.Shared.Controls
+{
+ internal class AsyncUIBenchmarkHost
+ {
+ public static ContentControl Root { get; set; }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkDotNetControl.xaml b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkDotNetControl.xaml
new file mode 100644
index 0000000..5612b4a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkDotNetControl.xaml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkDotNetControl.xaml.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkDotNetControl.xaml.cs
new file mode 100644
index 0000000..364becb
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkDotNetControl.xaml.cs
@@ -0,0 +1,314 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Exporters;
+using BenchmarkDotNet.Exporters.Csv;
+using BenchmarkDotNet.Exporters.Json;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Loggers;
+using BenchmarkDotNet.Running;
+using BenchmarkDotNet.Toolchains.InProcess;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.Storage;
+using Windows.Storage.Pickers;
+using Windows.Storage.Provider;
+using Windows.UI;
+using Windows.UI.Core;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Documents;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using Microsoft.UI;
+using Perfolizer.Horology;
+using BenchmarkDotNet.Toolchains.InProcess.NoEmit;
+using BenchmarkDotNet.Toolchains;
+using BenchmarkDotNet.Toolchains.Results;
+using BenchmarkDotNet.Validators;
+using BenchmarkDotNet.Characteristics;
+
+namespace Benchmarks.Shared.Controls
+{
+ public sealed partial class BenchmarkDotNetControl : UserControl
+ {
+ private const string BenchmarksBaseNamespace = "SamplesApp.Benchmarks.Suite";
+ private TextBlockLogger _logger;
+
+ public BenchmarkDotNetControl()
+ {
+ this.InitializeComponent();
+ }
+
+ public string ResultsAsBase64
+ {
+ get => (string)GetValue(ResultsAsBase64Property);
+ set => SetValue(ResultsAsBase64Property, value);
+ }
+
+ public static readonly DependencyProperty ResultsAsBase64Property =
+ DependencyProperty.Register("ResultsAsBase64", typeof(string), typeof(BenchmarkDotNetControl), new PropertyMetadata(""));
+
+ public string ClassFilter { get; set; } = "";
+
+ private void OnRunTests(object sender, object args)
+ {
+ _ = Dispatcher.RunAsync(
+ CoreDispatcherPriority.Normal,
+ async () => await Run()
+ );
+ }
+
+ private async Task Run()
+ {
+ _logger = new TextBlockLogger(runLogs, debugLog.IsChecked ?? false);
+
+ try
+ {
+ var config = new CoreConfig(_logger as BenchmarkDotNet.Loggers.ILogger);
+
+ BenchmarkUIHost.Root = FindName("testHost") as ContentControl;
+
+ await SetStatus("Discovering benchmarks in " + BenchmarksBaseNamespace);
+ var types = EnumerateBenchmarks(config).ToArray();
+
+ int currentCount = 0;
+ foreach (var type in types)
+ {
+ runCount.Text = (++currentCount).ToString();
+
+ await SetStatus($"Running benchmarks for {type}");
+ var b = BenchmarkRunner.Run(type, config);
+
+ for (int i = 0; i < 3; i++)
+ {
+ await Dispatcher.RunIdleAsync(_ =>
+ {
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ });
+ }
+ }
+
+ await SetStatus($"Finished");
+
+ ArchiveTestResult(config);
+ }
+ catch (Exception e)
+ {
+ await SetStatus($"Failed {e?.Message}");
+ _logger.WriteLine(LogKind.Error, e?.ToString());
+ }
+ finally
+ {
+ BenchmarkUIHost.Root = null;
+ }
+ }
+
+
+ private void ArchiveTestResult(CoreConfig config)
+ {
+ var archiveName = BenchmarkResultArchiveName;
+
+ if (File.Exists(archiveName))
+ {
+ File.Delete(archiveName);
+ }
+
+ ZipFile.CreateFromDirectory(config.ArtifactsPath, archiveName, CompressionLevel.Optimal, false);
+
+ downloadResults.IsEnabled = true;
+
+ ResultsAsBase64 = Convert.ToBase64String(File.ReadAllBytes(BenchmarkResultArchiveName));
+ }
+
+ private static string BenchmarkResultArchiveName
+ => Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "benchmarks-results.zip");
+
+ private async void OnDownloadResults()
+ {
+ FileSavePicker savePicker = new FileSavePicker();
+
+ savePicker.SuggestedStartLocation = PickerLocationId.Desktop;
+
+ // Dropdown of file types the user can save the file as
+ savePicker.FileTypeChoices.Add("Zip Archive", new List() { ".zip" });
+
+ // Default file name if the user does not type one in or select a file to replace
+ savePicker.SuggestedFileName = "benchmarks-results";
+
+ var file = await savePicker.PickSaveFileAsync();
+ if (file != null)
+ {
+ CachedFileManager.DeferUpdates(file);
+
+ await FileIO.WriteBytesAsync(file, File.ReadAllBytes(BenchmarkResultArchiveName));
+
+ await CachedFileManager.CompleteUpdatesAsync(file);
+ }
+ }
+
+ private async Task SetStatus(string status)
+ {
+ runStatus.Text = status;
+ await Task.Yield();
+ }
+
+ private IEnumerable EnumerateBenchmarks(IConfig config)
+ => from type in GetType().GetTypeInfo().Assembly.GetTypes()
+ where !type.IsGenericType
+ where type.Namespace?.StartsWith(BenchmarksBaseNamespace) ?? false
+ where BenchmarkConverter.TypeToBenchmarks(type, config).BenchmarksCases.Length != 0
+ where string.IsNullOrEmpty(ClassFilter)
+ || type.Name.IndexOf(ClassFilter, StringComparison.InvariantCultureIgnoreCase) >= 0
+ select type;
+
+ /**
+ * We had to create this class, because ArtifactsPaths provided by IProcessNoEmitToolchain is null
+ */
+ public class MyToolChain : IToolchain
+ {
+ private static readonly IToolchain _toolChain = InProcessNoEmitToolchain.Instance;
+
+ public string Name => _toolChain.Name;
+
+ public IGenerator Generator => _toolChain.Generator;
+
+ public IBuilder Builder { get; } = new MyBuilder(_toolChain.Builder);
+
+ public IExecutor Executor => _toolChain.Executor;
+
+ public bool IsInProcess => _toolChain.IsInProcess;
+
+ public IEnumerable Validate(BenchmarkCase benchmarkCase, IResolver resolver)
+ {
+ return _toolChain.Validate(benchmarkCase, resolver);
+ }
+ }
+
+
+ public class MyBuilder(IBuilder builder) : IBuilder
+ {
+ public BuildResult Build(GenerateResult result, BuildPartition buildPartition, BenchmarkDotNet.Loggers.ILogger logger)
+ {
+ //var result = builder.Build(generateResult, buildPartition, logger);
+ var genResult = new GenerateResult(ArtifactsPaths.Empty, result.IsGenerateSuccess, result.GenerateException, result.ArtifactsToCleanup);
+
+ return BuildResult.Success(genResult);
+ }
+ }
+
+ public class CoreConfig : ManualConfig, IConfig
+ {
+ // Constructor with ILogger parameter
+ public CoreConfig(BenchmarkDotNet.Loggers.ILogger logger)
+ {
+ Add(logger);
+ Add(AsciiDocExporter.Default);
+ Add(JsonExporter.Full);
+ Add(CsvExporter.Default);
+ Add(BenchmarkDotNet.Exporters.Xml.XmlExporter.Full);
+
+ Add(Job.InProcess
+ .WithLaunchCount(1)
+ .WithWarmupCount(1)
+ .WithIterationCount(5)
+ .WithIterationTime(TimeInterval.FromMilliseconds(100))
+#if __IOS__
+ // Fails on iOS with code generation used by EmitInvokeMultiple
+ .WithUnrollFactor(1)
+#endif
+
+ .With(new MyToolChain())
+ .WithId("InProcess")
+ );
+
+ ArtifactsPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "benchmarks");
+ Logger = logger;
+ }
+
+ // Property to store ILogger instance
+ public BenchmarkDotNet.Loggers.ILogger Logger { get; }
+ }
+
+ private class TextBlockLogger : BenchmarkDotNet.Loggers.ILogger
+ {
+ private static Dictionary ColorfulScheme { get; } =
+ new Dictionary
+ {
+ { LogKind.Default, new SolidColorBrush(Colors.Gray) },
+ { LogKind.Help, new SolidColorBrush(Colors.DarkGreen) },
+ { LogKind.Header, new SolidColorBrush(Colors.Magenta) },
+ { LogKind.Result, new SolidColorBrush(Colors.DarkCyan) },
+ { LogKind.Statistic, new SolidColorBrush(Colors.Cyan) },
+ { LogKind.Info, new SolidColorBrush(Colors.DarkOrange) },
+ { LogKind.Error, new SolidColorBrush(Colors.Red) },
+ { LogKind.Hint, new SolidColorBrush(Colors.DarkCyan) }
+ };
+
+
+ private readonly TextBlock _target;
+ private LogKind _minLogKind;
+
+ public TextBlockLogger(TextBlock target, bool isDebug)
+ {
+ _target = target;
+ _minLogKind = isDebug ? LogKind.Default : LogKind.Statistic;
+ }
+
+ public void Flush() { }
+
+ public void Write(LogKind logKind, string text)
+ {
+ if (logKind >= _minLogKind)
+ {
+ _target.DispatcherQueue.TryEnqueue(() =>
+ {
+ _target.Inlines.Add(new Run { Text = text, Foreground = GetLogKindColor(logKind) });
+ });
+ }
+ }
+
+
+ public static Brush GetLogKindColor(LogKind logKind)
+ {
+ if (!ColorfulScheme.TryGetValue(logKind, out var brush))
+ {
+ brush = ColorfulScheme[LogKind.Default];
+ }
+
+ return brush;
+ }
+
+ public void WriteLine()
+ {
+ _target.DispatcherQueue.TryEnqueue(() =>
+ {
+ _target.Inlines.Add(new LineBreak());
+ });
+ }
+
+ public void WriteLine(LogKind logKind, string text)
+ {
+ if (logKind >= _minLogKind)
+ {
+ Write(logKind, text);
+ WriteLine();
+ }
+ }
+
+ public string Id => "TextBlockLogger";
+
+ public int Priority => 0;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkUIHost.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkUIHost.cs
new file mode 100644
index 0000000..39575a5
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Controls/BenchmarkUIHost.cs
@@ -0,0 +1,9 @@
+using Microsoft.UI.Xaml.Controls;
+
+namespace Benchmarks.Shared.Controls
+{
+ internal class BenchmarkUIHost
+ {
+ public static ContentControl Root { get; internal set; }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/MainPage.xaml b/src/dopesbench/dopesbench/Benchmarks.Shared/MainPage.xaml
new file mode 100644
index 0000000..87edc99
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/MainPage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/MainPage.xaml.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/MainPage.xaml.cs
new file mode 100644
index 0000000..08a860d
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/MainPage.xaml.cs
@@ -0,0 +1,33 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+using Benchmarks.Shared.Controls;
+
+namespace Benchmarks
+{
+ public sealed partial class MainPage : Page
+ {
+ private UserControl _benchmarkDotNetControl = new BenchmarkDotNetControl();
+ private UserControl _asyncUIBenchmarkControl = new AsyncUIBenchmarkControl();
+
+ public MainPage()
+ {
+ this.InitializeComponent();
+ }
+
+ private void HandleCheck(object sender, RoutedEventArgs e)
+ {
+ var type = ((RadioButton)sender).Content;
+
+ switch (type)
+ {
+ case "Async UI Benchmarks" :
+ BenchmarkControl.Content = _asyncUIBenchmarkControl;
+ break;
+ default :
+ BenchmarkControl.Content = _benchmarkDotNetControl;
+ break;
+ }
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Strings/en/Resources.resw b/src/dopesbench/dopesbench/Benchmarks.Shared/Strings/en/Resources.resw
new file mode 100644
index 0000000..366322d
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Strings/en/Resources.resw
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ $ext_safeprojectname$
+
+
\ No newline at end of file
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/SpanBench/SimpleSpanBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/SpanBench/SimpleSpanBenchmark.cs
new file mode 100644
index 0000000..6fe579c
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/SpanBench/SimpleSpanBenchmark.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+
+namespace SamplesApp.Benchmarks.Suite.SpanBench
+{
+ public class SpanTesting
+ {
+ [Params(10, 20)]
+ public int Items { get; set; }
+
+ [Benchmark(Baseline = true)]
+ public void EnumerableSum()
+ {
+ var r = Enumerable.Range(0, Items).ToArray();
+
+ var s = r.Sum();
+ }
+
+
+ [Benchmark()]
+ public void SpanSum()
+ {
+ var r = Enumerable.Range(0, Items).ToArray();
+
+ var s = ((Span)r).Sum();
+ }
+ }
+
+ public static class Extensions
+ {
+ public static double Sum(this Span span)
+ {
+ double result = 0;
+
+ foreach (var value in span)
+ {
+ result += value;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesCreationBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesCreationBenchmark.cs
new file mode 100644
index 0000000..099552a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesCreationBenchmark.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Microsoft.UI.Xaml.Controls;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml.ResourceDictionaryBench
+{
+ public class XamlControlsResourcesCreationBenchmark
+ {
+ [Benchmark]
+ public void Create_XamlControlsResources()
+ {
+ var xcr = new XamlControlsResources();
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesCreationRetrievalBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesCreationRetrievalBenchmark.cs
new file mode 100644
index 0000000..600be55
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesCreationRetrievalBenchmark.cs
@@ -0,0 +1,26 @@
+#pragma warning disable 105 // Disabled until the tree is migrate to WinUI
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml.ResourceDictionaryBench
+{
+ public class XamlControlsResourcesCreationRetrievalBenchmark
+ {
+ [Benchmark]
+ public void Create_XamlControlsResources_And_Retrieve_Style()
+ {
+ var xcr = new XamlControlsResources();
+
+ var style = xcr["ListViewItemExpanded"] as Style;
+ var templateSetter = style.Setters.OfType().First(s => s.Property == Control.TemplateProperty);
+ var template = templateSetter.Value;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesReadBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesReadBenchmark.cs
new file mode 100644
index 0000000..72cb6c2
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml/ResourceDictionaryBench/XamlControlsResourcesReadBenchmark.cs
@@ -0,0 +1,46 @@
+#pragma warning disable 105 // Disabled until the tree is migrate to WinUI
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml.ResourceDictionaryBench
+{
+ public class XamlControlsResourcesReadBenchmark
+ {
+ XamlControlsResources SUT;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ SUT = new XamlControlsResources();
+ if (!(SUT["ListViewItemExpanded"] is Style)) {
+ throw new InvalidOperationException($"ListViewItemExpanded does not exist");
+ }
+
+ }
+
+ [Benchmark]
+ public void ReadInvalidKey()
+ {
+ SUT.TryGetValue("InvalidKey", out var style);
+ }
+
+ [Benchmark]
+ public void ReadExistingKey()
+ {
+ SUT.TryGetValue("ListViewItemExpanded", out var style);
+ }
+
+ [Benchmark]
+ public void ReadExistingType()
+ {
+ SUT.TryGetValue(typeof(Frame), out var style);
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/BorderBench/BorderBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/BorderBench/BorderBenchmark.cs
new file mode 100644
index 0000000..76a7d6d
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/BorderBench/BorderBenchmark.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Windows.Foundation;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.BorderBench
+{
+ public class BorderBenchmark
+ {
+ private Border SUT;
+ private SolidColorBrush MyBrush;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ SUT = new Border();
+ MyBrush = new SolidColorBrush();
+ }
+
+ [Benchmark()]
+ public void Toggle_BorderBrush()
+ {
+ SUT.BorderBrush = MyBrush;
+ SUT.BorderBrush = null;
+ }
+
+ [Benchmark()]
+ public void Toggle_Style()
+ {
+ SUT.Style = new Microsoft.UI.Xaml.Style();
+ SUT.ClearValue(Border.StyleProperty);
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/PropagationDPBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/PropagationDPBenchmark.cs
new file mode 100644
index 0000000..af7a9ee
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/PropagationDPBenchmark.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Benchmarks.Shared.Controls;
+using Windows.Foundation;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.DependencyPropertyBench
+{
+ public class PropagationDPBenchmark
+ {
+ private ContentControl SUT;
+ private int _updateCount;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ SUT = new ContentControl();
+ SUT.Content = new ContentControl();
+
+ BenchmarkUIHost.Root.Content = SUT;
+ }
+
+ [Benchmark()]
+ public void UpdateInheritedProperty()
+ {
+ SUT.FontSize = (_updateCount++ % 2) == 0 ? 21 : 42;
+ }
+
+ [Benchmark()]
+ public void UpdateNonInheritedProperty()
+ {
+ SUT.Tag = (_updateCount++ % 2) == 0 ? 21 : 42;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/SimpleDPBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/SimpleDPBenchmark.cs
new file mode 100644
index 0000000..e58742a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/SimpleDPBenchmark.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Windows.Foundation;
+using Uno.UI.Xaml.Controls;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.GridBench
+{
+ public class SimpleDPBenchmark
+ {
+ private Grid SUT;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ SUT = new Grid();
+ }
+
+ [Benchmark()]
+ public void DP_Write()
+ {
+ for (int i = 0; i < 100; i++)
+ {
+ SUT.Width = i;
+ }
+ }
+
+ [Benchmark()]
+ public void DP_Read()
+ {
+ for (int i = 0; i < 100; i++)
+ {
+ var r = SUT.Width;
+ }
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/SpecializedDPBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/SpecializedDPBenchmark.cs
new file mode 100644
index 0000000..f322571
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/DependencyPropertyBench/SpecializedDPBenchmark.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Microsoft.Foundation;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.DependencyPropertyBench
+{
+ public class SpecializedDPBenchmark
+ {
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ }
+
+ [Benchmark()]
+ public void Property_GetMetadataNotSelf()
+ {
+ Border.TagProperty.GetMetadata(typeof(Border));
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/FrameworkElementBench/FrameworkElementBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/FrameworkElementBench/FrameworkElementBenchmark.cs
new file mode 100644
index 0000000..2ba90d0
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/FrameworkElementBench/FrameworkElementBenchmark.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Windows.Foundation;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.FrameworkElementBench
+{
+ public class FrameworkElementBenchmark
+ {
+ private Border SUT;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ SUT = new Border();
+ }
+
+ [Benchmark()]
+ public void Toggle_Style()
+ {
+ SUT.Style = new Microsoft.UI.Xaml.Style();
+ SUT.ClearValue(Border.StyleProperty);
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/GridBench/SimpleGridBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/GridBench/SimpleGridBenchmark.cs
new file mode 100644
index 0000000..1903164
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/GridBench/SimpleGridBenchmark.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Linq;
+using BenchmarkDotNet.Attributes;
+using Windows.Foundation;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using BenchmarkDotNet.Engines;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.GridBench
+{
+ public class SimpleGridBenchmark
+ {
+ private Grid _sut;
+
+ [Params(0, 1, 5)]
+ public int ItemsCount { get; set; }
+
+ [IterationSetup]
+ public void Setup()
+ {
+ _sut = new Grid();
+
+ for (var i = 0; i < ItemsCount; i++)
+ {
+ _sut.Children.Add(new Border { Width = 10, Height = 10 });
+ }
+ }
+
+ [IterationCleanup]
+ public void Cleanup()
+ {
+ _sut = null;
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
+
+ [Benchmark(Baseline = true)]
+ public void Superposition_Measure()
+ {
+ _sut.Measure(new Size(20, 20));
+ }
+
+ [Benchmark]
+ public void Superposition_Measure_And_Arrange()
+ {
+ _sut.Measure(new Size(20, 20));
+ _sut.Arrange(new Rect(0, 0, 20, 20));
+ }
+
+ [Benchmark]
+ public void Complex_Measure_And_Arrange_Pixels()
+ {
+ Complex_Measure_And_Arrange(new GridLength(10));
+ }
+
+ [Benchmark]
+ public void Complex_Measure_And_Arrange_Auto()
+ {
+ Complex_Measure_And_Arrange(new GridLength(0, GridUnitType.Auto));
+ }
+
+ [Benchmark]
+ public void Complex_Measure_And_Arrange_Star()
+ {
+ Complex_Measure_And_Arrange(new GridLength(1, GridUnitType.Star));
+ }
+
+ private void Complex_Measure_And_Arrange(GridLength gridLength)
+ {
+ var children = _sut.Children;
+
+ for (var i = 0; i < ItemsCount; i++)
+ {
+ var colDef = new ColumnDefinition { Width = gridLength };
+ _sut.ColumnDefinitions.Add(colDef);
+
+ var border = children[i] as FrameworkElement;
+
+ Grid.SetColumn(border, i);
+ }
+
+ _sut.Measure(new Size(500, 500));
+ _sut.Arrange(new Rect(0, 0, 500, 500));
+ }
+
+ [Benchmark]
+ public void Complex_MultiDimension_Measure_And_Arrange_Pixels()
+ {
+ Complex_MultiDimension_Measure_And_Arrange(new GridLength(10));
+ }
+
+ [Benchmark]
+ public void Complex_MultiDimension_Measure_And_Arrange_Auto()
+ {
+ Complex_MultiDimension_Measure_And_Arrange(new GridLength(0, GridUnitType.Auto));
+ }
+
+ [Benchmark]
+ public void Complex_MultiDimension_Measure_And_Arrange_Star()
+ {
+ Complex_MultiDimension_Measure_And_Arrange(new GridLength(1, GridUnitType.Star));
+ }
+
+ private void Complex_MultiDimension_Measure_And_Arrange(GridLength gridLength)
+ {
+ var children = _sut.Children;
+
+ for (var i = 0; i < ItemsCount; i++)
+ {
+ var colDef = new ColumnDefinition { Width = gridLength };
+ _sut.ColumnDefinitions.Add(colDef);
+
+ var rowDef = new RowDefinition { Height = gridLength };
+ _sut.RowDefinitions.Add(rowDef);
+
+ var border = children[i] as FrameworkElement;
+
+ Grid.SetColumn(border, i);
+ Grid.SetColumnSpan(border, i % 4 + 1);
+
+ Grid.SetRow(border, i);
+ Grid.SetRowSpan(border, i % 3 + 1);
+ }
+
+ _sut.Measure(new Size(2000, 2000));
+ _sut.Arrange(new Rect(0, 0, 2000, 2000));
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/ControlCreationBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/ControlCreationBenchmark.cs
new file mode 100644
index 0000000..1a60ee4
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/ControlCreationBenchmark.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Benchmarks.Shared.Controls;
+using Windows.Foundation;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.GridBench
+{
+ public class ControlCreationBenchmark
+ {
+ [Benchmark()]
+ public void TextBoxCreation()
+ => BenchmarkUIHost.Root.Content = new TextBox();
+
+ [Benchmark()]
+ public void ButtonCreation()
+ => BenchmarkUIHost.Root.Content = new Button();
+
+ [Benchmark()]
+ public void CheckBoxCreation()
+ => BenchmarkUIHost.Root.Content = new CheckBox();
+
+ [Benchmark()]
+ public void TextBlockCreation()
+ => BenchmarkUIHost.Root.Content = new TextBlock();
+
+ [Benchmark()]
+ public void SplitViewCreation()
+ => BenchmarkUIHost.Root.Content = new SplitView();
+
+ [Benchmark()]
+ public void ScrollViewerCreation()
+ => BenchmarkUIHost.Root.Content = new ScrollViewer();
+
+ [Benchmark()]
+ public void NavigationViewCreation()
+ => BenchmarkUIHost.Root.Content = new NavigationView();
+
+ [Benchmark()]
+ public void ScrollBarCreation()
+ => BenchmarkUIHost.Root.Content = new ScrollBar();
+
+ [Benchmark()]
+ public void ListViewItemCreation()
+ => BenchmarkUIHost.Root.Content = new ListViewItem();
+
+ [Benchmark()]
+ public void ComboBoxCreation()
+ => BenchmarkUIHost.Root.Content = new ComboBox();
+
+ [Benchmark()]
+ public void ComboBoxItemCreation()
+ => BenchmarkUIHost.Root.Content = new ComboBoxItem();
+
+ [GlobalCleanup]
+ public void Setup()
+ {
+ BenchmarkUIHost.Root.Content = null;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/LoadUnloadPerf.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/LoadUnloadPerf.cs
new file mode 100644
index 0000000..ecf8f84
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/LoadUnloadPerf.cs
@@ -0,0 +1,48 @@
+using BenchmarkDotNet.Attributes;
+using Benchmarks.Shared.Controls;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.GridBench
+{
+ public class LoadUnloadBenchmark
+ {
+ [Params(5, 10, 30)]
+ public int Depth { get; set; }
+
+ private Grid SUT;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ SUT = CreateHierachy();
+ }
+
+ [Benchmark()]
+ public void BasicLoadUnload()
+ {
+ var item = CreateHierachy();
+
+ for (int i = 0; i < 50; i++)
+ {
+ BenchmarkUIHost.Root.Content = item;
+ BenchmarkUIHost.Root.Content = null;
+ }
+ }
+
+ private Grid CreateHierachy()
+ {
+ var top = new Grid();
+ var current = top;
+
+ for (int i = 0; i < Depth; i++)
+ {
+ var n = new Grid();
+ current.Children.Add(n);
+ current = n;
+ }
+
+ current.Children.Add(new TextBlock() { Text = "test" });
+
+ return top;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/UIElementCreationBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/UIElementCreationBenchmark.cs
new file mode 100644
index 0000000..efcce37
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/Suite/Windows_UI_Xaml_Controls/UIElementPerf/UIElementCreationBenchmark.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using Windows.Foundation;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Shapes;
+
+namespace SamplesApp.Benchmarks.Suite.Windows_UI_Xaml_Controls.UIElementPerf
+{
+ public class UIElementCreationBenchmark
+ {
+ [Benchmark]
+ public void BorderCreation()
+ {
+ var SUT = new Grid();
+
+ for (int i = 0; i < 20; i++)
+ {
+ SUT.Children.Add(new Border());
+ }
+ }
+
+ [Benchmark]
+ public void RectangleCreation()
+ {
+ var SUT = new Grid();
+
+ for (int i = 0; i < 20; i++)
+ {
+ SUT.Children.Add(new Rectangle());
+ }
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormBenchHelper.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormBenchHelper.cs
new file mode 100644
index 0000000..85f8326
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormBenchHelper.cs
@@ -0,0 +1,92 @@
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace Benchmarks.Shared.SuiteUI.ComplexUI.FormBench
+{
+ internal static class FormBenchHelper
+ {
+ internal static Grid MakeGrid()
+ {
+ var nameLabel = new TextBlock() { Text = "Name: " };
+ Grid.SetRow(nameLabel, 0);
+ Grid.SetColumn(nameLabel, 0);
+
+ var emailLabel = new TextBlock() { Text = "Email: " };
+ Grid.SetRow(emailLabel, 1);
+ Grid.SetColumn(emailLabel, 0);
+
+ var ageLabel = new TextBlock() { Text = "Age: " };
+ Grid.SetRow(ageLabel, 2);
+ Grid.SetColumn(ageLabel, 0);
+
+ var occupationLabel = new TextBlock() { Text = "Occupation: " };
+ Grid.SetRow(occupationLabel, 3);
+ Grid.SetColumn(occupationLabel, 0);
+
+ var notificationsLabel = new TextBlock() { Text = "Notifications: " };
+ Grid.SetRow(notificationsLabel, 4);
+ Grid.SetColumn(notificationsLabel, 0);
+
+ var name = new TextBox();
+ Grid.SetRow(name, 0);
+ Grid.SetColumn(name, 1);
+
+ var email = new TextBox();
+ Grid.SetRow(email, 1);
+ Grid.SetColumn(email, 1);
+
+ var age = new NumberBox();
+ Grid.SetRow(age, 2);
+ Grid.SetColumn(age, 1);
+
+ var occupation = new ComboBox()
+ {
+ ItemsSource = new[] { "Developer", "IT", "QA" },
+ SelectedIndex = 0
+ };
+ Grid.SetRow(occupation, 3);
+ Grid.SetColumn(occupation, 1);
+
+ var notifications = new CheckBox();
+ Grid.SetRow(notifications, 4);
+ Grid.SetColumn(notifications, 1);
+
+ var save = new Button() { Content = "Save changes" };
+ Grid.SetRow(save, 5);
+ Grid.SetColumn(save, 1);
+
+ return new Grid()
+ {
+ ColumnDefinitions =
+ {
+ new ColumnDefinition() { Width = new GridLength(100d, GridUnitType.Pixel) },
+ new ColumnDefinition() { Width = new GridLength(150d, GridUnitType.Pixel) }
+ },
+ RowDefinitions =
+ {
+ new RowDefinition() { Height = GridLength.Auto },
+ new RowDefinition() { Height = GridLength.Auto },
+ new RowDefinition() { Height = GridLength.Auto },
+ new RowDefinition() { Height = GridLength.Auto },
+ new RowDefinition() { Height = GridLength.Auto },
+ new RowDefinition() { Height = GridLength.Auto }
+ },
+ Children =
+ {
+ nameLabel,
+ emailLabel,
+ ageLabel,
+ occupationLabel,
+ notificationsLabel,
+ name,
+ email,
+ age,
+ occupation,
+ notifications,
+ save
+ }
+ };
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormInitializeBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormInitializeBenchmark.cs
new file mode 100644
index 0000000..f749fab
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormInitializeBenchmark.cs
@@ -0,0 +1,16 @@
+using System.Threading.Tasks;
+
+using Benchmarks.Shared.Benchmarking;
+
+namespace Benchmarks.Shared.SuiteUI.ComplexUI.FormBench
+{
+ internal class FormInitializeBenchmark : IAsyncUIBenchmark
+ {
+ public Task BenchmarkAsync()
+ {
+ FormBenchHelper.MakeGrid();
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormLoadedBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormLoadedBenchmark.cs
new file mode 100644
index 0000000..b0c01d8
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/FormBench/FormLoadedBenchmark.cs
@@ -0,0 +1,39 @@
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml.Controls;
+
+using Benchmarks.Shared.Benchmarking;
+using Benchmarks.Shared.Controls;
+
+namespace Benchmarks.Shared.SuiteUI.ComplexUI.FormBench
+{
+ internal class FormLoadedBenchmark : IAsyncUIBenchmark, IAsyncUIBenchmarkSetup
+ {
+ private Grid _sut;
+
+ private TaskCompletionSource _tcs;
+
+ public Task SetupAsync()
+ {
+ _tcs = new TaskCompletionSource();
+
+ _sut = FormBenchHelper.MakeGrid();
+ _sut.Loaded += (s, e) => _tcs.SetResult(true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task BenchmarkAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = _sut;
+
+ return _tcs.Task;
+ }
+
+ public Task TeardownAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = null;
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/BorderInitializeBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/BorderInitializeBenchmark.cs
new file mode 100644
index 0000000..47a6884
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/BorderInitializeBenchmark.cs
@@ -0,0 +1,29 @@
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+using Benchmarks.Shared.Benchmarking;
+using Microsoft.UI;
+
+namespace Benchmarks.Shared.SuiteUI.ComplexUI.MultiplePropertyBench
+{
+ internal class BorderInitializeBenchmark : IAsyncUIBenchmark
+ {
+ public Task BenchmarkAsync()
+ {
+ var border = new Border()
+ {
+ Background = new SolidColorBrush(Colors.Yellow),
+ BorderBrush = new SolidColorBrush(Colors.Black),
+ BorderThickness = new Thickness(10d),
+ CornerRadius = new CornerRadius(0.5d),
+ Padding = new Thickness(15d),
+
+ Child = new TextBlock() { Text = "BORDERLINE" }
+ };
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/BorderLoadedBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/BorderLoadedBenchmark.cs
new file mode 100644
index 0000000..5b59944
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/BorderLoadedBenchmark.cs
@@ -0,0 +1,52 @@
+using System.Threading.Tasks;
+using Windows.UI;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+using Benchmarks.Shared.Benchmarking;
+using Benchmarks.Shared.Controls;
+using Microsoft.UI;
+
+namespace Benchmarks.Shared.SuiteUI.ComplexUI.MultiplePropertyBench
+{
+ internal class BorderLoadedBenchmark : IAsyncUIBenchmark, IAsyncUIBenchmarkSetup
+ {
+ private Border _sut;
+
+ private TaskCompletionSource _tcs;
+
+ public Task SetupAsync()
+ {
+ _tcs = new TaskCompletionSource();
+
+ _sut = new Border()
+ {
+ Background = new SolidColorBrush(Colors.Yellow),
+ BorderBrush = new SolidColorBrush(Colors.Black),
+ BorderThickness = new Thickness(10d),
+ CornerRadius = new CornerRadius(0.5d),
+ Padding = new Thickness(15d),
+
+ Child = new TextBlock() { Text = "BORDERLINE" }
+ };
+ _sut.Loaded += (s, e) => _tcs.SetResult(true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task BenchmarkAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = _sut;
+
+ return _tcs.Task;
+ }
+
+ public Task TeardownAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = null;
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/TextBlockInitializeBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/TextBlockInitializeBenchmark.cs
new file mode 100644
index 0000000..4d57fe3
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/TextBlockInitializeBenchmark.cs
@@ -0,0 +1,32 @@
+using System.Threading.Tasks;
+using Microsoft.UI;
+using Microsoft.UI.Text;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+using Benchmarks.Shared.Benchmarking;
+
+namespace Benchmarks.Shared.SuiteUI.ComplexUI.MultiplePropertyBench
+{
+ internal class TextBlockInitializeBenchmark : IAsyncUIBenchmark
+ {
+ public Task BenchmarkAsync()
+ {
+ var textBlock = new TextBlock()
+ {
+ FontFamily = new FontFamily("Courier New"),
+ FontSize = 20d,
+ FontStyle = Windows.UI.Text.FontStyle.Italic,
+ FontWeight = FontWeights.ExtraBlack,
+ Foreground = new SolidColorBrush(Colors.Red),
+ HorizontalTextAlignment = TextAlignment.Right,
+ Text = "TYPo",
+ TextDecorations = Windows.UI.Text.TextDecorations.Strikethrough,
+ Width = 150d
+ };
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/TextBlockLoadedBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/TextBlockLoadedBenchmark.cs
new file mode 100644
index 0000000..58a4c03
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/MultiplePropertyBench/TextBlockLoadedBenchmark.cs
@@ -0,0 +1,56 @@
+using System.Threading.Tasks;
+using Windows.UI;
+using Windows.UI.Text;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+using Benchmarks.Shared.Benchmarking;
+using Benchmarks.Shared.Controls;
+using Microsoft.UI;
+using Microsoft.UI.Text;
+
+namespace Benchmarks.Shared.SuiteUI.ComplexUI.MultiplePropertyBench
+{
+ internal class TextBlockLoadedBenchmark : IAsyncUIBenchmark, IAsyncUIBenchmarkSetup
+ {
+ private TextBlock _sut;
+
+ private TaskCompletionSource _tcs;
+
+ public Task SetupAsync()
+ {
+ _tcs = new TaskCompletionSource();
+
+ _sut = new TextBlock()
+ {
+ FontFamily = new FontFamily("Courier New"),
+ FontSize = 20d,
+ FontStyle = FontStyle.Italic,
+ FontWeight = FontWeights.ExtraBlack,
+ Foreground = new SolidColorBrush(Colors.Red),
+ HorizontalTextAlignment = TextAlignment.Right,
+ Text = "TYPo",
+ TextDecorations = TextDecorations.Strikethrough,
+ Width = 150d
+ };
+ _sut.Loaded += (s, e) => _tcs.SetResult(true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task BenchmarkAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = _sut;
+
+ return _tcs.Task;
+ }
+
+ public Task TeardownAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = null;
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/TreeBench/DeepTreeLoadedBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/TreeBench/DeepTreeLoadedBenchmark.cs
new file mode 100644
index 0000000..a513eb3
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/TreeBench/DeepTreeLoadedBenchmark.cs
@@ -0,0 +1,58 @@
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml.Controls;
+
+using Benchmarks.Shared.Benchmarking;
+using Benchmarks.Shared.Controls;
+
+namespace Benchmarks.Shared.SuiteUI.TreeBench
+{
+ internal class DeepTreeLoadedBenchmark : IAsyncUIBenchmark, IAsyncUIBenchmarkSetup
+ {
+ private StackPanel _sut;
+
+ private TaskCompletionSource _tcs;
+
+ public Task SetupAsync()
+ {
+ _tcs = new TaskCompletionSource();
+
+ _sut = MakePanel();
+ _sut.Loaded += (s, e) => _tcs.SetResult(true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task BenchmarkAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = _sut;
+
+ return _tcs.Task;
+ }
+
+ public Task TeardownAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = null;
+
+ return Task.CompletedTask;
+ }
+
+ private StackPanel MakePanel()
+ {
+ var current = new StackPanel()
+ {
+ Children = { new TextBlock() { Text = "DEEP TROUBLE !" } }
+ };
+
+ for (int x = 0; x < 99; x++)
+ {
+ var panel = new StackPanel();
+
+ panel.Children.Add(current);
+
+ current = panel;
+ }
+
+ return current;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/TreeBench/WideTreeLoadedBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/TreeBench/WideTreeLoadedBenchmark.cs
new file mode 100644
index 0000000..274c547
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/ComplexUI/TreeBench/WideTreeLoadedBenchmark.cs
@@ -0,0 +1,56 @@
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml.Controls;
+
+using Benchmarks.Shared.Benchmarking;
+using Benchmarks.Shared.Controls;
+
+namespace Benchmarks.Shared.SuiteUI.TreeBench
+{
+ internal class WideTreeLoadedBenchmark : IAsyncUIBenchmark, IAsyncUIBenchmarkSetup
+ {
+ private StackPanel _sut;
+
+ private TaskCompletionSource _tcs;
+
+ public Task SetupAsync()
+ {
+ _tcs = new TaskCompletionSource();
+
+ _sut = MakePanel();
+ _sut.Loaded += (s, e) => _tcs.SetResult(true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task BenchmarkAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = _sut;
+
+ return _tcs.Task;
+ }
+
+ public Task TeardownAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = null;
+
+ return Task.CompletedTask;
+ }
+
+ private StackPanel MakePanel()
+ {
+ var panel = new StackPanel();
+
+ for (int x = 0; x < 50; x++)
+ {
+ var current = new StackPanel()
+ {
+ Children = { new TextBlock() { Text = "WIDE BERTH !" } }
+ };
+
+ panel.Children.Add(current);
+ }
+
+ return panel;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/NoOpBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/NoOpBenchmark.cs
new file mode 100644
index 0000000..06c7563
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/NoOpBenchmark.cs
@@ -0,0 +1,14 @@
+using System.Threading.Tasks;
+
+using Benchmarks.Shared.Benchmarking;
+
+namespace Benchmarks.Shared.SuiteUI
+{
+ internal class NoOpBenchmark : IAsyncUIBenchmark
+ {
+ public Task BenchmarkAsync()
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/Windows_UI_Xaml_Controls/TextBlockBench/LoadedBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/Windows_UI_Xaml_Controls/TextBlockBench/LoadedBenchmark.cs
new file mode 100644
index 0000000..47432e6
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/Windows_UI_Xaml_Controls/TextBlockBench/LoadedBenchmark.cs
@@ -0,0 +1,40 @@
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml.Controls;
+
+using Benchmarks.Shared.Benchmarking;
+using Benchmarks.Shared.Controls;
+
+namespace Benchmarks.Shared.SuiteUI.Windows_UI_Xaml_Controls.TextBlockBench
+{
+ internal class LoadedBenchmark : IAsyncUIBenchmark, IAsyncUIBenchmarkSetup
+ {
+ private TextBlock _sut;
+
+ private TaskCompletionSource _tcs;
+
+ public Task SetupAsync()
+ {
+ _tcs = new TaskCompletionSource();
+
+ _sut = new TextBlock();
+ _sut.Text = "Hello Uno!";
+ _sut.Loaded += (s, e) => _tcs.SetResult(true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task BenchmarkAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = _sut;
+
+ return _tcs.Task;
+ }
+
+ public Task TeardownAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = null;
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/Windows_UI_Xaml_Controls/TextBlockBench/MultipleLoadedBenchmark.cs b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/Windows_UI_Xaml_Controls/TextBlockBench/MultipleLoadedBenchmark.cs
new file mode 100644
index 0000000..4b5da48
--- /dev/null
+++ b/src/dopesbench/dopesbench/Benchmarks.Shared/SuiteUI/Windows_UI_Xaml_Controls/TextBlockBench/MultipleLoadedBenchmark.cs
@@ -0,0 +1,45 @@
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml.Controls;
+
+using Benchmarks.Shared.Benchmarking;
+using Benchmarks.Shared.Controls;
+
+namespace Benchmarks.Shared.SuiteUI.Windows_UI_Xaml_Controls.TextBlockBench
+{
+ internal class MultipleLoadedBenchmark : IAsyncUIBenchmark, IAsyncUIBenchmarkSetup
+ {
+ private StackPanel _sut;
+
+ private TaskCompletionSource _tcs;
+
+ public Task SetupAsync()
+ {
+ _tcs = new TaskCompletionSource();
+
+ _sut = new StackPanel();
+
+ for (int x = 0; x < 100; x++)
+ {
+ _sut.Children.Add(new TextBlock() { Text = "Hello Uno!" });
+ }
+
+ _sut.Loaded += (s, e) => _tcs.SetResult(true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task BenchmarkAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = _sut;
+
+ return _tcs.Task;
+ }
+
+ public Task TeardownAsync()
+ {
+ AsyncUIBenchmarkHost.Root.Content = null;
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/dopesbench/dopesbench/Components/AppBar.xaml b/src/dopesbench/dopesbench/Components/AppBar.xaml
new file mode 100644
index 0000000..efb741c
--- /dev/null
+++ b/src/dopesbench/dopesbench/Components/AppBar.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Components/AppBar.xaml.cs b/src/dopesbench/dopesbench/Components/AppBar.xaml.cs
new file mode 100644
index 0000000..bc09ba7
--- /dev/null
+++ b/src/dopesbench/dopesbench/Components/AppBar.xaml.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Benchmarks;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+
+// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
+
+namespace dopesbench.Components;
+public sealed partial class AppBar : UserControl
+{
+ public AppBar()
+ {
+ this.InitializeComponent();
+ }
+
+ private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
+ {
+
+ if (args.SelectedItem is NavigationViewItem item)
+ {
+ switch (item.Tag)
+ {
+ case "Dopes":
+ ContentFrame.Navigate(typeof(DopesPage));
+ break;
+ case "Home":
+ ContentFrame.Navigate(typeof(HomePage));
+ break;
+ case "Bench":
+ ContentFrame.Navigate(typeof(MainPage));
+ break;
+ }
+
+ }
+ }
+
+ public void Navigate(Type pageType, object parameter = null)
+ {
+ ContentFrame.Navigate(pageType, parameter);
+ }
+}
diff --git a/src/dopesbench/dopesbench/DopesPage.xaml b/src/dopesbench/dopesbench/DopesPage.xaml
new file mode 100644
index 0000000..4d7a76b
--- /dev/null
+++ b/src/dopesbench/dopesbench/DopesPage.xaml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/DopesPage.xaml.cs b/src/dopesbench/dopesbench/DopesPage.xaml.cs
new file mode 100644
index 0000000..28b1876
--- /dev/null
+++ b/src/dopesbench/dopesbench/DopesPage.xaml.cs
@@ -0,0 +1,841 @@
+using Azure;
+using Azure.Storage.Blobs;
+using Newtonsoft.Json;
+using Saplin.xOPS.UI.Misc;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.UI;
+using Microsoft.UI;
+using Xamarin.Essentials;
+
+
+// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
+
+namespace dopesbench
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ /// `
+ public sealed partial class DopesPage : Page
+ {
+ public DopesPage()
+ {
+ this.InitializeComponent();
+ }
+
+ volatile bool breakTest = false;
+ const int max = 600;
+
+ public static Brush ConvertColor(Color c) => new SolidColorBrush(c);
+
+ //void StartTestMT()
+ //{
+ // var rand = new Random2(0);
+
+ // breakTest = false;
+
+ // var width = absolute.ActualWidth;
+ // var height = absolute.ActualHeight;
+
+ // var i = 0;
+ // var processed = 0;
+
+ // async void Loop()
+ // {
+ // while (true)
+ // {
+ // if (processed < i - 20)
+ // {
+ // Thread.Sleep(1);
+ // continue;
+ // }
+
+ // var label = new TextBlock()
+ // {
+ // Text = "Dope",
+ // Foreground = new SolidColorBrush(Color.FromArgb(1, (byte)(rand.NextDouble()*255), (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255)))
+ // };
+
+ // label.RenderTransform = new RotateTransform() { Angle = rand.NextDouble() * 360 };
+
+ // Canvas.SetLeft(label, rand.NextDouble());
+ // Canvas.SetTop(label, rand.NextDouble());
+
+ // if (i > max)
+ // {
+ // absolute.Children.RemoveAt(0);
+ // }
+
+ // absolute.Children.Add(label);
+
+ // await Task.Yield();
+
+ // if (breakTest) break;
+
+ // i++;
+ // }
+ // });
+
+ // Loop();
+
+ // var sw = new Stopwatch();
+ // sw.Start();
+ // long prevTicks = 0;
+ // int prevProcessed = 0;
+ // double avgSum = 0;
+ // int avgN = 0;
+
+ // var timer = new DispatcherTimer();
+ // timer.Interval = TimeSpan.FromMilliseconds(500);
+ // timer.Tick += (s, e) =>
+ // {
+ // if (stop.Visibility == Visiblity.Visible)
+ // {
+ // var avg = avgSum / avgN;
+ // dopes.Text = string.Format("{0:0.00} Dopes/s (AVG)", avg).PadLeft(21);
+ // return false;
+ // }
+
+ // var r = (double)(processed - prevProcessed) / ((double)(sw.ElapsedTicks - prevTicks) / Stopwatch.Frequency);
+ // dopes.Text = string.Format("{0:0.00} Dopes/s", r).PadLeft(15);
+ // prevTicks = sw.ElapsedTicks;
+ // prevProcessed = processed;
+
+ // if (i > max)
+ // {
+ // avgSum += r;
+ // avgN++;
+ // }
+
+ // return true;
+ // });
+ //}
+
+ // void StartTestMT2()
+ // {
+ // var rand = new Random2(0);
+
+ // breakTest = false;
+
+ // var width = absolute.ActualWidth;
+ // var height = absolute.ActualHeight;
+
+ // const int step = 75;
+
+ // var processed = 0;
+
+ // long prevTicks = 0;
+ // long prevMs = 0;
+ // int prevProcessed = 0;
+ // double avgSum = 0;
+ // int avgN = 0;
+ // var sw = new Stopwatch();
+
+ // var bankA = new TextBlock[step];
+ // var bankB = new TextBlock[step];
+
+ // Action addLabels = (TextBlock[] labels) =>
+ // {
+ // for (int k = 0; k < step; k++)
+ // {
+ //var label = new TextBlock()
+ //{
+ // Text = "Dope",
+ // Foreground = new SolidColorBrush(Color.FromArgb(1, (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255)))
+ //};
+
+ //label.RenderTransform = new RotateTransform() { Angle = rand.NextDouble() * 360 };
+
+ //Canvas.SetLeft(label, rand.NextDouble());
+ //Canvas.SetTop(label, rand.NextDouble());
+
+ // labels[k] = label;
+ // }
+ // };
+
+ // addLabels(bankA);
+ // addLabels(bankB);
+
+ // var bank = bankA;
+
+ // Action loop = null;
+
+ // var i = 0;
+ // Task task = null;
+
+ // loop = () =>
+ // {
+ // if (breakTest)
+ // {
+ // var avg = avgSum / avgN;
+ // dopes.Text = string.Format("{0:0.00} Dopes/s (AVG)", avg).PadLeft(21);
+ // return;
+ // }
+
+ // if (processed > max)
+ // {
+ // absolute.Children.RemoveAt(0);
+ // }
+
+ // absolute.Children.Add(bank[i]);
+ // i++;
+
+ // if (i == step)
+ // {
+ // if (task != null && task.Status != TaskStatus.RanToCompletion) task.Wait();
+ // task = Task.Run(() => addLabels(bank));
+ // if (bank == bankA) bank = bankB; else bank = bankA;
+ // i = 0;
+ // }
+
+ // processed++;
+
+ // if (sw.ElapsedMilliseconds - prevMs > 500)
+ // {
+
+ // var r = (double)(processed - prevProcessed) / ((double)(sw.ElapsedTicks - prevTicks) / Stopwatch.Frequency);
+ // prevTicks = sw.ElapsedTicks;
+ // prevProcessed = processed;
+
+ // if (processed > max)
+ // {
+ // dopes.Text = string.Format("{0:0.00} Dopes/s", r).PadLeft(15);
+ // avgSum += r;
+ // avgN++;
+ // }
+
+ // prevMs = sw.ElapsedMilliseconds;
+ // }
+
+ // _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () => loop());
+ // };
+
+ // sw.Start();
+
+
+ // Device.BeginInvokeOnMainThread(loop);
+ // }
+
+ void StartTestST()
+ {
+ var rand = new Random2(0);
+
+ breakTest = false;
+
+ var width = absolute.ActualWidth;
+ var height = absolute.ActualHeight;
+
+ const int step = 20;
+ var labels = new TextBlock[step * 2];
+
+ var processed = 0;
+
+ long prevTicks = 0;
+ long prevMs = 0;
+ int prevProcessed = 0;
+ double avgSum = 0;
+ int avgN = 0;
+ var sw = new Stopwatch();
+
+ Action loop = null;
+
+ loop = () =>
+ {
+ var now = sw.ElapsedMilliseconds;
+
+ if (breakTest)
+ {
+ var avg = avgSum / avgN;
+ dopes.Text = string.Format("{0:0.00} Dopes/s (AVG)", avg).PadLeft(21);
+ return;
+ }
+
+ //60hz, 16ms to build the frame
+ while (sw.ElapsedMilliseconds - now < 16 && !breakTest)
+ {
+ var label = new TextBlock()
+ {
+ Text = "Dope",
+ Foreground = new SolidColorBrush(Color.FromArgb(0xFF, (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255)))
+ };
+
+ label.RenderTransform = new RotateTransform() { Angle = rand.NextDouble() * 360 };
+
+ Canvas.SetLeft(label, rand.NextDouble() * width);
+ Canvas.SetTop(label, rand.NextDouble() * height);
+
+ if (processed > max)
+ {
+ absolute.Children.RemoveAt(0);
+ }
+
+ absolute.Children.Add(label);
+
+ processed++;
+
+ if (sw.ElapsedMilliseconds - prevMs > 500)
+ {
+
+ var r = (double)(processed - prevProcessed) / ((double)(sw.ElapsedTicks - prevTicks) / Stopwatch.Frequency);
+ prevTicks = sw.ElapsedTicks;
+ prevProcessed = processed;
+
+ if (processed > max)
+ {
+ dopes.Text = string.Format("{0:0.00} Dopes/s", r).PadLeft(15);
+ avgSum += r;
+ avgN++;
+ }
+
+ prevMs = sw.ElapsedMilliseconds;
+ }
+ }
+
+ _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => loop());
+ };
+
+ sw.Start();
+
+ _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => loop());
+ }
+
+ void StartTestReuseST()
+ {
+ var rand = new Random2(0);
+
+ breakTest = false;
+
+ var width = absolute.ActualWidth;
+ var height = absolute.ActualHeight;
+
+ const int step = 20;
+ var labels = new TextBlock[step * 2];
+
+ var processed = 0;
+
+ long prevTicks = 0;
+ long prevMs = 0;
+ int prevProcessed = 0;
+ double avgSum = 0;
+ int avgN = 0;
+ var sw = new Stopwatch();
+
+ Action loop = null;
+
+ Stack _cache = new Stack();
+
+ loop = () =>
+ {
+ var now = sw.ElapsedMilliseconds;
+
+ if (breakTest)
+ {
+ var avg = avgSum / avgN;
+ dopes.Text = string.Format("{0:0.00} Dopes/s (AVG)", avg).PadLeft(21);
+ return;
+ }
+
+ //60hz, 16ms to build the frame
+ while (sw.ElapsedMilliseconds - now < 16 && !breakTest)
+ {
+ var label = _cache.Count == 0 ? new TextBlock() { Foreground = new SolidColorBrush() } : _cache.Pop();
+
+ label.Text = "Dope";
+ (label.Foreground as SolidColorBrush).Color = Color.FromArgb(0xFF, (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255));
+
+ label.RenderTransform = new RotateTransform() { Angle = rand.NextDouble() * 360 };
+
+ Canvas.SetLeft(label, rand.NextDouble() * width);
+ Canvas.SetTop(label, rand.NextDouble() * height);
+
+ if (processed > max)
+ {
+ _cache.Push(absolute.Children[0] as TextBlock);
+ absolute.Children.RemoveAt(0);
+ }
+
+ absolute.Children.Add(label);
+
+ processed++;
+
+ if (sw.ElapsedMilliseconds - prevMs > 500)
+ {
+
+ var r = (double)(processed - prevProcessed) / ((double)(sw.ElapsedTicks - prevTicks) / Stopwatch.Frequency);
+ prevTicks = sw.ElapsedTicks;
+ prevProcessed = processed;
+
+ if (processed > max)
+ {
+ dopes.Text = string.Format("{0:0.00} Dopes/s", r).PadLeft(15);
+ avgSum += r;
+ avgN++;
+ }
+
+ prevMs = sw.ElapsedMilliseconds;
+ }
+ }
+
+ _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () => loop());
+ };
+
+ sw.Start();
+
+ _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () => loop());
+ }
+
+ //void StartTestGridST()
+ //{
+ // var rand = new Random2(0);
+
+ // breakTest = false;
+
+ // var width = grid.Width;
+ // var height = grid.Height;
+
+ // const int step = 20;
+ // var labels = new Label[step * 2];
+
+ // var processed = 0;
+
+ // long prevTicks = 0;
+ // long prevMs = 0;
+ // int prevProcessed = 0;
+ // double avgSum = 0;
+ // int avgN = 0;
+ // var sw = new Stopwatch();
+
+ // Action loop = null;
+
+ // loop = () =>
+ // {
+ // if (breakTest)
+ // {
+ // var avg = avgSum / avgN;
+ // dopes.Text = string.Format("{0:0.00} Dopes/s (AVG)", avg).PadLeft(21);
+ // return;
+ // }
+
+ // var now = sw.ElapsedMilliseconds;
+
+ // //60hz, 16ms to build the frame
+ // while (sw.ElapsedMilliseconds - now < 16)
+ // {
+ // var label = new Label()
+ // {
+ // Text = "Dope",
+ // TextColor = new Color(rand.NextDouble(), rand.NextDouble(), rand.NextDouble()),
+ // Rotation = rand.NextDouble() * 360,
+ // TranslationX = rand.NextDouble() * width,
+ // TranslationY = rand.NextDouble() * height
+ // };
+
+
+ // if (processed > max)
+ // {
+ // grid.Children.RemoveAt(0);
+ // }
+
+ // grid.Children.Add(label);
+
+ // processed++;
+
+ // if (sw.ElapsedMilliseconds - prevMs > 500)
+ // {
+
+ // var r = (double)(processed - prevProcessed) / ((double)(sw.ElapsedTicks - prevTicks) / Stopwatch.Frequency);
+ // prevTicks = sw.ElapsedTicks;
+ // prevProcessed = processed;
+
+ // if (processed > max)
+ // {
+ // dopes.Text = string.Format("{0:0.00} Dopes/s", r).PadLeft(15);
+ // avgSum += r;
+ // avgN++;
+ // }
+
+ // prevMs = sw.ElapsedMilliseconds;
+ // }
+ // }
+
+ // Device.BeginInvokeOnMainThread(loop);
+ // };
+
+ // sw.Start();
+
+ // Device.BeginInvokeOnMainThread(loop);
+ //}
+
+ void StartTestBindings()
+ {
+ var rand = new Random2(0);
+
+ breakTest = false;
+
+ var width = absolute.ActualWidth;
+ var height = absolute.ActualHeight;
+
+ const int step = 20;
+ var labels = new TextBlock[step * 2];
+
+ var processed = 0;
+
+ long prevTicks = 0;
+ long prevMs = 0;
+ int prevProcessed = 0;
+ double avgSum = 0;
+ int avgN = 0;
+ var sw = new Stopwatch();
+
+ var source = Enumerable.Range(0, max).Select(i => new BindingItem() { Color = Colors.Red }).ToArray();
+ items.ItemsSource = source;
+
+ Action loop = null;
+ var current = 0;
+
+ loop = () =>
+ {
+ var now = sw.ElapsedMilliseconds;
+
+ if (breakTest)
+ {
+ var avg = avgSum / avgN;
+ dopes.Text = string.Format("{0:0.00} Dopes/s (AVG)", avg).PadLeft(21);
+ return;
+ }
+
+ //60hz, 16ms to build the frame
+ while (sw.ElapsedMilliseconds - now < 16 && !breakTest)
+ {
+ var index = current++ % source.Length;
+
+ source[index].Color = Color.FromArgb(0xFF, (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255));
+ source[index].Rotation = rand.NextDouble() * 360;
+ source[index].Top = rand.NextDouble() * height;
+ source[index].Left = rand.NextDouble() * width;
+
+ processed++;
+
+ if (sw.ElapsedMilliseconds - prevMs > 500)
+ {
+
+ var r = (double)(processed - prevProcessed) / ((double)(sw.ElapsedTicks - prevTicks) / Stopwatch.Frequency);
+ prevTicks = sw.ElapsedTicks;
+ prevProcessed = processed;
+
+ if (processed > max)
+ {
+ dopes.Text = string.Format("{0:0.00} Dopes/s", r).PadLeft(15);
+ avgSum += r;
+ avgN++;
+ }
+
+ prevMs = sw.ElapsedMilliseconds;
+ }
+ }
+
+ _ = Dispatcher.RunIdleAsync(_ => loop());
+ };
+
+ sw.Start();
+
+ _ = Dispatcher.RunIdleAsync(_ => loop());
+ }
+
+ public void StartTestChangeST()
+ {
+ var rand = new Random2(0);
+
+ breakTest = false;
+
+ var width = grid.ActualWidth;
+ var height = grid.ActualHeight;
+
+ const int step = 20;
+ var labels = new TextBlock[step * 2];
+
+ var processed = 0;
+
+ long prevTicks = 0;
+ long prevMs = 0;
+ int prevProcessed = 0;
+ double avgSum = 0;
+ int avgN = 0;
+ var sw = new Stopwatch();
+
+ var texts = new string[] { "dOpe", "Dope", "doPe", "dopE" };
+
+ Action loop = null;
+
+ loop = () =>
+ {
+ if (breakTest)
+ {
+ var avg = avgSum / avgN;
+ dopes.Text = string.Format("{0:0.00} Dopes/s (AVG)", avg).PadLeft(21);
+ return;
+ }
+
+ var now = sw.ElapsedMilliseconds;
+
+ //60hz, 16ms to build the frame
+ while (sw.ElapsedMilliseconds - now < 16 && !breakTest)
+ {
+ if (processed > max)
+ {
+ (absolute.Children[processed % max] as TextBlock).Text = texts[(int)Math.Floor(rand.NextDouble() * 4)];
+ }
+ else
+ {
+ var label = new TextBlock()
+ {
+ Text = "Dope",
+ Foreground = new SolidColorBrush(global::Windows.UI.Color.FromArgb(0xFF, (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255)))
+ };
+
+ label.RenderTransform = new RotateTransform() { Angle = rand.NextDouble() * 360 };
+
+ Canvas.SetLeft(label, rand.NextDouble() * width);
+ Canvas.SetTop(label, rand.NextDouble() * height);
+
+ absolute.Children.Add(label);
+ }
+
+ processed++;
+
+ if (sw.ElapsedMilliseconds - prevMs > 500)
+ {
+
+ var r = (double)(processed - prevProcessed) / ((double)(sw.ElapsedTicks - prevTicks) / Stopwatch.Frequency);
+ prevTicks = sw.ElapsedTicks;
+ prevProcessed = processed;
+
+ if (processed > max)
+ {
+ dopes.Text = string.Format("{0:0.00} Dopes/s", r).PadLeft(15);
+ avgSum += r;
+ avgN++;
+ }
+
+ prevMs = sw.ElapsedMilliseconds;
+ }
+ }
+
+ _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () => loop());
+ };
+
+ sw.Start();
+
+ _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () => loop());
+ }
+
+ private void SetControlsAtStart()
+ {
+ startChangeST.Visibility = startST.Visibility = startGridST.Visibility = Visibility.Collapsed;
+ stop.Visibility = dopes.Visibility = Visibility.Visible;
+ absolute.Children.Clear();
+ grid.Children.Clear();
+ dopes.Text = "Warming up..";
+ }
+
+ void startST_Clicked(System.Object sender, object e)
+ {
+ SetControlsAtStart();
+ StartTestST();
+ }
+
+ void startGridST_Clicked(System.Object sender, object e)
+ {
+ SetControlsAtStart();
+ StartTestBindings();
+ }
+
+ void startChangeST_Clicked(System.Object sender, object e)
+ {
+ SetControlsAtStart();
+ StartTestChangeST();
+ }
+
+ void startChangeReuse_Clicked(System.Object sender, object e)
+ {
+ SetControlsAtStart();
+ StartTestReuseST();
+ }
+
+ void Stop_Clicked(System.Object sender, object e)
+ {
+ breakTest = true;
+ stop.Visibility = Visibility.Collapsed;
+ startChangeST.Visibility = startST.Visibility = startGridST.Visibility = Visibility.Visible;
+ }
+
+ async void startAll_Clicked(System.Object sender, object e)
+ {
+#if HAS_UNO_SKIA
+ var deviceFamilyInfo = Windows.System.Profile.AnalyticsInfo.VersionInfo;
+ var deviceInfo = new
+ {
+ OS = "Skia",
+ OSVersion = deviceFamilyInfo.DeviceFamily,
+ DeviceModel = deviceFamilyInfo.DeviceFamily,
+ //DeviceManufacturer = DeviceInfo.Manufacturer,
+ //DeviceName = DeviceInfo.Name,
+ //DeviceIdiom = DeviceInfo.Idiom.ToString(),
+ //DeviceType = DeviceInfo.DeviceType.ToString()
+ };
+//#elif HAS_UNO_WASM
+// var deviceFamilyInfo = Windows.System.Profile.AnalyticsInfo.VersionInfo;
+// var browserDeviceIdiom = Windows.System.Profile.AnalyticsInfo.DeviceForm;
+// var browserUserAgent = WebAssemblyRuntime.InvokeJS("navigator.userAgent;");
+// var deviceInfo = new
+// {
+// OS = "WebAssembly",
+// //OSVersion = DeviceInfo.VersionString,
+// DeviceModel = browserUserAgent,
+// //DeviceManufacturer = DeviceInfo.Manufacturer,
+// //DeviceName = DeviceInfo.Name,
+// DeviceIdiom = browserDeviceIdiom,
+// //DeviceType = DeviceInfo.DeviceType.ToString()
+// };
+#else
+ var deviceInfo = new
+ {
+ OS = "mac catalyst",
+ OSVersion = string.Empty,
+ DeviceModel = string.Empty,
+ DeviceManufacturer = string.Empty,
+ DeviceName = string.Empty,
+ DeviceIdiom = string.Empty,
+ DeviceType = string.Empty
+ };
+ try
+ {
+ deviceInfo = new
+ {
+ OS = DeviceInfo.Platform.ToString(),
+ OSVersion = DeviceInfo.VersionString,
+ DeviceModel = DeviceInfo.Model,
+ DeviceManufacturer = DeviceInfo.Manufacturer,
+ DeviceName = DeviceInfo.Name,
+ DeviceIdiom = DeviceInfo.Idiom.ToString(),
+ DeviceType = DeviceInfo.DeviceType.ToString()
+ };
+ } catch { }
+#endif
+
+#if DEBUG
+ int testLengthMs = 5000;
+#else
+ int testLengthMs = 60000;
+#endif
+ int pauseLengthMs = 100;
+
+ startST_Clicked(default, default);
+ await Task.Delay(testLengthMs);
+ Stop_Clicked(default, default);
+ await Task.Delay(pauseLengthMs);
+ _ = Decimal.TryParse(dopes.Text.Replace(" Dopes/s (AVG)", "").Trim(), out var resultST);
+
+ startChangeST_Clicked(default, default);
+ await Task.Delay(testLengthMs);
+ Stop_Clicked(default, default);
+ await Task.Delay(pauseLengthMs);
+ _ = Decimal.TryParse(dopes.Text.Replace(" Dopes/s (AVG)", "").Trim(), out var resultChangeST);
+
+ //startChangeReuse_Clicked(default, default);
+ //await Task.Delay(testLengthMs);
+ //Stop_Clicked(default, default);
+ //await Task.Delay(pauseLengthMs);
+ //_ = Decimal.TryParse(dopes.Text.Replace(" Dopes/s (AVG)", "").Trim(), out var resultReuseST);
+
+ //startGridST_Clicked(default, default);
+ //await Task.Delay(testLengthMs);
+ //Stop_Clicked(default, default);
+ //await Task.Delay(pauseLengthMs);
+ //_ = Decimal.TryParse(dopes.Text.Replace(" Dopes/s (AVG)", "").Trim(), out var resultGridST);
+
+ var platformVersion = "Uno Platform 4.2.0-dev.601 .NET 6";
+
+ var results = new
+ {
+ Date = DateTime.Today,
+ DeviceInfo = deviceInfo,
+ Platform = platformVersion,
+ Build = resultST,
+ Change = resultChangeST,
+ //Reuse = resultReuseST,
+ //Grid = resultGridST
+ };
+ string jsonString = JsonConvert.SerializeObject(results);
+
+ Console.WriteLine(jsonString);
+ dopes.Text = $"Build: {results.Build}; Change: {results.Change}";
+
+
+ //try
+ //{
+ // //var client = new BlobServiceClient(Config.StorageConnectionString);
+ // var client = new BlobServiceClient(new Uri(Config.StorageUrl), new AzureSasCredential(Config.StorageSasToken));
+ // var blobContainerClient = client.GetBlobContainerClient("results");
+ // await blobContainerClient.CreateIfNotExistsAsync();
+
+ // var filename = $"{deviceInfo.OS}-{platformVersion}-{DateTime.UtcNow.ToString("yyyy-MM-dd-hh-mm-ss")}.json";
+
+ // using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
+ // await blobContainerClient.UploadBlobAsync(filename, memoryStream);
+
+ // Console.WriteLine("Uploaded.");
+ // }
+ // catch (Exception ex)
+ // {
+ // Console.WriteLine(ex);
+ // }
+
+ }
+ }
+
+ public class BindingItem : INotifyPropertyChanged
+ {
+ private double top;
+ private double left;
+ private double rotation;
+ private Color color;
+
+ public double Top
+ {
+ get => top; set
+ {
+ top = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Top)));
+ }
+ }
+ public double Left
+ {
+ get => left; set
+ {
+ left = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Left)));
+ }
+ }
+ public double Rotation
+ {
+ get => rotation; set
+ {
+ rotation = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Rotation)));
+ }
+ }
+ public Color Color
+ {
+ get => color; set
+ {
+ color = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Color)));
+ }
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+ }
+
+}
diff --git a/src/dopesbench/dopesbench/GlobalUsings.cs b/src/dopesbench/dopesbench/GlobalUsings.cs
new file mode 100644
index 0000000..eeafbe3
--- /dev/null
+++ b/src/dopesbench/dopesbench/GlobalUsings.cs
@@ -0,0 +1,4 @@
+global using System.Collections.Immutable;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Logging;
+global using ApplicationExecutionState = Windows.ApplicationModel.Activation.ApplicationExecutionState;
diff --git a/src/dopesbench/dopesbench/HomePage.xaml b/src/dopesbench/dopesbench/HomePage.xaml
new file mode 100644
index 0000000..cae8602
--- /dev/null
+++ b/src/dopesbench/dopesbench/HomePage.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/HomePage.xaml.cs b/src/dopesbench/dopesbench/HomePage.xaml.cs
new file mode 100644
index 0000000..0ecad14
--- /dev/null
+++ b/src/dopesbench/dopesbench/HomePage.xaml.cs
@@ -0,0 +1,33 @@
+using Azure;
+using Azure.Storage.Blobs;
+using Newtonsoft.Json;
+using Saplin.xOPS.UI.Misc;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.UI;
+using Microsoft.UI;
+using Benchmarks.Shared;
+
+
+// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
+
+namespace dopesbench
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ /// `
+ public sealed partial class HomePage : Page
+ {
+ public HomePage()
+ {
+ this.InitializeComponent();
+ }
+
+ private void NavigateToDopesPage(object sender, RoutedEventArgs e)
+ {
+ Frame.Navigate(typeof(DopesPage));
+ }
+ }
+
+}
diff --git a/src/dopesbench/dopesbench/Package.appxmanifest b/src/dopesbench/dopesbench/Package.appxmanifest
new file mode 100644
index 0000000..9ef3814
--- /dev/null
+++ b/src/dopesbench/dopesbench/Package.appxmanifest
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Platforms/Android/AndroidManifest.xml b/src/dopesbench/dopesbench/Platforms/Android/AndroidManifest.xml
new file mode 100644
index 0000000..95ae075
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Platforms/Android/Assets/AboutAssets.txt b/src/dopesbench/dopesbench/Platforms/Android/Assets/AboutAssets.txt
new file mode 100644
index 0000000..89ab409
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/Assets/AboutAssets.txt
@@ -0,0 +1,22 @@
+To add cross-platform image assets for your Uno Platform app, use the Assets folder
+in the shared project instead. Assets in this folder are Android-only assets.
+
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories) and given a Build Action of "AndroidAsset".
+
+These files will be deployed with your package and will be accessible using Android's
+AssetManager, like this:
+
+public class ReadAsset : Activity
+{
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ InputStream input = Assets.Open ("my_asset.txt");
+ }
+}
+
+Additionally, some Android functions will automatically load asset files:
+
+Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
diff --git a/src/dopesbench/dopesbench/Platforms/Android/Main.Android.cs b/src/dopesbench/dopesbench/Platforms/Android/Main.Android.cs
new file mode 100644
index 0000000..0d85fdb
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/Main.Android.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Microsoft.UI.Xaml.Media;
+
+namespace dopesbench.Droid;
+
+[global::Android.App.ApplicationAttribute(
+ Label = "@string/ApplicationName",
+ Icon = "@mipmap/icon",
+ LargeHeap = true,
+ HardwareAccelerated = true,
+ Theme = "@style/Theme.App.Starting"
+)]
+public class Application : Microsoft.UI.Xaml.NativeApplication
+{
+ static Application()
+ {
+ App.InitializeLogging();
+ }
+
+ public Application(IntPtr javaReference, JniHandleOwnership transfer)
+ : base(() => new App(), javaReference, transfer)
+ {
+ }
+
+}
+
diff --git a/src/dopesbench/dopesbench/Platforms/Android/MainActivity.Android.cs b/src/dopesbench/dopesbench/Platforms/Android/MainActivity.Android.cs
new file mode 100644
index 0000000..ccdfc5e
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/MainActivity.Android.cs
@@ -0,0 +1,23 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using Android.Views;
+using Android.Widget;
+
+namespace dopesbench.Droid;
+
+[Activity(
+ MainLauncher = true,
+ ConfigurationChanges = global::Uno.UI.ActivityHelper.AllConfigChanges,
+ WindowSoftInputMode = SoftInput.AdjustNothing | SoftInput.StateHidden
+)]
+public class MainActivity : Microsoft.UI.Xaml.ApplicationActivity
+{
+ protected override void OnCreate(Bundle? savedInstanceState)
+ {
+ global::AndroidX.Core.SplashScreen.SplashScreen.InstallSplashScreen(this);
+
+ base.OnCreate(savedInstanceState);
+ }
+
+}
diff --git a/src/dopesbench/dopesbench/Platforms/Android/Resources/AboutResources.txt b/src/dopesbench/dopesbench/Platforms/Android/Resources/AboutResources.txt
new file mode 100644
index 0000000..17e3b13
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/Resources/AboutResources.txt
@@ -0,0 +1,47 @@
+To add cross-platform image assets for your Uno Platform app, use the Assets folder
+in the shared project instead. Resources in this folder are Android-only.
+
+Images, layout descriptions, binary blobs and string dictionaries can be included
+in your application as resource files. Various Android APIs are designed to
+operate on the resource IDs instead of dealing with images, strings or binary blobs
+directly.
+
+For example, a sample Android app that contains a user interface layout (main.axml),
+an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
+would keep its resources in the "Resources" directory of the application:
+
+Resources/
+ drawable/
+ icon.png
+
+ layout/
+ main.axml
+
+ values/
+ strings.xml
+
+In order to get the build system to recognize Android resources, set the build action to
+"AndroidResource". The native Android APIs do not operate directly with filenames, but
+instead operate on resource IDs. When you compile an Android application that uses resources,
+the build system will package the resources for distribution and generate a class called "R"
+(this is an Android convention) that contains the tokens for each one of the resources
+included. For example, for the above Resources layout, this is what the R class would expose:
+
+public class R {
+ public class drawable {
+ public const int icon = 0x123;
+ }
+
+ public class layout {
+ public const int main = 0x456;
+ }
+
+ public class strings {
+ public const int first_string = 0xabc;
+ public const int second_string = 0xbcd;
+ }
+}
+
+You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
+to reference the layout/main.axml file, or R.strings.first_string to reference the first
+string in the dictionary file values/strings.xml.
diff --git a/src/dopesbench/dopesbench/Platforms/Android/Resources/values/Strings.xml b/src/dopesbench/dopesbench/Platforms/Android/Resources/values/Strings.xml
new file mode 100644
index 0000000..12f1b7e
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/Resources/values/Strings.xml
@@ -0,0 +1,5 @@
+
+
+ Hello World, Click Me!
+ dopesbench
+
diff --git a/src/dopesbench/dopesbench/Platforms/Android/Resources/values/Styles.xml b/src/dopesbench/dopesbench/Platforms/Android/Resources/values/Styles.xml
new file mode 100644
index 0000000..f47dcf3
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/Resources/values/Styles.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Platforms/Android/environment.conf b/src/dopesbench/dopesbench/Platforms/Android/environment.conf
new file mode 100644
index 0000000..d8c1064
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Android/environment.conf
@@ -0,0 +1,2 @@
+# See this for more details: http://developer.xamarin.com/guides/android/advanced_topics/garbage_collection/
+MONO_GC_PARAMS=bridge-implementation=new,nursery-size=32m,soft-heap-limit=256m
\ No newline at end of file
diff --git a/src/dopesbench/dopesbench/Platforms/Desktop/Program.cs b/src/dopesbench/dopesbench/Platforms/Desktop/Program.cs
new file mode 100644
index 0000000..543a5bc
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/Desktop/Program.cs
@@ -0,0 +1,21 @@
+using Uno.UI.Hosting;
+using dopesbench;
+
+internal class Program
+{
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ App.InitializeLogging();
+
+ var host = UnoPlatformHostBuilder.Create()
+ .App(() => new App())
+ .UseX11()
+ .UseLinuxFrameBuffer()
+ .UseMacOS()
+ .UseWin32()
+ .Build();
+
+ host.Run();
+ }
+}
diff --git a/src/dopesbench/dopesbench/Platforms/WebAssembly/LinkerConfig.xml b/src/dopesbench/dopesbench/Platforms/WebAssembly/LinkerConfig.xml
new file mode 100644
index 0000000..1773b75
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/WebAssembly/LinkerConfig.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Platforms/WebAssembly/Program.cs b/src/dopesbench/dopesbench/Platforms/WebAssembly/Program.cs
new file mode 100644
index 0000000..2d48697
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/WebAssembly/Program.cs
@@ -0,0 +1,11 @@
+using Uno.UI.Hosting;
+using dopesbench;
+
+App.InitializeLogging();
+
+var host = UnoPlatformHostBuilder.Create()
+ .App(() => new App())
+ .UseWebAssembly()
+ .Build();
+
+await host.RunAsync();
diff --git a/src/dopesbench/dopesbench/Platforms/WebAssembly/WasmCSS/Fonts.css b/src/dopesbench/dopesbench/Platforms/WebAssembly/WasmCSS/Fonts.css
new file mode 100644
index 0000000..4fdd605
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/WebAssembly/WasmCSS/Fonts.css
@@ -0,0 +1,28 @@
+/**
+ When adding fonts here, make sure to add them using a base64 data uri, otherwise
+ fonts loading are delayed, and text may get displayed incorrectly.
+*/
+
+/* https://github.com/unoplatform/uno/issues/3954 */
+@font-face {
+ font-family: 'Segoe UI';
+ src: local('Segoe UI'), local('-apple-system'), local('BlinkMacSystemFont'), local('Inter'), local('Cantarell'), local('Ubuntu'), local('Roboto'), local('Open Sans'), local('Noto Sans'), local('Helvetica Neue'), local('sans-serif');
+}
+
+@font-face {
+ font-family: 'Roboto';
+ src: url(./Uno.Fonts.Roboto/Fonts/Roboto-Light.ttf) format('truetype');
+ font-weight: 300;
+}
+
+@font-face {
+ font-family: 'Roboto';
+ src: url(./Uno.Fonts.Roboto/Fonts/Roboto-Regular.ttf) format('truetype');
+ font-weight: 400;
+}
+
+@font-face {
+ font-family: 'Roboto';
+ src: url(./Uno.Fonts.Roboto/Fonts/Roboto-Medium.ttf) format('truetype');
+ font-weight: 500;
+}
diff --git a/src/dopesbench/dopesbench/Platforms/WebAssembly/WasmScripts/AppManifest.js b/src/dopesbench/dopesbench/Platforms/WebAssembly/WasmScripts/AppManifest.js
new file mode 100644
index 0000000..3acf554
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/WebAssembly/WasmScripts/AppManifest.js
@@ -0,0 +1,3 @@
+var UnoAppManifest = {
+ displayName: "dopesbench"
+}
diff --git a/src/dopesbench/dopesbench/Platforms/WebAssembly/manifest.webmanifest b/src/dopesbench/dopesbench/Platforms/WebAssembly/manifest.webmanifest
new file mode 100644
index 0000000..5c84379
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/WebAssembly/manifest.webmanifest
@@ -0,0 +1,10 @@
+{
+ "background_color": "#ffffff",
+ "description": "dopesbench",
+ "display": "standalone",
+ "name": "dopesbench",
+ "short_name": "dopesbench",
+ "start_url": "/index.html",
+ "theme_color": "#ffffff",
+ "scope": "/"
+}
diff --git a/src/dopesbench/dopesbench/Platforms/WebAssembly/wwwroot/staticwebapp.config.json b/src/dopesbench/dopesbench/Platforms/WebAssembly/wwwroot/staticwebapp.config.json
new file mode 100644
index 0000000..79c1b17
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/WebAssembly/wwwroot/staticwebapp.config.json
@@ -0,0 +1,30 @@
+{
+ "navigationFallback": {
+ "rewrite": "/index.html",
+ "exclude": [
+ "*.{css,js}",
+ "*.{png}",
+ "*.{c,h,wasm,clr,pdb,dat,txt}"
+ ]
+ },
+ "routes": [
+ {
+ "route": "/package_*",
+ "headers": {
+ "cache-control": "public, immutable, max-age=31536000"
+ }
+ },
+ {
+ "route": "/*.ttf",
+ "headers": {
+ "cache-control": "public, immutable, max-age=31536000"
+ }
+ },
+ {
+ "route": "/*",
+ "headers": {
+ "cache-control": "must-revalidate, max-age=3600"
+ }
+ }
+ ]
+}
diff --git a/src/dopesbench/dopesbench/Platforms/WebAssembly/wwwroot/web.config b/src/dopesbench/dopesbench/Platforms/WebAssembly/wwwroot/web.config
new file mode 100644
index 0000000..8f5a860
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/WebAssembly/wwwroot/web.config
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Platforms/iOS/Entitlements.plist b/src/dopesbench/dopesbench/Platforms/iOS/Entitlements.plist
new file mode 100644
index 0000000..24c3103
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/iOS/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Platforms/iOS/Info.plist b/src/dopesbench/dopesbench/Platforms/iOS/Info.plist
new file mode 100644
index 0000000..ea3dcb4
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/iOS/Info.plist
@@ -0,0 +1,43 @@
+
+
+
+
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ XSAppIconAssets
+ Assets.xcassets/icon.appiconset
+ UIApplicationSupportsIndirectInputEvents
+
+
+
+
+
diff --git a/src/dopesbench/dopesbench/Platforms/iOS/Main.iOS.cs b/src/dopesbench/dopesbench/Platforms/iOS/Main.iOS.cs
new file mode 100644
index 0000000..a519ed4
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/iOS/Main.iOS.cs
@@ -0,0 +1,12 @@
+using UIKit;
+using Uno.UI.Hosting;
+using dopesbench;
+
+App.InitializeLogging();
+
+var host = UnoPlatformHostBuilder.Create()
+ .App(() => new App())
+ .UseAppleUIKit()
+ .Build();
+
+host.Run();
diff --git a/src/dopesbench/dopesbench/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json b/src/dopesbench/dopesbench/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json
new file mode 100644
index 0000000..69555e4
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json
@@ -0,0 +1,58 @@
+{
+ "images": [
+ {
+ "orientation": "portrait",
+ "extent": "full-screen",
+ "minimum-system-version": "7.0",
+ "scale": "2x",
+ "size": "640x960",
+ "idiom": "iphone"
+ },
+ {
+ "orientation": "portrait",
+ "extent": "full-screen",
+ "minimum-system-version": "7.0",
+ "subtype": "retina4",
+ "scale": "2x",
+ "size": "640x1136",
+ "idiom": "iphone"
+ },
+ {
+ "orientation": "portrait",
+ "extent": "full-screen",
+ "minimum-system-version": "7.0",
+ "scale": "1x",
+ "size": "768x1024",
+ "idiom": "ipad"
+ },
+ {
+ "orientation": "landscape",
+ "extent": "full-screen",
+ "minimum-system-version": "7.0",
+ "scale": "1x",
+ "size": "1024x768",
+ "idiom": "ipad"
+ },
+ {
+ "orientation": "portrait",
+ "extent": "full-screen",
+ "minimum-system-version": "7.0",
+ "scale": "2x",
+ "size": "1536x2048",
+ "idiom": "ipad"
+ },
+ {
+ "orientation": "landscape",
+ "extent": "full-screen",
+ "minimum-system-version": "7.0",
+ "scale": "2x",
+ "size": "2048x1536",
+ "idiom": "ipad"
+ }
+ ],
+ "properties": {},
+ "info": {
+ "version": 1,
+ "author": ""
+ }
+}
\ No newline at end of file
diff --git a/src/dopesbench/dopesbench/Platforms/iOS/PrivacyInfo.xcprivacy b/src/dopesbench/dopesbench/Platforms/iOS/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000..902abb0
--- /dev/null
+++ b/src/dopesbench/dopesbench/Platforms/iOS/PrivacyInfo.xcprivacy
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategorySystemBootTime
+ NSPrivacyAccessedAPITypeReasons
+
+ 35F9.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryDiskSpace
+ NSPrivacyAccessedAPITypeReasons
+
+ E174.1
+
+
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
diff --git a/src/dopesbench/dopesbench/Properties/PublishProfiles/win-arm64.pubxml b/src/dopesbench/dopesbench/Properties/PublishProfiles/win-arm64.pubxml
new file mode 100644
index 0000000..5d5632a
--- /dev/null
+++ b/src/dopesbench/dopesbench/Properties/PublishProfiles/win-arm64.pubxml
@@ -0,0 +1,18 @@
+
+
+
+
+ FileSystem
+ arm64
+ win-arm64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+ False
+ True
+
+
diff --git a/src/dopesbench/dopesbench/Properties/PublishProfiles/win-x64.pubxml b/src/dopesbench/dopesbench/Properties/PublishProfiles/win-x64.pubxml
new file mode 100644
index 0000000..12b8344
--- /dev/null
+++ b/src/dopesbench/dopesbench/Properties/PublishProfiles/win-x64.pubxml
@@ -0,0 +1,18 @@
+
+
+
+
+ FileSystem
+ x64
+ win-x64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+ False
+ True
+
+
diff --git a/src/dopesbench/dopesbench/Properties/PublishProfiles/win-x86.pubxml b/src/dopesbench/dopesbench/Properties/PublishProfiles/win-x86.pubxml
new file mode 100644
index 0000000..65b8f1d
--- /dev/null
+++ b/src/dopesbench/dopesbench/Properties/PublishProfiles/win-x86.pubxml
@@ -0,0 +1,23 @@
+
+
+
+
+ FileSystem
+ x86
+ win-x86
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+ False
+ True
+
+
+
diff --git a/src/dopesbench/dopesbench/Random2.cs b/src/dopesbench/dopesbench/Random2.cs
new file mode 100644
index 0000000..04a5ac3
--- /dev/null
+++ b/src/dopesbench/dopesbench/Random2.cs
@@ -0,0 +1,136 @@
+using System;
+
+namespace Saplin.xOPS.UI.Misc
+{
+ // ==++==
+ //
+ // Copyright (c) Microsoft Corporation. All rights reserved.
+ //
+ // ==--==
+ /*============================================================
+ **
+ ** Class: Random
+ **
+ **
+ ** Purpose: A random number generator.
+ **
+ **
+ ===========================================================*/
+
+ ///
+ /// To have consistent behaviour of random generator across Runtimes (Mono, Core) and avoid changes to it in future releases src from Github repo is used instead of stock BCL class.
+ ///
+ public class Random2
+ {
+ //
+ // Private Constants
+ //
+ private const int MBIG = 2000000000;
+ private const int MSEED = 161803398;
+
+ //
+ // Member Variables
+ //
+ private int inext;
+ private int inextp;
+ private int[] SeedArray = new int[56];
+
+ //
+ // Public Constants
+ //
+
+ //
+ // Native Declarations
+ //
+
+ //
+ // Constructors
+ //
+
+ public Random2(int Seed)
+ {
+ int ii;
+ int mj, mk;
+
+ //Initialize our Seed array.
+ //This algorithm comes from Numerical Recipes in C (2nd Ed.)
+ int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed);
+ mj = MSEED - subtraction;
+ SeedArray[55] = mj;
+ mk = 1;
+ for (int i = 1; i < 55; i++)
+ { //Apparently the range [1..55] is special (Knuth) and so we're wasting the 0'th position.
+ ii = (21 * i) % 55;
+ SeedArray[ii] = mk;
+ mk = mj - mk;
+ if (mk < 0) mk += MBIG;
+ mj = SeedArray[ii];
+ }
+ for (int k = 1; k < 5; k++)
+ {
+ for (int i = 1; i < 56; i++)
+ {
+ SeedArray[i] -= SeedArray[1 + (i + 30) % 55];
+ if (SeedArray[i] < 0) SeedArray[i] += MBIG;
+ }
+ }
+ inext = 0;
+ inextp = 21;
+ }
+
+ //
+ // Package Private Methods
+ //
+
+ /*====================================Sample====================================
+ **Action: Return a new random number [0..1) and reSeed the Seed array.
+ **Returns: A double [0..1)
+ **Arguments: None
+ **Exceptions: None
+ ==============================================================================*/
+ protected virtual double Sample()
+ {
+ //Including this division at the end gives us significantly improved
+ //random number distribution.
+ return (InternalSample() * (1.0 / MBIG));
+ }
+
+ private int InternalSample()
+ {
+ int retVal;
+ int locINext = inext;
+ int locINextp = inextp;
+
+ if (++locINext >= 56) locINext = 1;
+ if (++locINextp >= 56) locINextp = 1;
+
+ retVal = SeedArray[locINext] - SeedArray[locINextp];
+
+ if (retVal == MBIG) retVal--;
+ if (retVal < 0) retVal += MBIG;
+
+ SeedArray[locINext] = retVal;
+
+ inext = locINext;
+ inextp = locINextp;
+
+ return retVal;
+ }
+
+ //
+ // Public Instance Methods
+ //
+
+ /*=====================================Next=====================================
+ **Returns: A double [0..1)
+ **Arguments: None
+ **Exceptions: None
+ ==============================================================================*/
+ public virtual double NextDouble()
+ {
+ return Sample();
+ }
+
+ }
+
+}
diff --git a/src/dopesbench/dopesbench/ReadMe.md b/src/dopesbench/dopesbench/ReadMe.md
new file mode 100644
index 0000000..93482da
--- /dev/null
+++ b/src/dopesbench/dopesbench/ReadMe.md
@@ -0,0 +1,7 @@
+# Getting Started
+
+Welcome to the Uno Platform!
+
+To discover how to get started with your new app: https://aka.platform.uno/get-started
+
+For more information on how to use the Uno.Sdk or upgrade Uno Platform packages in your solution: https://aka.platform.uno/using-uno-sdk
\ No newline at end of file
diff --git a/src/dopesbench/dopesbench/Services/Endpoints/DebugHandler.cs b/src/dopesbench/dopesbench/Services/Endpoints/DebugHandler.cs
new file mode 100644
index 0000000..e4d18d6
--- /dev/null
+++ b/src/dopesbench/dopesbench/Services/Endpoints/DebugHandler.cs
@@ -0,0 +1,41 @@
+namespace dopesbench.Services.Endpoints;
+
+internal class DebugHttpHandler : DelegatingHandler
+{
+ public DebugHttpHandler(HttpMessageHandler? innerHandler = null)
+ : base(innerHandler ?? new HttpClientHandler())
+ {
+ }
+
+ protected async override Task SendAsync(
+ HttpRequestMessage request,
+ CancellationToken cancellationToken)
+ {
+ var response = await base.SendAsync(request, cancellationToken);
+#if DEBUG
+ if (!response.IsSuccessStatusCode)
+ {
+ Console.Error.WriteLine("Unsuccessful API Call");
+ if (request.RequestUri is not null)
+ {
+ Console.Error.WriteLine($"{request.RequestUri} ({request.Method})");
+ }
+
+ foreach ((var key, var values) in request.Headers.ToDictionary(x => x.Key, x => string.Join(", ", x.Value)))
+ {
+ Console.Error.WriteLine($" {key}: {values}");
+ }
+
+ var content = request.Content is not null ? await request.Content.ReadAsStringAsync() : null;
+ if (!string.IsNullOrEmpty(content))
+ {
+ Console.Error.WriteLine(content);
+ }
+
+ // Uncomment to automatically break when an API call fails while debugging
+ // System.Diagnostics.Debugger.Break();
+ }
+#endif
+ return response;
+ }
+}
diff --git a/src/dopesbench/dopesbench/Services/StopWatchService.cs b/src/dopesbench/dopesbench/Services/StopWatchService.cs
new file mode 100644
index 0000000..33da861
--- /dev/null
+++ b/src/dopesbench/dopesbench/Services/StopWatchService.cs
@@ -0,0 +1,5 @@
+namespace dopesbench.Services;
+public class StopWatchService
+{
+
+}
diff --git a/src/dopesbench/dopesbench/Strings/en/Resources.resw b/src/dopesbench/dopesbench/Strings/en/Resources.resw
new file mode 100644
index 0000000..3036069
--- /dev/null
+++ b/src/dopesbench/dopesbench/Strings/en/Resources.resw
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ dopesbench-en
+
+
diff --git a/src/dopesbench/dopesbench/app.manifest b/src/dopesbench/dopesbench/app.manifest
new file mode 100644
index 0000000..97b014a
--- /dev/null
+++ b/src/dopesbench/dopesbench/app.manifest
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/src/dopesbench/dopesbench/dopesbench.csproj b/src/dopesbench/dopesbench/dopesbench.csproj
new file mode 100644
index 0000000..996d7ed
--- /dev/null
+++ b/src/dopesbench/dopesbench/dopesbench.csproj
@@ -0,0 +1,52 @@
+
+
+ true
+
+
+
+ net9.0-android;net9.0-ios;net9.0-browserwasm;net9.0-desktop
+
+ Exe
+ true
+
+
+ dopesbench
+ com.companyname.dopesbench
+ 1.0
+ 1
+ dopesbench
+ dopesbench powered by Uno Platform.
+
+
+
+ Xaml;
+ Essentials;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HomePage.xaml
+
+
+
+
+
+ MSBuild:Compile
+
+
+
+
+
+ MSBuild:Compile
+
+
+
diff --git a/src/dopesbench/global.json b/src/dopesbench/global.json
new file mode 100644
index 0000000..413f7b7
--- /dev/null
+++ b/src/dopesbench/global.json
@@ -0,0 +1,9 @@
+{
+ // To update the version of Uno please update the version of the Uno.Sdk here. See https://aka.platform.uno/upgrade-uno-packages for more information.
+ "msbuild-sdks": {
+ "Uno.Sdk": "6.0.134"
+ },
+ "sdk":{
+ "allowPrerelease": false
+ }
+}