├── .github
└── workflows
│ ├── msbuild.yml
│ └── publish.yml
├── .gitignore
├── .gitmodules
├── AppMarkup
├── AppMarkup.def
├── AppMarkup.vcxproj
├── AppMarkup.vcxproj.filters
├── BlankPage.cpp
├── BlankPage.h
├── BlankPage.idl
├── BlankPage.xaml
├── PropertySheet.props
├── packages.config
├── pch.cpp
├── pch.h
└── readme.txt
├── CppXAMLSample
├── MarkupSample
│ ├── MainPage.idl
│ ├── MainPage.xaml
│ ├── MainPage.xaml.cpp
│ ├── MainPage.xaml.h
│ ├── MarkupSample.def
│ ├── MarkupSample.vcxproj
│ ├── MarkupSample.vcxproj.filters
│ ├── ModalPage.cpp
│ ├── ModalPage.h
│ ├── ModalPage.idl
│ ├── ModalPage.xaml
│ ├── PropertySheet.props
│ ├── ServiceVM.xaml
│ ├── assets
│ │ └── skulogo2_client.png
│ ├── packages.config
│ ├── pch.cpp
│ └── pch.h
├── Sample.sln
├── XamlIslandsSample
│ ├── Application.manifest
│ ├── Resource.h
│ ├── WindowsProject1.cpp
│ ├── WindowsProject1.ico
│ ├── WindowsProject1.rc
│ ├── WindowsProject1.vcxproj
│ ├── WindowsProject1.vcxproj.filters
│ ├── framework.h
│ ├── packages.config
│ ├── pri.resfiles
│ ├── priconfig.xml
│ └── small.ico
├── build.ps1
└── fixUpPRIFileList.ps1
├── Doxyfile
├── LICENSE
├── LICENSE.txt
├── Playground
├── Application.manifest
├── Playground.sln
├── Playground.vcxproj
├── Resource.h
├── WindowsProject1.cpp
├── WindowsProject1.h
├── WindowsProject1.ico
├── WindowsProject1.rc
├── WindowsProject1.vcxproj.filters
├── framework.h
├── packages.config
├── pch.h
├── small.ico
└── targetver.h
├── Unpackaged.nuspec
├── build
└── Unpackaged.targets
├── docs
├── README.md
└── img
│ └── VSM.gif
├── inc
├── XamlApplication.h
├── XamlApplication.idl
├── cppxaml
│ ├── Controls.h
│ ├── InitializeWithWindow.h
│ ├── VisualState.h
│ ├── XamlProperty.h
│ ├── XamlWindow.h
│ └── utils.h
├── per-monitor-v2.manifest
└── xaml-islands.manifest
├── readme.md
├── wap
├── Images
│ ├── LockScreenLogo.scale-200.png
│ ├── SplashScreen.scale-200.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── StoreLogo.png
│ └── Wide310x150Logo.scale-200.png
├── Package.appxmanifest
└── WapProjTemplate1.wapproj
└── win32
├── Application.manifest
├── Resource.h
├── WindowsProject1.cpp
├── WindowsProject1.h
├── WindowsProject1.ico
├── WindowsProject1.rc
├── WindowsProject1.sln
├── WindowsProject1.vcxproj
├── WindowsProject1.vcxproj.filters
├── build.cmd
├── framework.h
├── packages.config
├── pri.resfiles
├── priconfig.xml
├── small.ico
└── targetver.h
/.github/workflows/msbuild.yml:
--------------------------------------------------------------------------------
1 | name: MSBuild
2 |
3 | on: [push]
4 |
5 | env:
6 | # Path to the solution file relative to the root of the project.
7 | SOLUTION_FILE_PATH: Playground\Playground.sln
8 |
9 | # Configuration type to build.
10 | # You can convert this to a build matrix if you need coverage of multiple configuration types.
11 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
12 | BUILD_CONFIGURATION: Release
13 |
14 | jobs:
15 | build:
16 | runs-on: windows-2022
17 |
18 | steps:
19 | - uses: actions/checkout@v2
20 |
21 | - name: Add MSBuild to PATH
22 | uses: microsoft/setup-msbuild@v1.0.2
23 |
24 | - name: Make local NuGet package
25 | run: nuget pack
26 |
27 | - name: Add local NuGet feed
28 | run: nuget sources Add -Name xamlIslandsPlayground -Source .
29 |
30 | - name: List NuGet feeds
31 | run: nuget sources list
32 |
33 | - name: Push NuGet package
34 | run: nuget push Unpackaged*.nupkg -ApiKey api -Source xamlIslandsPlayground
35 |
36 | - name: Restore NuGet packages
37 | working-directory: ${{env.GITHUB_WORKSPACE}}
38 | run: nuget restore ${{env.SOLUTION_FILE_PATH}}
39 |
40 | - name: Build
41 | working-directory: ${{env.GITHUB_WORKSPACE}}
42 | # Add additional options to the MSBuild command line here (like platform or verbosity level).
43 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
44 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} /p:RestorePackagesConfig=true /restore
45 |
46 | cppxaml:
47 | runs-on: windows-2022
48 |
49 | steps:
50 | - uses: actions/checkout@v2
51 |
52 | - name: Add MSBuild to PATH
53 | uses: microsoft/setup-msbuild@v1.0.2
54 |
55 | - name: Restore NuGet packages
56 | working-directory: ${{env.GITHUB_WORKSPACE}}
57 | run: nuget restore CppXAMLSample\Sample.sln
58 |
59 | - name: Fix up PRI file list
60 | working-directory: CppXAMLSample
61 | run: .\fixUpPRIFileList.ps1 -Arch x64 -Config Release
62 |
63 | - name: Build
64 | working-directory: ${{env.GITHUB_WORKSPACE}}
65 | # Add additional options to the MSBuild command line here (like platform or verbosity level).
66 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
67 | run: msbuild /m /p:Platform=x64 /p:Configuration=${{env.BUILD_CONFIGURATION}} CppXAMLSample\Sample.sln /p:RestorePackagesConfig=true /restore /p:UseLocalInc=true
68 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Publish
4 |
5 | # Controls when the workflow will run
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the main branch
8 | push:
9 | branches: [ main ]
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
15 | jobs:
16 | docs:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: actions/checkout@v2
20 | with:
21 | submodules: true
22 |
23 | - name: Doxygen Action
24 | uses: mattnotmitt/doxygen-action@v1.1.0
25 | with:
26 | # Path to Doxyfile
27 | doxyfile-path: "./Doxyfile" # default is ./Doxyfile
28 | # Working directory
29 | working-directory: "." # default is .
30 |
31 | - name: Deploy
32 | uses: peaceiris/actions-gh-pages@v3
33 | with:
34 | github_token: ${{ secrets.GITHUB_TOKEN }}
35 | # Default Doxyfile build documentation to html directory.
36 | # Change the directory if changes in Doxyfile
37 | publish_dir: ./docs/html
38 |
39 | nuget:
40 | # The type of runner that the job will run on
41 | runs-on: windows-latest
42 |
43 | steps:
44 | - uses: actions/checkout@v2
45 | with:
46 | submodules: true
47 |
48 | - name: pack
49 | run: |
50 | nuget pack
51 | nuget push Unpackaged*.nupkg -Source nuget.org -ApiKey ${{secrets.NUGET_TOKEN}}
52 |
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
352 | docs/html
353 | docs/latex
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "doxygen-awesome-css"]
2 | path = doxygen-awesome-css
3 | url = https://github.com/jothepro/doxygen-awesome-css.git
4 |
--------------------------------------------------------------------------------
/AppMarkup/AppMarkup.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 | DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
3 | DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
4 |
--------------------------------------------------------------------------------
/AppMarkup/AppMarkup.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | true
6 | true
7 | true
8 | true
9 | {dbc3872e-0bbe-4ea0-9b0a-1331d81d8449}
10 | AppMarkup
11 | AppMarkup
12 | en-US
13 | 14.0
14 | true
15 | Windows Store
16 | 10.0
17 | 10.0.19041.0
18 | 10.0.17134.0
19 |
20 |
21 |
22 |
23 | Debug
24 | ARM
25 |
26 |
27 | Debug
28 | ARM64
29 |
30 |
31 | Debug
32 | Win32
33 |
34 |
35 | Debug
36 | x64
37 |
38 |
39 | Release
40 | ARM
41 |
42 |
43 | Release
44 | ARM64
45 |
46 |
47 | Release
48 | Win32
49 |
50 |
51 | Release
52 | x64
53 |
54 |
55 |
56 | DynamicLibrary
57 | v143
58 | v142
59 | v141
60 | v140
61 | Unicode
62 | false
63 |
64 |
65 | true
66 | true
67 |
68 |
69 | false
70 | true
71 | false
72 |
73 |
74 | true
75 |
76 |
77 | true
78 |
79 |
80 | true
81 |
82 |
83 | true
84 |
85 |
86 | true
87 |
88 |
89 | true
90 |
91 |
92 | true
93 |
94 |
95 | true
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | Use
113 | pch.h
114 | $(IntDir)pch.pch
115 | Level4
116 | %(AdditionalOptions) /bigobj
117 |
118 | /DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)
119 | _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)
120 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)
121 |
122 |
123 | Console
124 | false
125 | AppMarkup.def
126 |
127 |
128 |
129 |
130 | _DEBUG;%(PreprocessorDefinitions)
131 |
132 |
133 |
134 |
135 | NDEBUG;%(PreprocessorDefinitions)
136 |
137 |
138 | true
139 | true
140 |
141 |
142 |
143 |
144 | BlankPage.xaml
145 | Code
146 |
147 |
148 |
149 |
150 |
151 | BlankPage.xaml
152 | Code
153 |
154 |
155 | Create
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 | false
167 |
168 |
169 |
170 |
171 | Designer
172 |
173 |
174 |
175 |
176 | BlankPage.xaml
177 | Code
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/AppMarkup/AppMarkup.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | accd3aa8-1ba0-4223-9bbe-0c431709210b
6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms
7 |
8 |
9 | {926ab91d-31b4-48c3-b9a4-e681349f27f0}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/AppMarkup/BlankPage.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "BlankPage.h"
3 | #if __has_include("BlankPage.g.cpp")
4 | #include "BlankPage.g.cpp"
5 | #endif
6 |
7 | using namespace winrt;
8 | using namespace Windows::UI::Xaml;
9 |
10 | namespace winrt::AppMarkup::implementation
11 | {
12 | BlankPage::BlankPage()
13 | {
14 | InitializeComponent();
15 | }
16 |
17 | int32_t BlankPage::MyProperty()
18 | {
19 | throw hresult_not_implemented();
20 | }
21 |
22 | void BlankPage::MyProperty(int32_t /* value */)
23 | {
24 | throw hresult_not_implemented();
25 | }
26 |
27 | void BlankPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
28 | {
29 | Button().Content(box_value(L"Clicked"));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/AppMarkup/BlankPage.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "BlankPage.g.h"
4 |
5 | namespace winrt::AppMarkup::implementation
6 | {
7 | struct BlankPage : BlankPageT
8 | {
9 | BlankPage();
10 |
11 | int32_t MyProperty();
12 | void MyProperty(int32_t value);
13 |
14 | void ClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
15 | };
16 | }
17 |
18 | namespace winrt::AppMarkup::factory_implementation
19 | {
20 | struct BlankPage : BlankPageT
21 | {
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/AppMarkup/BlankPage.idl:
--------------------------------------------------------------------------------
1 | namespace AppMarkup
2 | {
3 | [default_interface]
4 | runtimeclass BlankPage : Windows.UI.Xaml.Controls.Page
5 | {
6 | BlankPage();
7 | Int32 MyProperty;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/AppMarkup/BlankPage.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/AppMarkup/PropertySheet.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/AppMarkup/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/AppMarkup/pch.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
--------------------------------------------------------------------------------
/AppMarkup/pch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
--------------------------------------------------------------------------------
/AppMarkup/readme.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | C++/WinRT AppMarkup Project Overview
3 | ========================================================================
4 |
5 | This project demonstrates how to get started authoring Windows Runtime
6 | classes directly with standard C++, using the C++/WinRT SDK component
7 | to generate implementation headers from interface (IDL) files. The
8 | generated Windows Runtime component binary and WinMD files should then
9 | be bundled with the Universal Windows Platform (UWP) app consuming them.
10 |
11 | Steps:
12 | 1. Create an interface (IDL) file to define your Windows Runtime class,
13 | its default interface, and any other interfaces it implements.
14 | 2. Build the project once to generate module.g.cpp, module.h.cpp, and
15 | implementation templates under the "Generated Files" folder, as
16 | well as skeleton class definitions under "Generated Files\sources".
17 | 3. Use the skeleton class definitions for reference to implement your
18 | Windows Runtime classes.
19 |
20 | ========================================================================
21 | Learn more about C++/WinRT here:
22 | http://aka.ms/cppwinrt/
23 | ========================================================================
24 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/MainPage.idl:
--------------------------------------------------------------------------------
1 |
2 | namespace MarkupSample
3 | {
4 |
5 | runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
6 | {
7 | MainPage();
8 |
9 | String InterfaceStr;
10 | String ImplString{ get; };
11 | Windows.UI.Xaml.Controls.Button OkButton;
12 | Windows.UI.Xaml.Documents.Hyperlink Link{ get; };
13 |
14 | Int32 MyInt{ get; set; };
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
19 |
20 | CppXAML island sample
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/MainPage.xaml.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "MainPage.xaml.h"
3 | #if __has_include("MainPage.g.cpp")
4 | #include "MainPage.g.cpp"
5 | #endif
6 |
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #undef max
17 |
18 | namespace winrt {
19 | using namespace Microsoft::UI::Xaml;
20 | using namespace Windows::UI::Xaml::Controls;
21 | }
22 | namespace xaml = winrt::Windows::UI::Xaml;
23 |
24 | using namespace std::chrono;
25 | // To learn more about WinUI, the WinUI project structure,
26 | // and more about our project templates, see: http://aka.ms/winui-project-info.
27 |
28 |
29 | namespace winrt::MarkupSample::implementation
30 | {
31 | MainPage::MainPage() : INIT_PROPERTY(MyInt, 42)
32 | {
33 | InitializeComponent();
34 | // Properties can be assigned to and read from with the operator= too!
35 | ImplString = winrt::hstring{ L"This string comes from the implementation" };
36 | winrt::hstring v = ImplString;
37 | BuildUIProgrammatically();
38 | }
39 |
40 | void MainPage::BuildUIProgrammatically() {
41 | std::wstring paraStr{ L"This string was created at runtime in code. Here is a link that opens a modal window." };
42 | size_t i = 0;
43 | while (i < paraStr.length()) {
44 | auto anchorStart = paraStr.find(L"", 0);
45 | if (anchorStart > i) {
46 | xaml::Documents::Run run;
47 | run.Text(paraStr.substr(i, anchorStart - i));
48 | rtbParagraph().Inlines().Append(run);
49 | auto textStart = anchorStart + std::size(L"") - 1;
50 | auto anchorEnd = paraStr.find(L"", textStart);
51 | if (anchorEnd > anchorStart) {
52 | xaml::Documents::Run linkText;
53 | linkText.Text(paraStr.substr(textStart, anchorEnd - textStart));
54 | assert(m_hl == nullptr);
55 | m_hl = winrt::Windows::UI::Xaml::Documents::Hyperlink();
56 | m_hl.Inlines().Append(linkText);
57 | rtbParagraph().Inlines().Append(m_hl);
58 | i = anchorEnd + std::size(L"") - 1;
59 | }
60 | }
61 | else {
62 | xaml::Documents::Run run;
63 | run.Text(paraStr.substr(i));
64 | rtbParagraph().Inlines().Append(run);
65 | break;
66 | }
67 | }
68 |
69 | }
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/MainPage.xaml.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "cppxaml/XAMLProperty.h"
7 | #include "MainPage.g.h"
8 |
9 |
10 | namespace winrt::MarkupSample::implementation
11 | {
12 |
13 |
14 | struct MainPage : MainPageT, cppxaml::SimpleNotifyPropertyChanged
15 | {
16 | MainPage();
17 | cppxaml::XamlProperty InterfaceStr;
18 | cppxaml::XamlProperty ImplString;
19 |
20 | cppxaml::XamlPropertyWithNPC MyInt;
21 | auto Link() const {
22 | return m_hl;
23 | }
24 | private:
25 | void BuildUIProgrammatically();
26 | std::wstring m_EvaluationStrTemplate;
27 | winrt::Windows::UI::Xaml::Documents::Hyperlink m_hl{nullptr};
28 | };
29 | }
30 |
31 | namespace winrt::MarkupSample::factory_implementation
32 | {
33 | struct MainPage : MainPageT
34 | {
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/MarkupSample.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 | DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
3 | DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
4 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/MarkupSample.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | accd3aa8-1ba0-4223-9bbe-0c431709210b
6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms
7 |
8 |
9 | {926ab91d-31b4-48c3-b9a4-e681349f27f0}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Resources
33 |
34 |
35 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/ModalPage.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "ModalPage.h"
3 | #if __has_include("ModalPage.g.cpp")
4 | #include "ModalPage.g.cpp"
5 | #endif
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | using namespace winrt;
12 | using namespace Windows::UI::Xaml;
13 |
14 | namespace winrt::MarkupSample::implementation
15 | {
16 | ModalPage::ModalPage()
17 | {
18 | InitializeComponent();
19 | }
20 | }
21 |
22 | void winrt::MarkupSample::implementation::ModalPage::Page_KeyUp(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
23 | {
24 | if (e.Key() == Windows::System::VirtualKey::Escape) {
25 | OkClicked.invoke(*this, L"");
26 | }
27 | }
28 |
29 |
30 | void winrt::MarkupSample::implementation::ModalPage::Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
31 | {
32 | OkClicked.invoke(*this, L"");
33 | }
34 |
35 |
36 | void winrt::MarkupSample::implementation::ModalPage::WebView_Loaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
37 | {
38 | //sender.as().Navigate(Windows::Foundation::Uri{ L"https://bing.com" });
39 | }
40 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/ModalPage.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "ModalPage.g.h"
4 | #include "cppxaml/XAMLProperty.h"
5 |
6 | namespace winrt::MarkupSample::implementation
7 | {
8 | struct ModalPage : ModalPageT
9 | {
10 | ModalPage();
11 |
12 | cppxaml::TypedXamlEvent OkClicked;
13 |
14 | void Page_KeyUp(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
15 | void Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
16 |
17 | void WebView_Loaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
18 | };
19 | }
20 |
21 | namespace winrt::MarkupSample::factory_implementation
22 | {
23 | struct ModalPage : ModalPageT
24 | {
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/ModalPage.idl:
--------------------------------------------------------------------------------
1 | namespace MarkupSample
2 | {
3 | [default_interface]
4 | runtimeclass ModalPage : Windows.UI.Xaml.Controls.Page
5 | {
6 | ModalPage();
7 |
8 | event Windows.Foundation.TypedEventHandler OkClicked;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/ModalPage.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/PropertySheet.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/ServiceVM.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/assets/skulogo2_client.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/CppXAMLSample/MarkupSample/assets/skulogo2_client.png
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/pch.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
--------------------------------------------------------------------------------
/CppXAMLSample/MarkupSample/pch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #undef GetCurrentTime
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
--------------------------------------------------------------------------------
/CppXAMLSample/Sample.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31912.275
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XamlIslandsSample", "XamlIslandsSample\WindowsProject1.vcxproj", "{1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MarkupSample", "MarkupSample\MarkupSample.vcxproj", "{DEC83DBE-36DF-4102-A195-B98CBB92844A}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CppXAML", "CppXAML", "{942DF2BD-662B-417D-88F9-AE7DFFB1A3A2}"
11 | ProjectSection(SolutionItems) = preProject
12 | ..\inc\cppxaml\Controls.h = ..\inc\cppxaml\Controls.h
13 | ..\docs\README.md = ..\docs\README.md
14 | ..\Unpackaged.nuspec = ..\Unpackaged.nuspec
15 | ..\inc\cppxaml\utils.h = ..\inc\cppxaml\utils.h
16 | ..\inc\cppxaml\VisualState.h = ..\inc\cppxaml\VisualState.h
17 | ..\inc\cppxaml\XamlProperty.h = ..\inc\cppxaml\XamlProperty.h
18 | ..\inc\cppxaml\XamlWindow.h = ..\inc\cppxaml\XamlWindow.h
19 | EndProjectSection
20 | EndProject
21 | Global
22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
23 | Debug|ARM = Debug|ARM
24 | Debug|ARM64 = Debug|ARM64
25 | Debug|x64 = Debug|x64
26 | Debug|x86 = Debug|x86
27 | Release|ARM = Release|ARM
28 | Release|ARM64 = Release|ARM64
29 | Release|x64 = Release|x64
30 | Release|x86 = Release|x86
31 | EndGlobalSection
32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
33 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|ARM.ActiveCfg = Debug|x64
34 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|ARM.Build.0 = Debug|x64
35 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|ARM64.ActiveCfg = Debug|Win32
36 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x64.ActiveCfg = Debug|x64
37 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x64.Build.0 = Debug|x64
38 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x86.ActiveCfg = Debug|Win32
39 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x86.Build.0 = Debug|Win32
40 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|ARM.ActiveCfg = Release|x64
41 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|ARM.Build.0 = Release|x64
42 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|ARM64.ActiveCfg = Release|Win32
43 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x64.ActiveCfg = Release|x64
44 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x64.Build.0 = Release|x64
45 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x86.ActiveCfg = Release|Win32
46 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x86.Build.0 = Release|Win32
47 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|ARM.ActiveCfg = Debug|ARM
48 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|ARM.Build.0 = Debug|ARM
49 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|ARM64.ActiveCfg = Debug|ARM64
50 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|ARM64.Build.0 = Debug|ARM64
51 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|x64.ActiveCfg = Debug|x64
52 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|x64.Build.0 = Debug|x64
53 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|x86.ActiveCfg = Debug|Win32
54 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Debug|x86.Build.0 = Debug|Win32
55 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|ARM.ActiveCfg = Release|ARM
56 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|ARM.Build.0 = Release|ARM
57 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|ARM64.ActiveCfg = Release|ARM64
58 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|ARM64.Build.0 = Release|ARM64
59 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|x64.ActiveCfg = Release|x64
60 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|x64.Build.0 = Release|x64
61 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|x86.ActiveCfg = Release|Win32
62 | {DEC83DBE-36DF-4102-A195-B98CBB92844A}.Release|x86.Build.0 = Release|Win32
63 | EndGlobalSection
64 | GlobalSection(SolutionProperties) = preSolution
65 | HideSolutionNode = FALSE
66 | EndGlobalSection
67 | GlobalSection(ExtensibilityGlobals) = postSolution
68 | SolutionGuid = {80872FBF-05BC-4620-BF8A-A9289BADB0EE}
69 | EndGlobalSection
70 | EndGlobal
71 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/Application.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
43 |
44 |
45 | PerMonitorV2
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/Resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by WindowsProject1.rc
4 |
5 | #define IDS_APP_TITLE 103
6 |
7 | #define IDR_MAINFRAME 128
8 | #define IDD_WINDOWSPROJECT1_DIALOG 102
9 | #define IDD_ABOUTBOX 103
10 | #define IDM_ABOUT 104
11 | #define IDM_EXIT 105
12 | #define IDI_WINDOWSPROJECT1 107
13 | #define IDI_SMALL 108
14 | #define IDC_WINDOWSPROJECT1 109
15 | #define IDC_MYICON 2
16 | #ifndef IDC_STATIC
17 | #define IDC_STATIC -1
18 | #endif
19 | // Next default values for new objects
20 | //
21 | #ifdef APSTUDIO_INVOKED
22 | #ifndef APSTUDIO_READONLY_SYMBOLS
23 |
24 | #define _APS_NO_MFC 130
25 | #define _APS_NEXT_RESOURCE_VALUE 129
26 | #define _APS_NEXT_COMMAND_VALUE 32771
27 | #define _APS_NEXT_CONTROL_VALUE 1000
28 | #define _APS_NEXT_SYMED_VALUE 110
29 | #endif
30 | #endif
31 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/WindowsProject1.cpp:
--------------------------------------------------------------------------------
1 | // WindowsProject1.cpp : Defines the entry point for the application.
2 | //
3 |
4 | #include "framework.h"
5 | #include "resource.h"
6 |
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #include "XamlApplication.h"
24 |
25 | using namespace winrt;
26 | using namespace Windows::UI::Xaml::Controls;
27 | using namespace Windows::UI::Xaml;
28 | using namespace Windows::UI::Xaml::Hosting;
29 |
30 |
31 | std::vector fontNames{};
32 |
33 | auto GetFontFamilies() {
34 | if (fontNames.size() == 0) {
35 | auto hDC = GetDC(nullptr);
36 | LOGFONT lf{};
37 | lf.lfCharSet = DEFAULT_CHARSET;
38 | int nRet = EnumFontFamiliesEx(hDC, &lf, [](const LOGFONT* lf, const TEXTMETRIC* tm, DWORD fontType, LPARAM lParam) {
39 | auto& _names = *(std::vector*)lParam;
40 | if (std::find(_names.begin(), _names.end(), lf->lfFaceName) == _names.end()) {
41 | _names.push_back(lf->lfFaceName);
42 | }
43 | return 1;
44 | }, (LPARAM)&fontNames, 0);
45 |
46 | ReleaseDC(nullptr, hDC);
47 | }
48 |
49 | return fontNames;
50 | }
51 |
52 | winrt::fire_and_forget CreateCppXamlUI(const cppxaml::XamlWindow* xw) {
53 | auto v = std::vector{ 1,2,3 };
54 | auto w = cppxaml::utils::transform(v, [](const int& t) { return t; });
55 | auto z = cppxaml::utils::transform_with_index(v, [](const int& t, std::vector::const_iterator::difference_type dt) { return t + dt; });
56 |
57 |
58 | auto gl = cppxaml::details::GridLength2(10);
59 | auto gl2 = cppxaml::details::GridLength2("*");
60 | auto gl3 = cppxaml::details::GridLength2("Auto");
61 | auto gl4 = cppxaml::details::GridLength2("2*");
62 |
63 | auto gc = cppxaml::details::GridColumns({ 10, 20 });
64 | auto gc2 = cppxaml::details::GridColumns({ 10, {"*"}, {"Auto"} });
65 |
66 | auto gr = cppxaml::details::GridRows("10, 20, *");
67 | auto gr2 = cppxaml::details::GridRows{ "10, 20, *, Auto" };
68 | auto gr3 = cppxaml::details::GridRows{ 10, 20, {"*"}, {"Auto"} };
69 |
70 | auto strs = std::vector{ L"first", L"second", L"third", L"fourth" };
71 |
72 | auto lambda = [](const std::wstring& t, std::vector::const_iterator::difference_type index) {
73 | return cppxaml::details::UIElementInGrid{
74 | (int)index / 2,
75 | (int)index % 2,
76 | cppxaml::Button(winrt::hstring(t))
77 | };
78 | };
79 |
80 | auto button = cppxaml::Button(L"click me")
81 | .VisualStates( {
82 | { L"PointerOver", [](auto&sender, cppxaml::xaml::VisualStateChangedEventArgs args) {
83 | auto x = args.NewState().Name();
84 | auto button = sender.as();
85 | button.Content(winrt::box_value(x));
86 | } },
87 | { L"Normal", [](auto&sender, auto&) {
88 | auto button = sender.as();
89 | button.Content(winrt::box_value(L"click me"));
90 | } },
91 | { L"Pressed", [](auto& sender, auto&) {
92 | auto button = sender.as();
93 | button.Content(winrt::box_value(L"pressed"));
94 | } },
95 | });
96 |
97 | auto tb = cppxaml::TextBlock(L"something")
98 | .Set(Controls::Grid::RowProperty(), 1)
99 | .Set(Controls::Grid::ColumnSpanProperty(), 2);
100 |
101 | auto sv = cppxaml::MakeContentControl({
102 | cppxaml::StackPanel({
103 | button,
104 | cppxaml::Grid(
105 | {"40, *"}, {"Auto, Auto"},
106 | cppxaml::utils::transform_with_index(strs,
107 | [](const std::wstring& t, auto index) {
108 | return cppxaml::details::UIElementInGrid{
109 | (int)index / 2,
110 | (int)index % 2,
111 | cppxaml::Button(winrt::hstring(t))
112 | };
113 | })
114 | ),
115 | //cppxaml::details::Wrapper().Name(L"cp"),
116 | cppxaml::AutoSuggestBox(GetFontFamilies())
117 | .EnableDefaultSearch()
118 | .Margin(0, 16, 0, 4)
119 | .Name(L"fontTB"),
120 | }).Orientation(Controls::Orientation::Vertical).Name(L"stackpanel")
121 | });
122 |
123 | auto cd = cppxaml::ContentDialog(sv).PrimaryButtonText(L"Ok");
124 |
125 | cd->Loaded([sv](auto&...) {
126 | auto stackpanel = cppxaml::FindChildByName< Controls::StackPanel>(sv, L"stackpanel");
127 | stackpanel = sv->FindName(L"stackpanel").as();
128 |
129 | });
130 | auto fontTB = cppxaml::FindChildByName(*cd, L"fontTB");
131 |
132 | cppxaml::InitializeWithWindow(cd, xw);
133 | auto res = co_await cd->ShowAsync();
134 | if (res == cppxaml::xaml::Controls::ContentDialogResult::Primary) {
135 | fontTB = cppxaml::FindChildByName(*cd, L"fontTB");
136 | auto fontName = fontTB.Text();
137 | }
138 |
139 | }
140 |
141 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
142 | _In_opt_ HINSTANCE hPrevInstance,
143 | _In_ LPWSTR lpCmdLine,
144 | _In_ int nCmdShow)
145 | {
146 | winrt::init_apartment(winrt::apartment_type::single_threaded);
147 |
148 | auto winuiIXMP = winrt::Microsoft::UI::Xaml::XamlTypeInfo::XamlControlsXamlMetaDataProvider();
149 | auto markupIXMP = winrt::MarkupSample::XamlMetaDataProvider();
150 |
151 | auto xapp = winrt::make_application(winuiIXMP, markupIXMP);
152 |
153 | cppxaml::AppController controller(hInstance, xapp);
154 |
155 | controller.OnUICreated = [](UIElement page, cppxaml::XamlWindow* xw) {
156 | if (auto mainPage = page.try_as()) {
157 | assert(xw->Id() == L"MarkupSample");
158 | mainPage.InterfaceStr(L"This string comes from the win32 app");
159 |
160 | mainPage.Link().Click([](auto&...) {
161 |
162 | auto& modalWindow = cppxaml::XamlWindow::Get(L"Modal");
163 | auto& mainWindow = cppxaml::XamlWindow::Get(L"MarkupSample");
164 |
165 | CreateCppXamlUI(&mainWindow);
166 |
167 |
168 | modalWindow.Create(L"Modal", 0 /*WS_POPUPWINDOW*/, mainWindow.hwnd(), 600 * GetDpiForSystem() / 96, 600 * GetDpiForSystem() / 96);
169 | EnableWindow(mainWindow.hwnd(), FALSE);
170 | });
171 |
172 | mainPage.OkButton().Tapped([xw, mainPage](Windows::Foundation::IInspectable, auto&) {
173 |
174 | auto menuFlyout = cppxaml::MenuFlyout(
175 | cppxaml::MenuFlyoutItem(L"Exit")
176 | .IconElement(cppxaml::FontIcon(0xe8bb))
177 | .Click([hwnd = xw->hwnd()](auto&...) {
178 | DestroyWindow(hwnd);
179 | }),
180 |
181 | cppxaml::MenuFlyoutItem(L"Cancel")
182 | .IconElement(cppxaml::FontIcon(L"\xE8A7"))
183 | )
184 | .CentralizedHandler([](Windows::Foundation::IInspectable sender, auto&) {
185 | auto mfi = sender.as();
186 | auto x = mfi.Text();
187 | });
188 |
189 | cppxaml::InitializeWithWindow(menuFlyout, mainPage);
190 | // menuFlyout->ShowAt(mainPage.OkButton());
191 | DestroyWindow(xw->hwnd());
192 | });
193 | }
194 | else if (auto modalPage = page.try_as()) {
195 | assert(xw->Id() == L"Modal");
196 | modalPage.OkClicked([xw](auto&...) {
197 | DestroyWindow(xw->hwnd());
198 | SetFocus(cppxaml::XamlWindow::Get(L"MarkupSample").hwnd());
199 | });
200 | }
201 | };
202 |
203 | controller.WndProc =
204 | [](HWND hWnd, INT message, WPARAM wParam, LPARAM lParam, cppxaml::XamlWindow* xw) -> LRESULT {
205 | switch (message) {
206 | case WM_CREATE: {
207 | auto hInstance = xw->Controller()->HInstance();
208 | auto smallIcon = LoadIconW(hInstance, MAKEINTRESOURCE(IDI_SMALL));
209 | assert(smallIcon != nullptr);
210 | SendMessageW(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)smallIcon);
211 | auto bigIcon = LoadIconW(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));
212 | assert(bigIcon != nullptr);
213 | SendMessageW(hWnd, WM_SETICON, ICON_BIG, (LPARAM)bigIcon);
214 | return 0;
215 | break;
216 | }
217 | case WM_KEYUP: {
218 | if (xw->Id() == L"Modal" && wParam == VK_ESCAPE) {
219 | DestroyWindow(xw->hwnd());
220 | SetFocus(cppxaml::XamlWindow::Get(L"MarkupSample").hwnd());
221 | return 0;
222 | }
223 | break;
224 | }
225 | case WM_DESTROY:
226 | if (xw->Id() == L"MarkupSample") {
227 | PostQuitMessage(0);
228 | }
229 | else if (xw->Id() == L"Modal") {
230 | EnableWindow(cppxaml::XamlWindow::Get(L"MarkupSample").hwnd(), TRUE);
231 | }
232 | break;
233 | }
234 | return DefWindowProcW(hWnd, message, wParam, lParam);
235 | };
236 |
237 | xapp.Resources().MergedDictionaries().Append(winrt::Microsoft::UI::Xaml::Controls::XamlControlsResources());
238 | auto& mainWindow = cppxaml::XamlWindow::Make(L"MarkupSample", &controller);
239 | auto& modalWindow = cppxaml::XamlWindow::Make(L"Modal", &controller);
240 |
241 | HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
242 | mainWindow.SetAcceleratorTable(hAccelTable);
243 |
244 | wchar_t szTitle[100]; // The title bar text
245 | LoadStringW(hInstance, IDS_APP_TITLE, szTitle, static_cast(std::size(szTitle)));
246 | HWND hWnd = mainWindow.Create(szTitle, WS_OVERLAPPEDWINDOW, nullptr, 660, 880, nCmdShow);
247 | if (!hWnd)
248 | {
249 | return FALSE;
250 | }
251 |
252 | return mainWindow.RunLoop();
253 | }
254 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/WindowsProject1.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/CppXAMLSample/XamlIslandsSample/WindowsProject1.ico
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/WindowsProject1.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/CppXAMLSample/XamlIslandsSample/WindowsProject1.rc
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/WindowsProject1.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 |
26 |
27 | Source Files
28 |
29 |
30 |
31 |
32 | Resource Files
33 |
34 |
35 |
36 |
37 | Resource Files
38 |
39 |
40 | Resource Files
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/framework.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
4 |
5 | // Windows Header Files
6 | #include
7 | // C RunTime Header Files
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #undef GetCurrentTime
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/pri.resfiles:
--------------------------------------------------------------------------------
1 | ..\x64\Debug\MarkupSample\MarkupSample.pri
2 | ..\packages\Microsoft.UI.Xaml.2.8.0-prerelease.210927001\runtimes\win10-x64\native\Microsoft.UI.Xaml.pri
3 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/priconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/CppXAMLSample/XamlIslandsSample/small.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/CppXAMLSample/XamlIslandsSample/small.ico
--------------------------------------------------------------------------------
/CppXAMLSample/build.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param (
3 | [ValidateSet('x64', 'x86')]
4 | [string]
5 | $Arch = [ArchTypeEnum]::x64,
6 | [ValidateSet('Debug', 'Release')]
7 | [string]
8 | $Config = [Config]::Release
9 | )
10 |
11 | enum ArchTypeEnum {
12 | x64
13 | x86
14 | }
15 |
16 | enum Config {
17 | Debug
18 | Release
19 | }
20 |
21 | Write-Host Building $Arch $Config -ForegroundColor Green
22 |
23 | try {
24 | $msbuild = Get-Command msbuild.exe
25 | } catch {}
26 |
27 | if ($null -eq $msbuild) {
28 | Write-Host Must run this in a VS dev cmd
29 | return
30 | }
31 |
32 | & nuget restore $PWD
33 | & msbuild $PWD\MarkupSample.sln /p:Platform=$Arch /p:Configuration=$Config /p:RestorePackagesConfig=true /restore /bl
34 | $resources = @(
35 | "..\$Arch\$Config\MarkupSample\MarkupSample.pri",
36 | "..\packages\Microsoft.UI.Xaml.2.8.0-prerelease.210927001\runtimes\win10-x64\native\Microsoft.UI.Xaml.pri"
37 | )
38 | Write-Output $resources | Out-File $PWD\XamlIslandsSample\pri.resfiles
39 |
40 | makepri new /pr $PWD\app /cf $PWD\XamlIslandsSample\priconfig.xml /of $PWD\$Arch\$Config\resources.pri /o
41 |
42 | $output = "$PWD\$Arch\$Config\UnpackagedWin32.exe"
43 | if (Test-Path $output) {
44 | Write-Host -ForegroundColor Green Output at $output
45 | } else {
46 | Write-Error "Errors found, $output not found"
47 | }
48 |
49 | return
50 |
--------------------------------------------------------------------------------
/CppXAMLSample/fixUpPRIFileList.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param (
3 | [ValidateSet('x64', 'x86')]
4 | [string]
5 | $Arch = [ArchTypeEnum]::x64,
6 | [ValidateSet('Debug', 'Release')]
7 | [string]
8 | $Config = [Config]::Release
9 | )
10 |
11 | enum ArchTypeEnum {
12 | x64
13 | x86
14 | }
15 |
16 | enum Config {
17 | Debug
18 | Release
19 | }
20 |
21 | $resources = @(
22 | "..\$Arch\$Config\MarkupSample\MarkupSample.pri",
23 | "..\packages\Microsoft.UI.Xaml.2.8.0-prerelease.210927001\runtimes\win10-x64\native\Microsoft.UI.Xaml.pri"
24 | )
25 | Write-Output $resources | Out-File $PWD\XamlIslandsSample\pri.resfiles
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Alexander Sklar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Alexander Sklar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Playground/Application.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
33 |
34 |
35 |
36 |
37 |
38 | PerMonitorV2
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Playground/Playground.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31624.102
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Playground", "Playground.vcxproj", "{1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x64.ActiveCfg = Debug|x64
17 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x64.Build.0 = Debug|x64
18 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x86.ActiveCfg = Debug|Win32
19 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Debug|x86.Build.0 = Debug|Win32
20 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x64.ActiveCfg = Release|x64
21 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x64.Build.0 = Release|x64
22 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x86.ActiveCfg = Release|Win32
23 | {1ACA4F14-B0C1-495D-8FFF-B4E93D7F12C6}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {80872FBF-05BC-4620-BF8A-A9289BADB0EE}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/Playground/Playground.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | false
7 | true
8 |
9 |
10 |
11 | Debug
12 | Win32
13 |
14 |
15 | Release
16 | Win32
17 |
18 |
19 | Debug
20 | x64
21 |
22 |
23 | Release
24 | x64
25 |
26 |
27 |
28 | 16.0
29 | Win32Proj
30 | {1aca4f14-b0c1-495d-8fff-b4e93d7f12c6}
31 | WindowsProject1
32 | 10.0
33 | Playground
34 |
35 |
36 |
37 | Application
38 | true
39 | v143
40 | Unicode
41 |
42 |
43 | Application
44 | false
45 | v143
46 | true
47 | Unicode
48 |
49 |
50 | Application
51 | true
52 | v143
53 | Unicode
54 |
55 |
56 | Application
57 | false
58 | v143
59 | true
60 | Unicode
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 | true
88 |
89 |
90 | false
91 |
92 |
93 |
94 | Level3
95 | true
96 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
97 | true
98 | Create
99 | pch.h
100 |
101 |
102 | Windows
103 | true
104 |
105 |
106 | Application.manifest %(AdditionalManifestFiles)
107 |
108 |
109 |
110 |
111 | Level3
112 | true
113 | true
114 | true
115 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
116 | true
117 |
118 |
119 | Windows
120 | true
121 | true
122 | true
123 |
124 |
125 | Application.manifest %(AdditionalManifestFiles)
126 |
127 |
128 |
129 |
130 | Level3
131 | true
132 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
133 | true
134 |
135 |
136 | Windows
137 | true
138 |
139 |
140 | Application.manifest %(AdditionalManifestFiles)
141 |
142 |
143 |
144 |
145 | Level3
146 | true
147 | true
148 | true
149 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
150 | true
151 |
152 |
153 | Windows
154 | true
155 | true
156 | true
157 |
158 |
159 | Application.manifest %(AdditionalManifestFiles)
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
--------------------------------------------------------------------------------
/Playground/Resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by WindowsProject1.rc
4 |
5 | #define IDS_APP_TITLE 103
6 |
7 | #define IDR_MAINFRAME 128
8 | #define IDD_WINDOWSPROJECT1_DIALOG 102
9 | #define IDD_ABOUTBOX 103
10 | #define IDM_ABOUT 104
11 | #define IDM_EXIT 105
12 | #define IDI_WINDOWSPROJECT1 107
13 | #define IDI_SMALL 108
14 | #define IDC_WINDOWSPROJECT1 109
15 | #define IDC_MYICON 2
16 | #ifndef IDC_STATIC
17 | #define IDC_STATIC -1
18 | #endif
19 | // Next default values for new objects
20 | //
21 | #ifdef APSTUDIO_INVOKED
22 | #ifndef APSTUDIO_READONLY_SYMBOLS
23 |
24 | #define _APS_NO_MFC 130
25 | #define _APS_NEXT_RESOURCE_VALUE 129
26 | #define _APS_NEXT_COMMAND_VALUE 32771
27 | #define _APS_NEXT_CONTROL_VALUE 1000
28 | #define _APS_NEXT_SYMED_VALUE 110
29 | #endif
30 | #endif
31 |
--------------------------------------------------------------------------------
/Playground/WindowsProject1.cpp:
--------------------------------------------------------------------------------
1 | // WindowsProject1.cpp : Defines the entry point for the application.
2 | //
3 | #include "pch.h"
4 | #include "framework.h"
5 | #include "WindowsProject1.h"
6 |
7 |
8 | using namespace winrt;
9 | using namespace Windows::UI::Xaml::Controls;
10 | using namespace Windows::UI::Xaml;
11 | using namespace Windows::UI::Xaml::Hosting;
12 |
13 | using namespace Microsoft::Toolkit::Win32::UI::XamlHost;
14 |
15 | using namespace Microsoft::UI::Xaml::Controls;
16 |
17 | // This DesktopWindowXamlSource is the object that enables a non-UWP desktop application
18 | // to host WinRT XAML controls in any UI element that is associated with a window handle (HWND).
19 | DesktopWindowXamlSource desktopXamlSource{ nullptr };
20 | XamlApplication xapp{ nullptr };
21 | ContentPresenter presenter{ nullptr };
22 |
23 | #define MAX_LOADSTRING 100
24 |
25 | // Global Variables:
26 | HINSTANCE hInst; // current instance
27 | WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
28 | WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
29 |
30 | // Forward declarations of functions included in this code module:
31 | ATOM MyRegisterClass(HINSTANCE hInstance);
32 | BOOL InitInstance(HINSTANCE, int);
33 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
34 | INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
35 |
36 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
37 | _In_opt_ HINSTANCE hPrevInstance,
38 | _In_ LPWSTR lpCmdLine,
39 | _In_ int nCmdShow)
40 | {
41 | UNREFERENCED_PARAMETER(hPrevInstance);
42 | UNREFERENCED_PARAMETER(lpCmdLine);
43 |
44 | // TODO: Place code here.
45 |
46 | // Initialize global strings
47 | LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
48 | LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
49 | MyRegisterClass(hInstance);
50 |
51 | winrt::init_apartment(apartment_type::single_threaded);
52 |
53 | auto winuiIXMP = winrt::Microsoft::UI::Xaml::XamlTypeInfo::XamlControlsXamlMetaDataProvider();
54 |
55 | xapp = XamlApplication({ winuiIXMP });
56 | WindowsXamlManager winxamlmanager = WindowsXamlManager::InitializeForCurrentThread();
57 | xapp.Resources().MergedDictionaries().Append(winrt::Microsoft::UI::Xaml::Controls::XamlControlsResources());
58 |
59 | desktopXamlSource = DesktopWindowXamlSource();
60 | SetThreadDescription(GetCurrentThread(), L"XAML thread");
61 | // Perform application initialization:
62 | if (!InitInstance (hInstance, nCmdShow))
63 | {
64 | return FALSE;
65 | }
66 |
67 | HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
68 |
69 | MSG msg;
70 |
71 |
72 | // Main message loop:
73 | while (GetMessage(&msg, nullptr, 0, 0))
74 | {
75 | if (auto xamlSourceNative2 = desktopXamlSource.as()) {
76 | BOOL xamlSourceProcessedMessage = FALSE;
77 | winrt::check_hresult(xamlSourceNative2->PreTranslateMessage(&msg, &xamlSourceProcessedMessage));
78 | if (xamlSourceProcessedMessage) {
79 | continue;
80 | }
81 | }
82 |
83 | if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
84 | {
85 | TranslateMessage(&msg);
86 | DispatchMessage(&msg);
87 | }
88 | }
89 |
90 | return (int) msg.wParam;
91 | }
92 |
93 |
94 |
95 | //
96 | // FUNCTION: MyRegisterClass()
97 | //
98 | // PURPOSE: Registers the window class.
99 | //
100 | ATOM MyRegisterClass(HINSTANCE hInstance)
101 | {
102 | WNDCLASSEXW wcex;
103 |
104 | wcex.cbSize = sizeof(WNDCLASSEX);
105 |
106 | wcex.style = CS_HREDRAW | CS_VREDRAW;
107 | wcex.lpfnWndProc = WndProc;
108 | wcex.cbClsExtra = 0;
109 | wcex.cbWndExtra = 0;
110 | wcex.hInstance = hInstance;
111 | wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));
112 | wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
113 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
114 | wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);
115 | wcex.lpszClassName = szWindowClass;
116 | wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
117 |
118 | return RegisterClassExW(&wcex);
119 | }
120 |
121 | //
122 | // FUNCTION: InitInstance(HINSTANCE, int)
123 | //
124 | // PURPOSE: Saves instance handle and creates main window
125 | //
126 | // COMMENTS:
127 | //
128 | // In this function, we save the instance handle in a global variable and
129 | // create and display the main program window.
130 | //
131 | BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
132 | {
133 | hInst = hInstance; // Store instance handle in our global variable
134 |
135 | HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
136 | CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
137 |
138 | if (!hWnd)
139 | {
140 | return FALSE;
141 | }
142 |
143 | ShowWindow(hWnd, nCmdShow);
144 | UpdateWindow(hWnd);
145 |
146 | // The call to winrt::init_apartment initializes COM; by default, in a multithreaded apartment.
147 |
148 | return TRUE;
149 | }
150 |
151 | //
152 | // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
153 | //
154 | // PURPOSE: Processes messages for the main window.
155 | //
156 | // WM_COMMAND - process the application menu
157 | // WM_PAINT - Paint the main window
158 | // WM_DESTROY - post a quit message and return
159 | //
160 | //
161 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
162 | {
163 | // Get handle to the core window.
164 | auto interop = desktopXamlSource.as();
165 |
166 | switch (message)
167 | {
168 | case WM_CREATE: {
169 |
170 |
171 | // Parent the DesktopWindowXamlSource object to the current window.
172 | check_hresult(interop->AttachToWindow(hWnd)); // This fails due to access violation!
173 |
174 | auto createStruct = reinterpret_cast(lParam);
175 |
176 | // Get the new child window's hwnd
177 | HWND hWndXamlIsland = nullptr;
178 | check_hresult(interop->get_WindowHandle(&hWndXamlIsland));
179 |
180 | SetWindowPos(hWndXamlIsland, nullptr, 0, 0, createStruct->cx, createStruct->cy, SWP_SHOWWINDOW);
181 |
182 | StackPanel main;
183 |
184 | TextBlock tb;
185 | tb.Text(L"XAML islands Playground");
186 | tb.HorizontalAlignment(HorizontalAlignment::Center);
187 | tb.FontWeight(Windows::UI::Text::FontWeights::Black());
188 | tb.FontSize(32);
189 | main.Children().Append(tb);
190 |
191 | auto infobar = Microsoft::UI::Xaml::Controls::InfoBar();
192 | main.Children().Append(infobar);
193 |
194 | StackPanel sp;
195 | sp.Orientation(Orientation::Horizontal);
196 |
197 | Grid editPanel;
198 | TextBox edit;
199 | edit.Height(600);
200 | edit.MinWidth(600);
201 | edit.HorizontalAlignment(HorizontalAlignment::Stretch);
202 | edit.VerticalAlignment(VerticalAlignment::Top);
203 | edit.AcceptsReturn(true);
204 | edit.IsSpellCheckEnabled(false);
205 | Media::FontFamily consolas(L"Consolas");
206 | edit.FontFamily(consolas);
207 |
208 | edit.Text(LR"(
209 |
213 |
214 |
215 | )");
216 | editPanel.Children().Append(edit);
217 |
218 | Button run;
219 | run.Content(winrt::box_value(L"Run"));
220 | run.Tapped([=](auto&, auto&) {
221 | try {
222 | auto parsedContent = Markup::XamlReader::Load(edit.Text());
223 | presenter.Content(parsedContent);
224 | }
225 | catch (const winrt::hresult_error& e) {
226 | infobar.Title(L"Error");
227 | infobar.Message(e.message());
228 | infobar.Severity(InfoBarSeverity::Error);
229 | infobar.IsOpen(true);
230 | }
231 | });
232 |
233 | run.Margin(ThicknessHelper::FromUniformLength(4));
234 | run.HorizontalAlignment(HorizontalAlignment::Right);
235 | run.VerticalAlignment(VerticalAlignment::Top);
236 | editPanel.Margin(ThicknessHelper::FromUniformLength(12));
237 | editPanel.Children().Append(run);
238 |
239 | sp.Children().Append(editPanel);
240 | presenter = ContentPresenter();
241 | presenter.HorizontalAlignment(HorizontalAlignment::Stretch);
242 | presenter.Background(Media::SolidColorBrush{ Windows::UI::Colors::Aqua() });
243 | presenter.Margin(ThicknessHelper::FromUniformLength(4));
244 |
245 | presenter.MinWidth(600);
246 | presenter.MinHeight(800);
247 | sp.Children().Append(presenter);
248 |
249 | main.Children().Append(sp);
250 |
251 | desktopXamlSource.Content(main);
252 |
253 | break;
254 | }
255 | case WM_COMMAND:
256 | {
257 | int wmId = LOWORD(wParam);
258 | // Parse the menu selections:
259 | switch (wmId)
260 | {
261 | case IDM_ABOUT:
262 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
263 | break;
264 | case IDM_EXIT:
265 | DestroyWindow(hWnd);
266 | break;
267 | default:
268 | return DefWindowProc(hWnd, message, wParam, lParam);
269 | }
270 | }
271 | break;
272 | case WM_PAINT:
273 | {
274 | // PAINTSTRUCT ps;
275 | // HDC hdc = BeginPaint(hWnd, &ps);
276 | // TODO: Add any drawing code that uses hdc here...
277 | // EndPaint(hWnd, &ps);
278 | }
279 | break;
280 | case WM_SIZE:
281 | {
282 | HWND hWndXamlIsland = nullptr;
283 | check_hresult(interop->get_WindowHandle(&hWndXamlIsland));
284 |
285 | SetWindowPos(hWndXamlIsland, nullptr, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_SHOWWINDOW);
286 |
287 | break;
288 | }
289 | case WM_DESTROY:
290 | xapp.Close();
291 | PostQuitMessage(0);
292 | break;
293 | default:
294 | return DefWindowProc(hWnd, message, wParam, lParam);
295 | }
296 | return 0;
297 | }
298 |
299 | // Message handler for about box.
300 | INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
301 | {
302 | UNREFERENCED_PARAMETER(lParam);
303 | switch (message)
304 | {
305 | case WM_INITDIALOG:
306 | return (INT_PTR)TRUE;
307 |
308 | case WM_COMMAND:
309 | if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
310 | {
311 | EndDialog(hDlg, LOWORD(wParam));
312 | return (INT_PTR)TRUE;
313 | }
314 | break;
315 | }
316 | return (INT_PTR)FALSE;
317 | }
318 |
--------------------------------------------------------------------------------
/Playground/WindowsProject1.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "resource.h"
4 |
--------------------------------------------------------------------------------
/Playground/WindowsProject1.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/Playground/WindowsProject1.ico
--------------------------------------------------------------------------------
/Playground/WindowsProject1.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/Playground/WindowsProject1.rc
--------------------------------------------------------------------------------
/Playground/WindowsProject1.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 |
35 |
36 | Source Files
37 |
38 |
39 |
40 |
41 | Resource Files
42 |
43 |
44 |
45 |
46 | Resource Files
47 |
48 |
49 | Resource Files
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Playground/framework.h:
--------------------------------------------------------------------------------
1 | // header.h : include file for standard system include files,
2 | // or project specific include files
3 | //
4 |
5 | #pragma once
6 |
7 | #include "targetver.h"
8 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
9 | // Windows Header Files
10 | #include
11 | // C RunTime Header Files
12 | #include
13 | #include
14 | #include
15 | #include
16 |
--------------------------------------------------------------------------------
/Playground/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Playground/pch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include
15 |
16 | #include
17 | #include
18 |
19 | #include
20 | #include
21 |
22 | #include
23 | #include
--------------------------------------------------------------------------------
/Playground/small.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/Playground/small.ico
--------------------------------------------------------------------------------
/Playground/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // // Including SDKDDKVer.h defines the highest available Windows platform.
4 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
5 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
6 | #include
7 |
--------------------------------------------------------------------------------
/Unpackaged.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Unpackaged
5 | 0.0.21
6 | Alexander Sklar
7 | Alexander Sklar
8 | false
9 | LICENSE.txt
10 | https://github.com/asklar/xaml-islands
11 | Helpers for unpackaged and XAML Islands apps
12 | Copyright Alexander Sklar (c) 2021
13 | unpackaged msix xaml islands xaml-islands
14 | docs\README.md
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/build/Unpackaged.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)\..\inc
6 |
7 |
8 |
9 |
10 | $(BeforeLinkTargets);
11 | _UnpackagedWin32GenerateAdditionalWinmdManifests;
12 |
13 |
14 |
15 |
16 |
17 | <_UnpackagedWin32WinmdManifest Include="@(ReferencePath->'$(IntDir)\%(FileName).manifest')" Condition="'%(ReferencePath.IsSystemReference)' != 'true' and '%(ReferencePath.WinMDFile)' == 'true' and '%(ReferencePath.ReferenceSourceTarget)' == 'ResolveAssemblyReference' and '%(ReferencePath.Implementation)' != ''">
18 | %(ReferencePath.FullPath)
19 | %(ReferencePath.Implementation)
20 |
21 |
24 | <_UnpackagedWin32WinmdProjectReference Condition="'%(_ResolvedNativeProjectReferencePaths.ProjectType)' != 'StaticLibrary'" Include="@(_ResolvedNativeProjectReferencePaths->WithMetadataValue('FileType','winmd')->'%(RootDir)%(Directory)%(TargetPath)')" />
25 | <_UnpackagedWin32WinmdManifest Include="@(_UnpackagedWin32WinmdProjectReference->'$(IntDir)\%(FileName).manifest')">
26 | %(Identity)
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | $(MSBuildThisFileDirectory)\..\..\inc\XamlApplication.idl
56 |
57 |
58 |
59 |
60 | %(ManifestInput);$(MSBuildThisFileDirectory)..\inc\xaml-islands.manifest
61 | %(ManifestInput);$(MSBuildThisFileDirectory)..\inc\per-monitor-v2.manifest
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # CppXAML
2 |
3 | [CppXAML](https://github.com/asklar/xaml-islands) aims to make usage of XAML and XAML islands in C++ more natural and idiomatic.
4 |
5 | [C++/WinRT](https://docs.microsoft.com/windows/uwp/cpp-and-winrt-apis/) provides a projection of a Windows Runtime component's API, but one that isn’t always easy to use (esp. for XAML). It also is unopinionated about how to implement properties. This added flexibility can be useful, but is often unnecessary and results in overly-verbose code.
6 |
7 | CppXAML provides several kinds of higher-level helpers. Some usage information can be found below; for more details, see the [API reference](https://asklar.github.io/xaml-islands).
8 |
9 | GitHub repo: https://github.com/asklar/xaml-islands
10 |
11 | # Table of Contents
12 | * [Facilities for writing XAML controls](#facilities-for-writing-xaml-controls)
13 | * [Facilities for using XAML controls](#facilities-for-using-xaml-controls)
14 | * [Facilities for using XAML islands](#facilities-for-using-xaml-islands)
15 |
16 | # Facilities for writing XAML controls {#facilities-for-writing-xaml-controls}
17 |
18 | ## Property and event helpers
19 |
20 | - [`XamlProperty`](./structcppxaml_1_1_xaml_property.html)
21 | - [`SimpleNotifyPropertyChanged`](./structcppxaml_1_1_simple_notify_property_changed.html)
22 | - [`XamlPropertyWithNPC`](./structcppxaml_1_1_xaml_property_with_n_p_c.html)
23 | - [`XamlEvent`](./structcppxaml_1_1_xaml_event.html)
24 | - [`TypedXamlEvent`](./structcppxaml_1_1_typed_xaml_event.html)
25 |
26 | These provide stock/simple property objects that remove the need for verbose hand-written options.
27 |
28 | #### Example
29 |
30 | Suppose you have the following Page defined in IDL:
31 | ```csharp
32 | namespace Foo {
33 | runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged {
34 | MainPage();
35 | event Windows.Foundation.EventHandler OkClicked;
36 | String InterfaceStr;
37 | Int32 MyInt;
38 | }
39 | }
40 | ```
41 |
42 | **Before (plain C++/WinRT)**
43 | ```cpp
44 | struct MainPage : MainPageT {
45 | winrt::event> m_okClicked{};
46 | winrt::event_token OkClicked(winrt::Windows::Foundation::EventHandler h) {
47 | return m_okClicked.add(h);
48 | }
49 | void OkClicked(winrt::event_token token) {
50 | m_okClicked.remove(token);
51 | }
52 |
53 | winrt::hstring m_InterfaceStr;
54 | winrt::hstring InterfaceStr() {
55 | return m_InterfaceStr;
56 | }
57 | void InterfaceStr(winrt::hstring v) {
58 | m_InterfaceStr = v;
59 | }
60 |
61 | winrt::event m_propertyChanged;
62 |
63 | winrt::event_token PropertyChanged(winrt::Windows::Xaml::Data::PropertyChangedEventHandler const& value) {
64 | return m_propertyChanged.add(value);
65 | }
66 | void PropertyChanged(winrt::event_token const& token) {
67 | m_propertyChanged.remove(token);
68 | }
69 |
70 | int32_t m_MyInt;
71 | int32_t MyInt() {
72 | return m_MyInt;
73 | }
74 | void MyInt(int32_t v) {
75 | m_MyInt = v;
76 | m_propertyChanged(*this, { L"MyInt" });
77 | }
78 |
79 | };
80 |
81 | ```
82 |
83 | **After (with CppXaml)**
84 | ```cpp
85 |
86 | struct MainPage : MainPageT, cppxaml::SimpleNotifyPropertyChanged {
87 | cppxaml::XamlEvent OkClicked;
88 | cppxaml::XamlProperty InterfaceStr;
89 | cppxaml::XamlPropertyWithNPC MyInt;
90 | MainPage() : INIT_PROPERTY(MyInt, 42) {
91 | InitializeComponent();
92 |
93 | // Properties can be assigned to and read from with the operator= too!
94 | InterfaceStr = winrt::hstring{ L"This string comes from the implementation" };
95 | winrt::hstring v = InterfaceStr;
96 | }
97 |
98 | void MyPage::DoSomething() {
99 | // when MyInt is modified, it automatically sends NPC!
100 | MyInt = 39;
101 |
102 | // if we want to manually send a notification:
103 | RaisePropertyChanged(L"MyInt");
104 | }
105 | };
106 | ```
107 |
108 | # Facilities for using XAML controls {#facilities-for-using-xaml-controls}
109 |
110 | ## Control helpers
111 | CppXAML includes some primitives to make it more natural to write XAML UI in code.
112 |
113 |
114 | ### xaml Namespace alias
115 | Since we want CppXAML to be future proof and work with WinUI 3, CppXAML creates a namespace alias `cppxaml::xaml` which points at either `Windows::UI::Xaml` or `Microsoft::UI::Xaml` for system XAML or WinUI 3, respectively.
116 |
117 | ### Builder-style programming
118 | C++/WinRT enables setting properties on a type by calling a property setter method, e.g. `myTextBlock.Text(L"text");`. If you then want to set another property, then you have to make another call `myTextBlock.XYZ(...);`. This can get verbose when having to set multiple properties. CppXAML enables writing builder-style code instead of the former imperative-style:
119 |
120 | **Before (plain C++/WinRT)**
121 | ```cpp
122 | auto myTextBlock = winrt::Windows::UI::Xaml::Controls::TextBlock{};
123 | myTextBlock.Text(L"Hello world");
124 | myTextBlock.Margin(winrt::Windows::UI::Xaml::ThicknessHelper::FromUniformLength(4));
125 | myTextBlock.Padding(winrt::Windows::UI::Xaml::ThicknessHelper::FromUniformLength(6));
126 | myTextBlock.Name(L"myTB");
127 | ```
128 |
129 | **After (with CppXAML)**
130 | ```cpp
131 | auto myTextBlock = cppxaml::TextBlock(L"Hello world")
132 | .Margin(4)
133 | .Padding(6)
134 | .Name(L"myTB");
135 | ```
136 |
137 | ### TextBlock
138 | Most commonly, you will want to construct a `TextBlock` from a string of text. This can be a bit cumbersome if you are using C++/WinRT directly.
139 | With cppxaml, as you've seen above, you can just write:
140 | ```cpp
141 | auto tb = cppxaml::TextBlock(L"Hello");
142 | ```
143 |
144 | ### StackPanel
145 | Panels in XAML can have zero or more children. CppXAML makes it easy to naturally describe a panel's children with an initializer list. For example:
146 |
147 | **Before (plain C++/WinRT)**
148 | ```cpp
149 | auto sp = winrt::Windows::UI::Xaml::Controls::StackPanel();
150 | auto tb1 = winrt::Windows::UI::Xaml::Controls::TextBlock();
151 | tb1.Text(L"Hello");
152 | auto tb2 = winrt::Windows::UI::Xaml::Controls::TextBlock();
153 | tb2.Text(L"world!");
154 | sp.Children().Append(tb1);
155 | sp.Children().Append(tb2);
156 | ```
157 |
158 | **After (with CppXaml)**
159 | ```cpp
160 | auto sp = cppxaml::StackPanel({
161 | cppxaml::TextBlock(L"Hello"),
162 | cppxaml::TextBlock(L"world!")
163 | });
164 | ```
165 |
166 |
167 | You can also set its `Orientation`:
168 | ```cpp
169 | auto sp cppxaml::StackPanel({
170 | cppxaml::TextBlock(L"Hello"),
171 | cppxaml::TextBlock(L"world!").Name(L"worldTB")
172 | }).Orientation(cppxaml::xaml::Controls::Orientation::Horizontal);
173 | ```
174 |
175 | ### ContentControl (Button, etc.)
176 | Sub-classes of XAML's `ContentControl` enable nesting one control into another via the `Content` property. CppXAML makes this easier:
177 | ```cpp
178 | auto scrollViewer = cppxaml::MakeContentControl({
179 | cppxaml::StackPanel({
180 | cppxaml::TextBlock(L"Hello"),
181 | cppxaml::TextBlock(L"world!").Name(L"worldTB")
182 | })
183 | });
184 | ```
185 |
186 | ### Locating elements by name
187 | Sometimes you will need to perform some operation on an element that is deeply nested in a builder-style declaration. You can use `FindChildByName` to find an element in a XAML tree with a given name:
188 | ```cpp
189 | auto worldTB = cppxaml::FindChildByName(*scrollViewer, L"worldTB");
190 | ```
191 |
192 | ### Grid
193 | Declaring a `Grid` in XAML via code is cumbersome as one has to create and set its `RowDefinitions` and `ColumnDefinitions`.
194 |
195 | **Before (plain C++/WinRT)**
196 | ```cpp
197 | winrt::Windows::UI::Xaml::Controls::Grid g;
198 | auto rd1 = winrt::Windows::UI::Xaml::Controls::RowDefinition();
199 | rd1.Height(winrt::Windows::UI::Xaml::GridLengthHelper::FromPixels(40));
200 | auto rd2 = winrt::Windows::UI::Xaml::Controls::RowDefinition();
201 | rd2.Height(winrt::Windows::UI::Xaml::GridLengthHelper::FromValueAndType(1,
202 | winrt::Windows::UI::Xaml::GridUnitType::Star));
203 | g.RowDefinitions().Append(rd1);
204 | g.RowDefinitions().Append(rd2);
205 |
206 | auto cd1 = winrt::Windows::UI::Xaml::Controls::ColumnDefinition();
207 | cd1.Width(winrt::Windows::UI::Xaml::GridLengthHelper::Auto());
208 | auto cd2 = winrt::Windows::UI::Xaml::Controls::ColumnDefinition();
209 | cd2.Width(winrt::Windows::UI::Xaml::GridLengthHelper::Auto());
210 | g.ColumnDefinitions().Append(cd1);
211 | g.ColumnDefinitions().Append(cd2);
212 |
213 | auto tb1 = winrt::Windows::UI::Xaml::Controls::TextBlock();
214 | tb1.Text(L"first");
215 | tb1.SetValue(winrt::Windows::UI::Xaml::Controls::Grid::RowProperty(), winrt::box_value(0));
216 | tb1.SetValue(winrt::Windows::UI::Xaml::Controls::Grid::ColumnProperty(), winrt::box_value(0));
217 | g.Children().Append(tb1);
218 | // repeat 3 more times... :-(
219 | ```
220 |
221 | **After (with CppXaml)**
222 | ```cpp
223 | auto grid = cppxaml::Grid({"40, *"}, {"Auto, Auto"}, {
224 | {0, 0, cppxaml::TextBlock(L"first") },
225 | {0, 1, cppxaml::TextBlock(L"second") },
226 | {1, 0, cppxaml::TextBlock(L"third") },
227 | {1, 1, cppxaml::TextBlock(L"fourth") },
228 | }),
229 | ```
230 |
231 | Here we defined a 2x2 `Grid`. The rows have heights of 40 px and `*`, and the columns are `Auto`. Then each child of the Grid is added in the cell designated by each entry in the initializer list, read as "row, column, child".
232 |
233 | In addition to the string syntax (which requires some parsing/tokenizing), this also works:
234 | ```cpp
235 | auto grid = cppxaml::Grid({40, {"*"}}, {{"Auto"}, {"Auto"}}, {
236 | {0, 0, cppxaml::TextBlock(L"first") },
237 | {0, 1, cppxaml::TextBlock(L"second") },
238 | {1, 0, cppxaml::TextBlock(L"third") },
239 | {1, 1, cppxaml::TextBlock(L"fourth") },
240 | }),
241 | ```
242 |
243 | ### Attached properties
244 | You can set arbitrary dependency properties, including attached properties, on a cppxaml wrapper:
245 |
246 | ```cpp
247 | auto tb = cppxaml::TextBlock(L"something")
248 | .Set(Grid::RowProperty(), 1)
249 | .Set(Grid::ColumnSpanProperty(), 2);
250 | ```
251 |
252 | ### AutoSuggestBox
253 | You can easily create an `AutoSuggestBox` from a `std::vector`; make sure the vector's lifetime extends for at least as long as the XAML UI is up.
254 |
255 | `EnableDefaultSearch()` will provide a reasonable default search experience (filters the list of items down to those that contain the search string). This behavior is case insensitive by default, but can be made case sensitive by passing `false`.
256 |
257 | ```cpp
258 | auto asb = cppxaml::AutoSuggestBox(GetFontFamilies())
259 | .EnableDefaultSearch()
260 | .Margin(0, 16, 0, 4)
261 | .Name(L"fontTB");
262 | ```
263 |
264 | ### Visual State change notifications
265 | You can easily set up visual state change notifications:
266 |
267 | ```cpp
268 | auto button = cppxaml::Button(L"click me")
269 | .VisualStates( {
270 | { L"PointerOver", [](auto&sender, cppxaml::xaml::VisualStateChangedEventArgs args) {
271 | auto x = args.NewState().Name();
272 | auto button = sender.as();
273 | button.Content(winrt::box_value(x));
274 | } },
275 | { L"Normal", [](auto&sender, auto&) {
276 | auto button = sender.as();
277 | button.Content(winrt::box_value(L"click me"));
278 | } },
279 | { L"Pressed", [](auto& sender, auto&) {
280 | auto button = sender.as();
281 | button.Content(winrt::box_value(L"pressed"));
282 | } },
283 | });
284 | ```
285 |
286 | ### Initializing Panels from collections
287 | As we saw earlier, you can initialize a panel from its children.
288 | You can also use transforms, to map elements from a data model into its corresponding view.
289 |
290 | For example:
291 | ```cpp
292 | auto strs = std::vector{ L"first", L"second", L"third", L"fourth" };
293 | auto grid = cppxaml::Grid({"40, *"}, {"Auto, Auto"},
294 | cppxaml::utils::transform_with_index(strs, [](const std::wstring& t, auto index) {
295 | return cppxaml::TextBlock(t)
296 | .Set(Grid::RowProperty(), (int)index / 2)
297 | .Set(Grid::ColumnProperty(), (int)index % 2);
298 | };
299 | })
300 | );
301 | ```
302 |
303 | For more details see `cppxaml::transform` and `cppxaml::transform_with_index` in [utils.h](./namespacecppxaml_1_1utils.html).
304 |
305 | ### Menus and icons
306 | You can easily compose MenuFlyoutItems into a MenuFlyout, and also have a centralized menu handler callback:
307 | ```cpp
308 | auto menuFlyout = cppxaml::MenuFlyout(
309 | cppxaml::MenuFlyoutItem(L"Exit")
310 | .IconElement(cppxaml::FontIcon(0xe8bb))
311 | .Click([hwnd = xw->hwnd()](auto&...) {
312 | DestroyWindow(hwnd);
313 | }),
314 | cppxaml::MenuFlyoutItem(L"Cancel")
315 | .IconElement(cppxaml::FontIcon(L"\xE8A7"))
316 | )
317 | .CentralizedHandler([](Windows::Foundation::IInspectable sender, auto&) {
318 | auto mfi = sender.as();
319 | auto x = mfi.Text();
320 | });
321 | ```
322 |
323 |
324 | # Facilities for using XAML Islands {#facilities-for-using-xaml-islands}
325 |
326 | ## XamlWindow
327 |
328 | `XamlWindow` implements an HWND based host for XAML Islands. You can create a `XamlWindow` from one of three overloads of Make:
329 |
330 | 1. Host a build-time XAML `UIElement` (usually defined in a runtime component project, often will be a `Page`)
331 | API:
332 | ```cpp
333 | template
334 | static XamlWindow& Make(PCWSTR id, AppController* controller = nullptr);
335 | ```
336 | Usage:
337 | ```cpp
338 | auto& mainWindow = cppxaml::XamlWindow::Make(L"MarkupSample", &controller);
339 | ```
340 | 2. Host UI created from markup at runtime:
341 | API:
342 | ```cpp
343 | static XamlWindow& Make(PCWSTR id, std::wstring_view markup, AppController* c = nullptr)
344 | ```
345 | Usage:
346 | ```cpp
347 | auto& xw = cppxaml::XamlWindow::Make(L"MyPage", LR"(
348 |
349 | Hello
350 | )", &controller);
351 | ```
352 | 3. Host UI created programmatically at runtime:
353 | API:
354 | ```cpp
355 | static XamlWindow& Make(PCWSTR id, winrt::Windows::UI::Xaml::UIElement(*getUI)(const XamlWindow&), AppController* c = nullptr);
356 | ```
357 | Usage:
358 | ```cpp
359 | auto& xw = cppxaml::XamlWindow::Make(L"Foo", [](auto&...) {
360 | return winrt::Windows::UI::Xaml::Controls::Button();
361 | });
362 | ```
363 |
364 | ### Parenting flyouts
365 | To parent a flyout or context menu, you may use one of the `InitializeWithWindow` methods:
366 |
367 | - Initialize with a WinUI 3 `Window`-like object:
368 | ```cpp
369 | template
370 | std::enable_if_t> InitializeWithWindow(winrt::Windows::Foundation::IInspectable obj, TWindow /*winrt::Microsoft::UI::Xaml::Window*/ w)
371 | ```
372 | - Initialize with an `HWND`:
373 | ```cpp
374 | bool InitializeWithWindow(cppxaml::xaml::FrameworkElement obj, HWND hwnd)
375 | ```
376 | - Initialize with a `XamlWindow`:
377 | ```cpp
378 | void InitializeWithWindow(cppxaml::xaml::FrameworkElement obj, const cppxaml::XamlWindow* xw)
379 | ```
380 |
381 | ## AppController
382 | `AppController` is responsible for coordinating XamlWindow instances, can extend their wndproc, and provides an opportunity to hook up event handlers once a XAML UI becomes live
383 |
384 |
385 |
--------------------------------------------------------------------------------
/docs/img/VSM.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asklar/xaml-islands/31c4e0c2e30eca9b90790dd83ed9062cd66bcba5/docs/img/VSM.gif
--------------------------------------------------------------------------------
/inc/XamlApplication.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "CppXaml.XamlApplication.g.h"
4 | #include
5 | #include
6 | #include
7 |
8 | namespace winrt::CppXaml::implementation
9 | {
10 | struct XamlApplication : XamlApplicationT
11 | {
12 | XamlApplication() = default;
13 |
14 | XamlApplication(std::initializer_list providers)
15 | {
16 | for (auto&& provider : providers)
17 | {
18 | m_providers.Append(provider);
19 | }
20 | }
21 |
22 | ~XamlApplication()
23 | {
24 | Close();
25 | }
26 |
27 | void InitializeComponent() // C++ WinRT 2 phase construction
28 | {
29 | m_windowsXamlManager = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
30 | }
31 |
32 | winrt::Windows::Foundation::Collections::IVector MetadataProviders()
33 | {
34 | return m_providers;
35 | }
36 |
37 | winrt::Windows::Foundation::IClosable WindowsXamlManager()
38 | {
39 | return m_windowsXamlManager;
40 | }
41 |
42 | // ICloseable
43 | void Close()
44 | {
45 | if (b_closed) return;
46 |
47 | b_closed = true;
48 |
49 | m_windowsXamlManager.Close();
50 | m_providers.Clear();
51 | m_windowsXamlManager = nullptr;
52 |
53 | // Toolkit has a message loop here.
54 | }
55 |
56 | // IXamlMetadataProvider
57 | winrt::Windows::UI::Xaml::Markup::IXamlType GetXamlType(winrt::Windows::UI::Xaml::Interop::TypeName const& type)
58 | {
59 | for (const auto& provider : m_providers)
60 | {
61 | if (const auto xamlType = provider.GetXamlType(type))
62 | {
63 | return xamlType;
64 | }
65 | }
66 | return nullptr;
67 | }
68 |
69 | winrt::Windows::UI::Xaml::Markup::IXamlType GetXamlType(hstring const& fullName)
70 | {
71 | for (const auto& provider : m_providers)
72 | {
73 | if (const auto xamlType = provider.GetXamlType(fullName))
74 | {
75 | return xamlType;
76 | }
77 | }
78 | return nullptr;
79 | }
80 |
81 | com_array GetXmlnsDefinitions()
82 | {
83 | std::list definitions;
84 | for (const auto& provider : m_providers)
85 | {
86 | auto defs = provider.GetXmlnsDefinitions();
87 | for (const auto& def : defs)
88 | {
89 | definitions.insert(definitions.begin(), def);
90 | }
91 | }
92 |
93 | return winrt::com_array(definitions.begin(), definitions.end());
94 | }
95 |
96 | private:
97 | winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager m_windowsXamlManager{ nullptr };
98 | winrt::Windows::Foundation::Collections::IVector m_providers
99 | = winrt::single_threaded_vector();
100 | bool b_closed{};
101 | };
102 | }
103 |
104 | namespace winrt {
105 | template
106 | winrt::CppXaml::XamlApplication make_application(TProviders&&... providers)
107 | {
108 | return winrt::make(std::initializer_list{providers...});
109 | }
110 | }
111 |
112 | #pragma comment(lib, "onecoreuap_apiset.lib")
113 |
114 | namespace cppxaml {
115 | namespace details {
116 | PWSTR g_winUIDepId{};
117 | PACKAGEDEPENDENCY_CONTEXT g_ctx{};
118 | }
119 |
120 | ///
121 | /// Dynamically initializes WinUI 2. This API works on Windows 11 and newer.
122 | /// Adds the WinUI 2 framework package to the process's package graph.
123 | /// This enables unpackaged applications to use the stable (non-prerelease) WinUI 2 NuGet package.
124 | ///
125 | /// Optional minor version. Defaults to 8 (for 2.8)
126 | void InitializeWinUI(uint8_t minorVersion = 8) {
127 |
128 | if (details::g_winUIDepId == nullptr) {
129 | PACKAGE_VERSION minVersion{};
130 | minVersion.Major = minorVersion;
131 |
132 | constexpr const std::wstring_view winuiPackageFamilyNameTemplate{ L"Microsoft.UI.Xaml.2.%d_8wekyb3d8bbwe" };
133 | wchar_t pfn[PACKAGE_FAMILY_NAME_MAX_LENGTH]{};
134 | winrt::check_hresult(StringCchPrintf(pfn, std::size(pfn), winuiPackageFamilyNameTemplate.data(), minorVersion));
135 |
136 | winrt::check_hresult(TryCreatePackageDependency(nullptr, pfn, minVersion,
137 | PackageDependencyProcessorArchitectures_None, PackageDependencyLifetimeKind_Process,
138 | nullptr, CreatePackageDependencyOptions_None, &details::g_winUIDepId));
139 | }
140 |
141 | PWSTR packageFullName{};
142 |
143 | winrt::check_hresult(AddPackageDependency(details::g_winUIDepId, 0, AddPackageDependencyOptions_None, &details::g_ctx, &packageFullName));
144 | }
145 |
146 | ///
147 | /// Removes a reference to WinUI from the process's package graph.
148 | ///
149 | void UninitializeWinUI() {
150 | winrt::check_hresult(RemovePackageDependency(details::g_ctx));
151 | // should HeapFree g_winUIDepId - but do it in a refcounted way
152 | }
153 | }
--------------------------------------------------------------------------------
/inc/XamlApplication.idl:
--------------------------------------------------------------------------------
1 | namespace CppXaml
2 | {
3 | runtimeclass XamlApplication : Windows.UI.Xaml.Application, Windows.UI.Xaml.Markup.IXamlMetadataProvider, Windows.Foundation.IClosable
4 | {
5 | Windows.Foundation.Collections.IVector MetadataProviders{ get; };
6 | Windows.Foundation.IClosable WindowsXamlManager{ get; };
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/inc/cppxaml/InitializeWithWindow.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | /** @file
8 | * @author Alexander Sklar
9 | * @section LICENSE
10 | * Copyright (c) Alexander Sklar
11 | *
12 | * Licensed under the MIT license
13 | */
14 |
15 | namespace cppxaml {
16 |
17 | auto SetXamlRoot(winrt::Windows::Foundation::IInspectable obj, cppxaml::xaml::XamlRoot root) {
18 | if (auto fe = obj.try_as()) {
19 | return fe.XamlRoot(root);
20 | }
21 | else if (auto fb = obj.try_as()) {
22 | return fb.XamlRoot(root);
23 | }
24 | throw winrt::hresult_error(E_NOINTERFACE);
25 | }
26 |
27 | /**
28 | * @brief Initializes an object with a window-like object
29 | * @tparam TWindow the window-like type. \n
30 | * In system XAML, it must have a XamlRoot. \n
31 | * In WinUI 3, it must implement `IWindowNative` and have a Content property that exposes a XamlRoot (this will usually be Microsoft::UI::Xaml::Window).
32 | * @param obj The object to attach to the window, e.g. a `ContentDialog`.
33 | * @param w The window-like object.
34 | * @return
35 | */
36 | template
37 | #ifndef DOXY
38 | std::enable_if_t<
39 | !std::is_same_v &&
40 | !std::is_same_v>
41 | #else
42 | void
43 | #endif
44 | InitializeWithWindow(winrt::Windows::Foundation::IInspectable obj, TWindow /*winrt::Microsoft::UI::Xaml::Window*/ w) {
45 | #ifdef USE_WINUI3
46 | if (auto iww = obj.try_as()) {
47 | HWND hwnd{};
48 | w.as()->get_WindowHandle(&hwnd);
49 | iww->Initialize(hwnd);
50 | }
51 | else if (auto window = w.as()) {
52 | obj.XamlRoot(window.Content().XamlRoot());
53 | }
54 | else
55 | #else
56 | {
57 | SetXamlRoot(obj, w.XamlRoot());
58 | }
59 | #endif
60 | }
61 |
62 | /**
63 | * @brief Initializes a `FrameworkElement` with an HWND
64 | * @param obj
65 | * @param hwnd
66 | * @return
67 | */
68 | bool InitializeWithWindow(winrt::Windows::Foundation::IInspectable obj, HWND hwnd) {
69 | if (auto iww = obj.try_as()) {
70 | iww->Initialize(hwnd);
71 | return true;
72 | }
73 | return false;
74 | }
75 |
76 | /**
77 | * @brief Initializes a `FrameworkElement` with the window represented by the `XamlWindow` or the XAML content root that the `XamlWindow` object is hosting
78 | * @param obj
79 | * @param xw
80 | */
81 | void InitializeWithWindow(winrt::Windows::Foundation::IInspectable obj, const cppxaml::XamlWindow* xw) {
82 | if (!InitializeWithWindow(obj, xw->hwnd())) {
83 | SetXamlRoot(obj, xw->GetUIElement().XamlRoot());
84 | }
85 | }
86 |
87 | /**
88 | * @brief
89 | * @tparam TUIElement
90 | * @tparam TWindow
91 | * @param obj
92 | * @param w
93 | * @return
94 | */
95 | template
96 | #ifndef DOXY
97 | std::enable_if_t &&
98 | !std::is_same_v, void>
99 | #else
100 | void
101 | #endif
102 | InitializeWithWindow(cppxaml::details::Wrapper obj, TWindow /*winrt::Microsoft::UI::Xaml::Window*/ w) {
103 | return InitializeWithWindow(*obj, w);
104 | }
105 | }
--------------------------------------------------------------------------------
/inc/cppxaml/VisualState.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | /** @file
6 | * @author Alexander Sklar
7 | * @section LICENSE
8 | * Copyright (c) Alexander Sklar
9 | *
10 | * Licensed under the MIT license
11 | */
12 |
13 | namespace cppxaml {
14 | namespace details {
15 |
16 | cppxaml::xaml::FrameworkElement FindChildWithVSG(cppxaml::xaml::FrameworkElement fe) {
17 | cppxaml::xaml::FrameworkElement root{ nullptr };
18 | for (auto i = 0; i < cppxaml::xaml::Media::VisualTreeHelper::GetChildrenCount(fe); i++) {
19 | auto child = cppxaml::xaml::Media::VisualTreeHelper::GetChild(fe, i);
20 | if (auto childFE = child.try_as()) {
21 | winrt::Windows::Foundation::Collections::IVector vsgs = cppxaml::xaml::VisualStateManager::GetVisualStateGroups(childFE);
22 | if (vsgs.Size() != 0) {
23 | root = childFE;
24 | break;
25 | }
26 | }
27 | }
28 | return root;
29 | }
30 |
31 | // TODO: make the callback take a template parameter so we don't have to cast from IInspectable
32 | struct VSMListener : winrt::implements {
33 |
34 | VSMListener(cppxaml::xaml::FrameworkElement fe, const std::unordered_map& map) : m_map(map) {
35 | if (auto root = FindChildWithVSG(fe)) {
36 | for (const cppxaml::xaml::VisualStateGroup& vsg : cppxaml::xaml::VisualStateManager::GetVisualStateGroups(root)) {
37 | vsg.CurrentStateChanged([_this = this->get_strong(), fe](winrt::Windows::Foundation::IInspectable sender, cppxaml::xaml::VisualStateChangedEventArgs args) {
38 |
39 | auto newState = args.NewState();
40 | auto newName = newState.Name();
41 | const auto newNameStr = newName.c_str();
42 | if (_this->m_map.find(newNameStr) != _this->m_map.end()) {
43 | _this->m_map[newNameStr](fe, args);
44 | }
45 | });
46 | }
47 | }
48 |
49 | }
50 |
51 | private:
52 | std::unordered_map m_map{};
53 | };
54 | }
55 |
56 | template
57 | auto VSMListener(TFrameworkElement obj, const std::unordered_map& map) {
58 | cppxaml::xaml::FrameworkElement fe(obj);
59 | if (!fe.Parent()) {
60 | fe.Loaded([map](winrt::Windows::Foundation::IInspectable sender, auto&) {
61 | auto listener = winrt::make_self(sender.as(), map);
62 | });
63 | }
64 | else {
65 | auto listener = winrt::make_self(fe, map);
66 | }
67 | return obj;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/inc/cppxaml/XamlProperty.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | /** @file
6 | * @author Alexander Sklar
7 | * @section LICENSE
8 | * Copyright (c) Alexander Sklar
9 | *
10 | * Licensed under the MIT license
11 | */
12 |
13 | namespace winrt {
14 | template
15 | T try_as(I* i) {
16 | T t;
17 | if (i->QueryInterface(winrt::guid_of(), winrt::put_abi(t)) == S_OK) {
18 | return t;
19 | }
20 | return nullptr;
21 | }
22 | }
23 |
24 | /**
25 | * @namespace
26 | */
27 | namespace cppxaml {
28 |
29 | namespace details {
30 | template
31 | struct XamlEvent_t {
32 | winrt::event_token operator()(T const& handler) {
33 | return m_handler.add(handler);
34 | }
35 | auto operator()(const winrt::event_token& token) noexcept { return m_handler.remove(token); }
36 |
37 | template
38 | auto invoke(TArgs&&... args) {
39 | return m_handler(args...);
40 | }
41 | private:
42 | winrt::event m_handler;
43 | };
44 | }
45 | /**
46 | * @brief A default event handler that maps to [Windows.Foundation.EventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.eventhandler-1).
47 | * @tparam T The event data type.
48 | */
49 | template
50 | struct XamlEvent : cppxaml::details::XamlEvent_t> {};
51 |
52 | /**
53 | * @brief A default event handler that maps to [Windows.Foundation.TypedEventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.typedeventhandler-2).
54 | * @tparam T The event data type.
55 | * @details Usage example:
56 | * @code
57 | * // In IDL, this corresponds to:
58 | * // event Windows.Foundation.TypedEventHandler OkClicked;
59 | * cppxaml::TypedXamlEvent OkClicked;
60 | * @endcode
61 | */
62 | template
63 | struct TypedXamlEvent : cppxaml::details::XamlEvent_t> {};
64 |
65 | /**
66 | * @brief Helper base class to inherit from to have a simple implementation of [INotifyPropertyChanged](https://docs.microsoft.com/uwp/api/windows.ui.xaml.data.inotifypropertychanged).
67 | * @tparam T CRTP type
68 | * @details When you declare your class, make this class a base class and pass your class as a template parameter:
69 | * @code
70 | * struct MyPage : MyPageT, SimpleNotifyPropertyChanged {
71 | * cppxaml::XamlPropertyWithNPC MyInt;
72 | *
73 | * MyPage() : INIT_PROPERTY(MyInt, 42) { }
74 | * };
75 | * @endcode
76 | */
77 | template
78 | struct SimpleNotifyPropertyChanged {
79 | public:
80 | using Type = T;
81 | auto PropertyChanged(cppxaml::xaml::Data::PropertyChangedEventHandler const& value) {
82 | return m_propertyChanged.add(value);
83 | }
84 | void PropertyChanged(winrt::event_token const& token) {
85 | m_propertyChanged.remove(token);
86 | }
87 | Type& self() {
88 | return *static_cast(this);
89 | }
90 |
91 | /**
92 | * @brief Raises a property change notification event
93 | * @param name The name of the property
94 | * @return
95 | * @details Usage example\n
96 | * XAML file
97 | * @code{.xml}
98 | *
99 | *
100 | * @endcode
101 | * C++
102 | * @code
103 | * void MyPage::DoSomething() {
104 | * // modify MyInt
105 | * // MyInt = ...
106 | *
107 | * // now send a notification to update the bound UI elements
108 | * RaisePropertyChanged(L"MyInt");
109 | * }
110 | * @endcode
111 | */
112 | auto RaisePropertyChanged(std::wstring_view name) {
113 | return m_propertyChanged(self(), cppxaml::xaml::Data::PropertyChangedEventHandler{name});
114 | }
115 | protected:
116 | winrt::event m_propertyChanged;
117 |
118 | template
119 | friend struct XamlProperty;
120 | };
121 |
122 | /**
123 | * @brief Implements a simple property (without change notifications).
124 | * @tparam T the property type.
125 | */
126 | template
127 | struct XamlProperty {
128 | using Type = T;
129 | T operator()() const {
130 | return m_value;
131 | }
132 | void operator()(const T& value) {
133 | m_value = value;
134 | }
135 |
136 | operator T() {
137 | return m_value;
138 | }
139 |
140 | XamlProperty& operator=(const T& t) {
141 | operator()(t);
142 | return *this;
143 | }
144 |
145 | XamlProperty(const XamlProperty&) = delete;
146 | XamlProperty(XamlProperty&&) = delete;
147 |
148 | template
149 | XamlProperty(TArgs&&... args) : m_value(std::forward(args)...) {}
150 |
151 | private:
152 | Type m_value{};
153 | };
154 |
155 | /**
156 | * @brief Implements a property type with notifications
157 | * @tparam T the property type
158 | * @details Use the #INIT_PROPERTY macro to initialize this property in your class constructor. This will set up the right property name, and bind it to the `SimpleNotifyPropertyChanged` implementation.
159 | */
160 | template
161 | struct XamlPropertyWithNPC : XamlProperty {
162 | using Type = T;
163 |
164 | T operator()() const {
165 | return XamlProperty::operator()();
166 | }
167 |
168 | void operator()(const T& value) {
169 | if (value != operator()()) {
170 | XamlProperty::operator()(value);
171 | if (m_npc) {
172 | (*m_npc)(m_sender, cppxaml::xaml::Data::PropertyChangedEventArgs{ m_name });
173 | }
174 | }
175 | }
176 | template
177 | XamlPropertyWithNPC(
178 | winrt::event* npc,
179 | winrt::Windows::Foundation::IInspectable sender,
180 | std::wstring_view name,
181 | TArgs&&... args) :
182 | XamlProperty(std::forward(args)...) {
183 | m_name = name;
184 | m_npc = npc;
185 | m_sender = sender;
186 | }
187 |
188 | XamlPropertyWithNPC(const XamlPropertyWithNPC&) = default;
189 | XamlPropertyWithNPC(XamlPropertyWithNPC&&) = default;
190 | private:
191 | std::wstring m_name;
192 | winrt::event* m_npc;
193 | winrt::Windows::Foundation::IInspectable m_sender;
194 | };
195 | }
196 |
197 | /**
198 | * @def INIT_PROPERTY
199 | * @brief use this to initialize a cppxaml::XamlPropertyWithNPC in your class constructor.
200 | */
201 | #define INIT_PROPERTY(NAME, VALUE) \
202 | NAME(&m_propertyChanged, winrt::try_as(this), std::wstring_view{ L#NAME }, VALUE)
203 |
204 |
--------------------------------------------------------------------------------
/inc/cppxaml/XamlWindow.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | /** @file
9 | * @author Alexander Sklar
10 | * @section LICENSE
11 | * Copyright (c) Alexander Sklar
12 | *
13 | * Licensed under the MIT license
14 | */
15 |
16 | namespace cppxaml {
17 | struct XamlWindow;
18 |
19 | /**
20 | * @brief `AppController` is responsible for coordinating XamlWindow instances, can extend their wndproc, and provides an opportunity to hook up event handlers once a XAML UI becomes live.
21 | */
22 | struct AppController {
23 | public:
24 | /**
25 | * @brief App-provided callback to be called when any of this controller's windows create their UI (usually Pages).
26 | */
27 | void (*OnUICreated)(winrt::Windows::UI::Xaml::UIElement content, XamlWindow* xw) { nullptr };
28 | LRESULT(*WndProc)(HWND, INT, WPARAM, LPARAM, XamlWindow*) { nullptr };
29 |
30 | /**
31 | * @brief
32 | * @param hInst
33 | * @param xapp
34 | */
35 | AppController(HINSTANCE hInst, winrt::Windows::UI::Xaml::Application xapp) {
36 | m_hInstance = hInst;
37 | m_xapp = xapp;
38 | m_winxamlmanager = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
39 | }
40 |
41 | HINSTANCE HInstance() const {
42 | return m_hInstance;
43 | }
44 |
45 | private:
46 | winrt::Windows::UI::Xaml::Application m_xapp{ nullptr };
47 | HINSTANCE m_hInstance{ nullptr };
48 | winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager m_winxamlmanager{ nullptr };
49 | };
50 |
51 | /**
52 | * @brief Implements an HWND based host for XAML Islands. You can create a `XamlWindow` from one of three overloads of XamlWindow::Make.
53 | */
54 | struct XamlWindow {
55 | private:
56 | XamlWindow(std::wstring_view id) : m_Id(id) {}
57 | winrt::Windows::UI::Xaml::UIElement(*m_getUI) (const XamlWindow& xw) { nullptr };
58 |
59 | // This DesktopWindowXamlSource is the object that enables a non-UWP desktop application
60 | // to host WinRT XAML controls in any UI element that is associated with a window handle (HWND).
61 | winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource m_desktopXamlSource{ nullptr };
62 | HWND m_hWnd{ nullptr };
63 | HACCEL m_hAccelTable{ nullptr };
64 |
65 | AppController* m_controller{ nullptr };
66 | std::wstring m_Id;
67 | std::wstring m_markup;
68 | winrt::Windows::UI::Xaml::UIElement m_ui{ nullptr };
69 |
70 | static inline std::unordered_map s_windows{};
71 | public:
72 | XamlWindow(const XamlWindow&) = delete;
73 | XamlWindow(XamlWindow&& other) noexcept :
74 | m_Id(std::move(other.m_Id)),
75 | m_getUI(std::move(other.m_getUI)),
76 | m_markup(std::move(other.m_markup)),
77 | m_desktopXamlSource(std::move(other.m_desktopXamlSource)),
78 | m_hWnd(std::move(other.m_hWnd)),
79 | m_hAccelTable(std::move(m_hAccelTable)),
80 | m_controller(std::move(other.m_controller))
81 | {}
82 |
83 | /**
84 | * @brief returns the HWND backing the XamlWindow.
85 | * @return
86 | */
87 | HWND hwnd() const {
88 | return m_hWnd;
89 | }
90 |
91 | /**
92 | * @brief returns the XAML UI that the XamlWindow was created with.
93 | * @tparam T XAML type to cast to; defaults to UIElement.
94 | * @return
95 | */
96 | template
97 | T GetUIElement() const {
98 | return m_ui.as();
99 | }
100 |
101 |
102 | /**
103 | * @brief Creates a window that hosts a XAML UI element
104 | * @tparam TUIElement the XAML type to instantiate, usually a subclass of Page; this is usually defined by a separate WinRT Runtime component project, that the XAML Islands project references via C++/WinRT.
105 | * @param id
106 | * @param controller
107 | * @return
108 | * @details Usage: \n
109 | * @code
110 | * auto& mainWindow = cppxaml::XamlWindow::Make(L"MarkupSample", &controller);
111 | * @endcode
112 | */
113 | template
114 | static XamlWindow& Make(std::wstring_view id, AppController* controller = nullptr) {
115 | XamlWindow xw(id);
116 | xw.m_controller = controller;
117 | xw.m_getUI = [](const XamlWindow&) { return TUIElement().as(); };
118 | const auto& entry = s_windows.emplace(id, std::move(xw));
119 | return entry.first->second;
120 | }
121 |
122 | /**
123 | * @brief Creates a window that hosts XAML UI, based on some markup provided as an input parameter.
124 | * @param id
125 | * @param markup XAML markup string to use to create the UI.
126 | * @param c
127 | * @return
128 | * @details
129 | * Usage: \n
130 | * @code
131 | * auto& xw = cppxaml::XamlWindow::Make(L"MyPage", LR"(
132 | *
133 | * Hello
134 | * )", &controller);
135 | * @endcode
136 | */
137 | static XamlWindow& Make(std::wstring_view id, std::wstring_view markup, AppController* c = nullptr) {
138 | XamlWindow xw(id);
139 | xw.m_controller = c;
140 | xw.m_markup = markup;
141 | xw.m_getUI = [](const XamlWindow& xw) {
142 | return winrt::Windows::UI::Xaml::Markup::XamlReader::Load(xw.m_markup)
143 | .as();
144 | };
145 | const auto& entry = s_windows.emplace(id, std::move(xw));
146 | return entry.first->second;
147 | }
148 |
149 | /**
150 | * @brief Creates a window that hosts XAML UI. The UI will be provided by the app.
151 | * @param id
152 | * @param getUI App-provided function to create UI. This can e.g. instantiate XAML types programmatically.
153 | * @param c
154 | * @return
155 | * @details
156 | * Usage: \n
157 | * @code
158 | * auto& xw = cppxaml::XamlWindow::Make(L"Foo", [](auto&...) { return winrt::Windows::UI::Xaml::Controls::Button(); });
159 | * @endcode
160 | */
161 | static XamlWindow& Make(std::wstring_view id, winrt::Windows::UI::Xaml::UIElement(*getUI)(const XamlWindow&), AppController* c = nullptr) {
162 | XamlWindow xw(id);
163 | xw.m_controller = c;
164 | xw.m_getUI = getUI;
165 | const auto& entry = s_windows.emplace(id, std::move(xw));
166 | return entry.first->second;
167 | }
168 |
169 | /**
170 | * @brief returns the window's id
171 | * @return
172 | */
173 | std::wstring_view Id() const {
174 | return m_Id;
175 | }
176 |
177 | /**
178 | * @brief returns the XamlWindow corresponding to the id.
179 | * @param id
180 | * @return
181 | */
182 | static XamlWindow& Get(std::wstring_view id) {
183 | return s_windows.at(std::wstring(id));
184 | }
185 | static constexpr wchar_t const* const WindowClass() {
186 | return L"XamlWindow";
187 | }
188 |
189 | /**
190 | * @brief Call this function to create the actual window. Afterwards, you will call XamlWindow::RunLoop to process window messages.
191 | * @param szTitle The window title.
192 | * @param style The window style. See [Window styles](https://docs.microsoft.com/windows/win32/winmsg/window-styles) and [CreateWindow](https://docs.microsoft.com/windows/win32/api/winuser/nf-winuser-createwindoww).
193 | * @param parent optional parent window.
194 | * @param width optional window width.
195 | * @param height optional window height.
196 | * @param nCmdShow Controls how the window is shown. See [ShowWindow](https://docs.microsoft.com/windows/win32/api/winuser/nf-winuser-showwindow).
197 | * @return
198 | */
199 | HWND Create(wchar_t const* szTitle, DWORD style, HWND parent = nullptr, int width = CW_USEDEFAULT, int height = CW_USEDEFAULT, int nCmdShow = SW_NORMAL) {
200 | static std::once_flag once;
201 |
202 | std::call_once(once, [ctl = this->m_controller]() {
203 | WNDCLASSEXW wcex{};
204 | wcex.cbSize = sizeof(wcex);
205 |
206 | wcex.style = CS_HREDRAW | CS_VREDRAW;
207 | wcex.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT
208 | {
209 | // Get handle to the core window.
210 | auto xw = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA));
211 | if (xw == nullptr && message == WM_CREATE) {
212 | auto createStruct = reinterpret_cast(lParam);
213 |
214 | xw = reinterpret_cast(createStruct->lpCreateParams);
215 | SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(xw));
216 | }
217 |
218 |
219 | return xw ? xw->WndProc(hWnd, message, wParam, lParam) : DefWindowProc(hWnd, message, wParam, lParam);
220 | };
221 |
222 | wcex.cbWndExtra = sizeof(XamlWindow*);
223 | wcex.hInstance = ctl->HInstance();
224 | wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
225 | wcex.lpszClassName = WindowClass();
226 | winrt::check_bool(RegisterClassExW(&wcex) != 0);
227 | });
228 |
229 | m_desktopXamlSource = winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource();
230 | auto hWnd = CreateWindowW(WindowClass(), szTitle, style,
231 | CW_USEDEFAULT, CW_USEDEFAULT, width, height, parent, nullptr, m_controller->HInstance(), this);
232 | if (hWnd) {
233 | ShowWindow(hWnd, nCmdShow);
234 | UpdateWindow(hWnd);
235 | }
236 | return hWnd;
237 | }
238 |
239 | /**
240 | * @brief
241 | * @param acc
242 | */
243 | void SetAcceleratorTable(HACCEL acc) {
244 | m_hAccelTable = acc;
245 | }
246 |
247 | /**
248 | * @brief
249 | * @return
250 | */
251 | AppController* Controller() const {
252 | return m_controller;
253 | }
254 |
255 | /**
256 | * @brief
257 | * @return
258 | */
259 | int RunLoop() {
260 | MSG msg;
261 |
262 | // Main message loop:
263 | while (GetMessage(&msg, nullptr, 0, 0))
264 | {
265 | if (auto xamlSourceNative2 = m_desktopXamlSource.as()) {
266 | BOOL xamlSourceProcessedMessage = FALSE;
267 | winrt::check_hresult(xamlSourceNative2->PreTranslateMessage(&msg, &xamlSourceProcessedMessage));
268 | if (xamlSourceProcessedMessage) {
269 | continue;
270 | }
271 | }
272 |
273 | if (!TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
274 | {
275 | TranslateMessage(&msg);
276 | DispatchMessage(&msg);
277 | }
278 | }
279 | return (int)msg.wParam;
280 | }
281 |
282 | HWND GetBridgeWindow() const {
283 | static HWND hWndXamlIsland = nullptr;
284 | if (!hWndXamlIsland) {
285 | auto interop = m_desktopXamlSource.as();
286 | winrt::check_hresult(interop->get_WindowHandle(&hWndXamlIsland));
287 | }
288 | return hWndXamlIsland;
289 | }
290 |
291 | LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
292 | auto interop = m_desktopXamlSource.as();
293 |
294 | switch (message)
295 | {
296 | case WM_CREATE: {
297 | this->m_hWnd = hwnd;
298 | auto createStruct = reinterpret_cast(lParam);
299 |
300 | // Parent the DesktopWindowXamlSource object to the current window.
301 | winrt::check_hresult(interop->AttachToWindow(m_hWnd)); // This fails due to access violation!
302 |
303 | this->m_ui = this->m_getUI(*this);
304 | if (m_controller && m_controller->OnUICreated) {
305 | m_controller->OnUICreated(m_ui, this);
306 | }
307 | m_desktopXamlSource.Content(m_ui);
308 | break;
309 | }
310 | case WM_SIZE:
311 | {
312 | HWND hWndXamlIsland = nullptr;
313 | winrt::check_hresult(interop->get_WindowHandle(&hWndXamlIsland));
314 |
315 | SetWindowPos(hWndXamlIsland, nullptr, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_SHOWWINDOW);
316 |
317 | break;
318 | }
319 | case WM_NCDESTROY:
320 | {
321 | SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)nullptr);
322 | break;
323 | }
324 | }
325 | if (m_controller && m_controller->WndProc) {
326 | return m_controller->WndProc(hwnd, message, wParam, lParam, this);
327 | }
328 | else return DefWindowProc(hwnd, message, wParam, lParam);
329 |
330 | }
331 | };
332 | }
333 |
--------------------------------------------------------------------------------
/inc/cppxaml/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | /** @file
4 | * @author Alexander Sklar
5 | * @section LICENSE
6 | * Copyright (c) Alexander Sklar
7 | *
8 | * Licensed under the MIT license
9 | */
10 |
11 | /**
12 | * @brief
13 | * @namespace cppxaml
14 | */
15 | namespace cppxaml {
16 |
17 | #ifdef USE_WINUI3
18 | namespace xaml = winrt::Microsoft::UI::Xaml;
19 | #else
20 | namespace xaml = winrt::Windows::UI::Xaml;
21 | #endif
22 |
23 |
24 | /**
25 | * @namespace cppxaml::utils
26 | * @brief Various utilities
27 | */
28 | namespace utils {
29 | /**
30 | * @brief
31 | * @param sv
32 | * @return
33 | */
34 | inline auto tolower(std::wstring_view sv) {
35 | std::wstring copy(sv);
36 | std::transform(copy.begin(), copy.end(), copy.begin(), [](wchar_t x) { return (wchar_t)::tolower(x); });
37 | return copy;
38 | }
39 |
40 | /**
41 | * @brief Maps each element in a container via a unary operation on each element
42 | * @tparam TOutContainer The output container type. Defaults to std::vector.
43 | * @tparam TInContainer The type of the container
44 | * @tparam UnaryOp Lambda type
45 | * @param iterable The container
46 | * @param unary_op The lambda for the unary operation; takes the element type of the input container.
47 | * @return A container comprised of the mapped elements
48 | * @details
49 | * Example:\n
50 | *
51 | *
52 | */
53 | template typename TOutContainer = std::vector, typename TInContainer, typename UnaryOp>
54 | auto transform(TInContainer const& iterable, UnaryOp&& unary_op) {
55 | using result_t = std::invoke_result_t;
56 | TOutContainer out{};
57 | auto o = std::inserter(out, out.end());
58 | for (auto i = iterable.cbegin(); i != iterable.cend(); i++) {
59 | o = unary_op(*i);
60 | }
61 | return out;
62 | }
63 |
64 | /**
65 | * @brief Maps each element in a container via a unary operation on each element
66 | * @tparam TOutContainer The output container type. Defaults to std::vector.
67 | * @tparam TInContainer The type of the container
68 | * @tparam UnaryOp Lambda type
69 | * @param iterable The container
70 | * @param unary_op The lambda for the unary operation; takes the element type of the input container, and the index within the container.
71 | * @return A container comprised of the mapped elements
72 | * @details Example:\n
73 | * Here we can define a Grid with Buttons, each of whose content is sourced from a string vector:
74 | * @code
75 | * auto strs = std::vector{ L"first", L"second", L"third", L"fourth" };
76 | * auto grid = cppxaml::Grid({"40, *"}, {"Auto, Auto"},
77 | * cppxaml::utils::transform_with_index(strs, [](const std::wstring& t, auto index) {
78 | * return cppxaml::details::UIElementInGrid{
79 | * (int)index / 2,
80 | * (int)index % 2,
81 | * cppxaml::Button(winrt::hstring(t))
82 | * };
83 | * })
84 | * );
85 | * @endcode
86 | * Example:\n
87 | * @code
88 | * auto strs = std::vector{ L"first", L"second", L"third", L"fourth" };
89 | * auto grid = cppxaml::Grid({"40, *"}, {"Auto, Auto"},
90 | * cppxaml::utils::transform_with_index(strs, [](const std::wstring& t, auto index) {
91 | * return cppxaml::Button(winrt::hstring(t))
92 | * .Set(Grid::RowProperty(), (int)index / 2)
93 | * .Set(Grid::ColumnProperty(), (int)index % 2);
94 | * };
95 | * })
96 | * );
97 | * @endcode
98 | */
99 | template typename TOutContainer = std::vector, typename TInContainer, typename UnaryOp>
100 | auto transform_with_index(TInContainer const& iterable, UnaryOp&& unary_op) {
101 | using result_t = std::invoke_result_t;
102 | TOutContainer out{};
103 | auto o = std::inserter(out, out.end());
104 | for (auto i = iterable.cbegin(); i != iterable.cend(); i++) {
105 | o = unary_op(*i, i - iterable.cbegin());
106 | }
107 | return out;
108 | }
109 |
110 | }
111 |
112 | /**
113 | * @brief Finds a XAML element by name.
114 | * @tparam T Expected type of the element - defaults to DependencyObject.
115 | * @param d XAML element object.
116 | * @param name The name to search for.
117 | * @return The XAML element whose name matches the one specified as input.
118 | */
119 | template