Browse Source

Merge branch 'master' into fix/RTB_ignores_Shadow

pull/20790/head
Tim 4 days ago
committed by GitHub
parent
commit
956dcb3163
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 181
      .github/workflows/api-diff.yml
  2. 124
      .github/workflows/update-api.yml
  3. 1
      .gitignore
  4. 3
      .gitmodules
  5. 1
      Directory.Packages.props
  6. 4
      api/Avalonia.LinuxFramebuffer.nupkg.xml
  7. 4
      api/Avalonia.Skia.nupkg.xml
  8. 686
      api/Avalonia.nupkg.xml
  9. 2
      build/SharedVersion.props
  10. 1
      external/Numerge
  11. 2
      global.json
  12. 4
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  13. 15
      native/Avalonia.Native/src/OSX/metal.mm
  14. 6
      nukebuild/_build.csproj
  15. BIN
      samples/ControlCatalog/Assets/Sanctuary/city_bg.jpg
  16. BIN
      samples/ControlCatalog/Assets/Sanctuary/forest_bg.jpg
  17. BIN
      samples/ControlCatalog/Assets/Sanctuary/main_arctic_silence.jpg
  18. BIN
      samples/ControlCatalog/Assets/Sanctuary/main_deep_forest.jpg
  19. BIN
      samples/ControlCatalog/Assets/Sanctuary/main_desert_sands.jpg
  20. BIN
      samples/ControlCatalog/Assets/Sanctuary/main_hero.jpg
  21. BIN
      samples/ControlCatalog/Assets/Sanctuary/mountain_bg.jpg
  22. 9
      samples/ControlCatalog/ControlCatalog.csproj
  23. 14
      samples/ControlCatalog/MainView.xaml
  24. 11
      samples/ControlCatalog/Pages/CarouselDemoPage.xaml
  25. 91
      samples/ControlCatalog/Pages/CarouselDemoPage.xaml.cs
  26. 117
      samples/ControlCatalog/Pages/CarouselPage.xaml
  27. 116
      samples/ControlCatalog/Pages/CarouselPage.xaml.cs
  28. 98
      samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml
  29. 1068
      samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs
  30. 119
      samples/ControlCatalog/Pages/CarouselPage/CarouselCustomizationPage.xaml
  31. 48
      samples/ControlCatalog/Pages/CarouselPage/CarouselCustomizationPage.xaml.cs
  32. 60
      samples/ControlCatalog/Pages/CarouselPage/CarouselDataBindingPage.xaml
  33. 95
      samples/ControlCatalog/Pages/CarouselPage/CarouselDataBindingPage.xaml.cs
  34. 557
      samples/ControlCatalog/Pages/CarouselPage/CarouselGalleryAppPage.xaml
  35. 101
      samples/ControlCatalog/Pages/CarouselPage/CarouselGalleryAppPage.xaml.cs
  36. 93
      samples/ControlCatalog/Pages/CarouselPage/CarouselGesturesPage.xaml
  37. 59
      samples/ControlCatalog/Pages/CarouselPage/CarouselGesturesPage.xaml.cs
  38. 74
      samples/ControlCatalog/Pages/CarouselPage/CarouselGettingStartedPage.xaml
  39. 40
      samples/ControlCatalog/Pages/CarouselPage/CarouselGettingStartedPage.xaml.cs
  40. 140
      samples/ControlCatalog/Pages/CarouselPage/CarouselMultiItemPage.xaml
  41. 47
      samples/ControlCatalog/Pages/CarouselPage/CarouselMultiItemPage.xaml.cs
  42. 115
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageCustomizationPage.xaml
  43. 79
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageCustomizationPage.xaml.cs
  44. 44
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageDataTemplatePage.xaml
  45. 209
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageDataTemplatePage.xaml.cs
  46. 37
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageEventsPage.xaml
  47. 92
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageEventsPage.xaml.cs
  48. 61
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageFirstLookPage.xaml
  49. 35
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageFirstLookPage.xaml.cs
  50. 64
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageGesturePage.xaml
  51. 44
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageGesturePage.xaml.cs
  52. 45
      samples/ControlCatalog/Pages/CarouselPage/CarouselPagePerformancePage.xaml
  53. 103
      samples/ControlCatalog/Pages/CarouselPage/CarouselPagePerformancePage.xaml.cs
  54. 90
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageSelectionPage.xaml
  55. 56
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageSelectionPage.xaml.cs
  56. 65
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageTransitionsPage.xaml
  57. 69
      samples/ControlCatalog/Pages/CarouselPage/CarouselPageTransitionsPage.xaml.cs
  58. 97
      samples/ControlCatalog/Pages/CarouselPage/CarouselTransitionsPage.xaml
  59. 66
      samples/ControlCatalog/Pages/CarouselPage/CarouselTransitionsPage.xaml.cs
  60. 132
      samples/ControlCatalog/Pages/CarouselPage/CarouselVerticalPage.xaml
  61. 39
      samples/ControlCatalog/Pages/CarouselPage/CarouselVerticalPage.xaml.cs
  62. 298
      samples/ControlCatalog/Pages/CarouselPage/SanctuaryMainPage.xaml
  63. 11
      samples/ControlCatalog/Pages/CarouselPage/SanctuaryMainPage.xaml.cs
  64. 335
      samples/ControlCatalog/Pages/CarouselPage/SanctuaryShowcasePage.xaml
  65. 70
      samples/ControlCatalog/Pages/CarouselPage/SanctuaryShowcasePage.xaml.cs
  66. 5
      samples/ControlCatalog/Pages/ClipboardPage.xaml.cs
  67. 95
      samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml
  68. 220
      samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml.cs
  69. 1
      samples/ControlCatalog/Pages/CommandBarPage.xaml.cs
  70. 32
      samples/ControlCatalog/Pages/ContentPage/ContentPageCommandBarPage.xaml
  71. 14
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  72. 3
      samples/ControlCatalog/Pages/DrawerDemoPage.xaml.cs
  73. 113
      samples/ControlCatalog/Pages/DrawerPage/DrawerPageBreakpointPage.xaml
  74. 84
      samples/ControlCatalog/Pages/DrawerPage/DrawerPageBreakpointPage.xaml.cs
  75. 5
      samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml
  76. 13
      samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml.cs
  77. 13
      samples/ControlCatalog/Pages/DrawerPage/DrawerPageFirstLookPage.xaml.cs
  78. 8
      samples/ControlCatalog/Pages/DrawerPage/EcoTrackerAppPage.xaml
  79. 3
      samples/ControlCatalog/Pages/NavigationDemoPage.xaml.cs
  80. 51
      samples/ControlCatalog/Pages/NavigationPage/LAvenirAppPage.xaml.cs
  81. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageAppearancePage.xaml.cs
  82. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageAttachedMethodsPage.xaml.cs
  83. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageBackButtonPage.xaml.cs
  84. 7
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageEventsPage.xaml
  85. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageEventsPage.xaml.cs
  86. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageFirstLookPage.xaml.cs
  87. 19
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageGesturePage.xaml.cs
  88. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageInteractiveHeaderPage.xaml.cs
  89. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageModalPage.xaml.cs
  90. 8
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageModalTransitionsPage.xaml.cs
  91. 95
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmNavigation.cs
  92. 86
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmPage.xaml
  93. 32
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmPage.xaml.cs
  94. 252
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmPageFactory.cs
  95. 238
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmViewModels.cs
  96. 6
      samples/ControlCatalog/Pages/NavigationPage/NavigationPagePassDataPage.xaml.cs
  97. 24
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageScrollAwarePage.xaml.cs
  98. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageStackPage.xaml.cs
  99. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageTitlePage.xaml.cs
  100. 5
      samples/ControlCatalog/Pages/NavigationPage/NavigationPageToolbarPage.xaml.cs

181
.github/workflows/api-diff.yml

@ -0,0 +1,181 @@
name: Output API Diff
on:
issue_comment:
types: [created]
permissions: {}
concurrency:
group: api-diff-${{ github.event.issue.number }}
cancel-in-progress: true
jobs:
api-diff:
name: Output API Diff
if: >-
github.event.issue.pull_request
&& contains(github.event.comment.body, '/api-diff')
&& contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Check maintainer permission
uses: actions/github-script@v7
with:
script: |
const { data: permLevel } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.payload.comment.user.login,
});
const allowed = ['admin', 'maintain', 'write'];
if (!allowed.includes(permLevel.permission)) {
core.setFailed(`User @${context.payload.comment.user.login} does not have write access.`);
}
- name: Add reaction to acknowledge command
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'eyes',
});
- name: Get PR branch info
id: pr
uses: actions/github-script@v7
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
if (pr.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`) {
core.setFailed('Cannot run /api-diff on fork PRs — would execute untrusted code.');
return;
}
core.setOutput('ref', pr.head.ref);
core.setOutput('sha', pr.head.sha);
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ steps.pr.outputs.sha }}
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Run OutputApiDiff
run: dotnet run --project ./nukebuild/_build.csproj -- OutputApiDiff
- name: Post API diff as PR comment
if: always() && steps.pr.outcome == 'success'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const diffDir = path.join(process.env.GITHUB_WORKSPACE, 'artifacts', 'api-diff', 'markdown');
const mergedPath = path.join(diffDir, '_diff.md');
let body;
if (fs.existsSync(mergedPath)) {
let diff = fs.readFileSync(mergedPath, 'utf8').trim();
if (!diff || diff.toLowerCase().includes('no changes')) {
body = '### API Diff\n\n✅ No public API changes detected in this PR.';
} else {
const MAX_COMMENT_LENGTH = 60000; // GitHub comment limit is 65536
const header = '### API Diff\n\n';
const footer = '\n\n---\n_Generated by `/api-diff` command._';
const budget = MAX_COMMENT_LENGTH - header.length - footer.length;
if (diff.length > budget) {
diff = diff.substring(0, budget) + '\n\n> ⚠️ Output truncated. See the [full workflow run](' +
`${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` +
') for complete diff.';
}
body = header + diff + footer;
}
} else {
body = '### API Diff\n\n⚠️ No diff output was produced. Check the [workflow run](' +
`${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` +
') for details.';
}
// Collapse into <details> if large
if (body.length > 2000) {
const inner = body;
body = '<details>\n<summary>📋 API Diff (click to expand)</summary>\n\n' + inner + '\n\n</details>';
}
// Update existing bot comment or create a new one
const marker = '<!-- api-diff-bot -->';
body = marker + '\n' + body;
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
per_page: 100,
});
const existing = comments.find(c => c.body?.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Add success reaction
if: success()
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'rocket',
});
- name: Report failure
if: failure()
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: '-1',
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `❌ \`/api-diff\` failed. [See logs](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}).`,
});

124
.github/workflows/update-api.yml

@ -0,0 +1,124 @@
name: Update API Suppressions
on:
issue_comment:
types: [created]
permissions: {}
concurrency:
group: update-api-${{ github.event.issue.number }}
cancel-in-progress: true
jobs:
update-api:
name: Update API Suppressions
if: >-
github.event.issue.pull_request
&& contains(github.event.comment.body, '/update-api')
&& contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Check maintainer permission
uses: actions/github-script@v7
with:
script: |
const { data: permLevel } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.payload.comment.user.login,
});
const allowed = ['admin', 'maintain', 'write'];
if (!allowed.includes(permLevel.permission)) {
core.setFailed(`User @${context.payload.comment.user.login} does not have write access.`);
}
- name: Add reaction to acknowledge command
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'eyes',
});
- name: Get PR branch info
id: pr
uses: actions/github-script@v7
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
if (pr.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`) {
core.setFailed('Cannot run /update-api on fork PRs — would execute untrusted code with write permissions.');
return;
}
core.setOutput('ref', pr.head.ref);
core.setOutput('sha', pr.head.sha);
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ steps.pr.outputs.sha }}
token: ${{ secrets.GITHUB_TOKEN }}
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Run ValidateApiDiff
run: dotnet run --project ./nukebuild/_build.csproj -- ValidateApiDiff --update-api-suppression true
- name: Commit and push changes
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add api/
if git diff --cached --quiet; then
echo "No API suppression changes to commit."
else
git commit -m "Update API suppressions"
git push origin HEAD:${{ steps.pr.outputs.ref }}
fi
- name: Add success reaction
if: success()
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'rocket',
});
- name: Report failure
if: failure()
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: '-1',
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `❌ \`/update-api\` failed. [See logs](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}).`,
});

1
.gitignore

@ -219,3 +219,4 @@ src/Browser/Avalonia.Browser.Blazor/wwwroot
src/Browser/Avalonia.Browser/wwwroot
api/diff
src/Browser/Avalonia.Browser/staticwebassets
.serena

3
.gitmodules

@ -1,6 +1,3 @@
[submodule "Numerge"]
path = external/Numerge
url = https://github.com/kekekeks/Numerge.git
[submodule "XamlX"]
path = external/XamlX
url = https://github.com/kekekeks/XamlX.git

1
Directory.Packages.props

@ -36,6 +36,7 @@
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />
<PackageVersion Include="NuGet.Protocol" Version="7.0.1" />
<PackageVersion Include="Nuke.Common" Version="10.1.0" />
<PackageVersion Include="Numerge" Version="1.0.0" />
<PackageVersion Include="NUnit" Version="4.4.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageVersion Include="Quamotion.RemoteViewing" Version="1.1.211" />

4
api/Avalonia.LinuxFramebuffer.nupkg.xml

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
@ -37,4 +37,4 @@
<Left>baseline/Avalonia.LinuxFramebuffer/lib/net8.0/Avalonia.LinuxFramebuffer.dll</Left>
<Right>current/Avalonia.LinuxFramebuffer/lib/net8.0/Avalonia.LinuxFramebuffer.dll</Right>
</Suppression>
</Suppressions>
</Suppressions>

4
api/Avalonia.Skia.nupkg.xml

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
@ -169,4 +169,4 @@
<Left>baseline/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Left>
<Right>current/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll</Right>
</Suppression>
</Suppressions>
</Suppressions>

686
api/Avalonia.nupkg.xml

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
@ -109,6 +109,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Input.GotFocusEventArgs</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Input.IDataObject</Target>
@ -157,6 +163,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.TextFormatting.TextRange</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IGeometryContext2</Target>
@ -397,6 +409,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.Primitives.SelectionHandleType</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.Remote.RemoteServer</Target>
@ -571,6 +589,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Input.GotFocusEventArgs</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Input.IDataObject</Target>
@ -619,6 +643,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.TextFormatting.TextRange</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IGeometryContext2</Target>
@ -859,6 +889,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.Primitives.SelectionHandleType</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.Remote.RemoteServer</Target>
@ -955,12 +991,36 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.CrossAxisCancelThresholdProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.EdgeSizeProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Input.HoldingState.Cancelled</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Input.InputElement.GotFocusEvent</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Input.InputElement.LostFocusEvent</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.DrawingImage.ViewboxProperty</Target>
@ -1069,12 +1129,72 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.#ctor(Avalonia.Input.IInputElement)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.ClearFocus</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.ClearFocusOnElementRemoved(Avalonia.Input.IInputElement,Avalonia.Visual)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.FindNextElement(Avalonia.Input.NavigationDirection)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.TryMoveFocus(Avalonia.Input.NavigationDirection)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.get_CrossAxisCancelThreshold</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.get_EdgeSize</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.set_CrossAxisCancelThreshold(System.Double)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.set_EdgeSize(System.Double)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.HoldingRoutedEventArgs.#ctor(Avalonia.Input.HoldingState,Avalonia.Point,Avalonia.Input.PointerType)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.ClearFocus</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.IInputRoot.get_KeyboardNavigationHandler</Target>
@ -1177,6 +1297,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.InputElement.OnGotFocus(Avalonia.Input.GotFocusEventArgs)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.InputElement.OnLostFocus(Avalonia.Interactivity.RoutedEventArgs)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.InputElement.RemovePinchEndedHandler(Avalonia.Interactivity.Interactive,System.EventHandler{Avalonia.Input.PinchEndedEventArgs})</Target>
@ -1315,6 +1447,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.SwipeGestureEventArgs.#ctor(System.Int32,Avalonia.Input.SwipeDirection,Avalonia.Vector,Avalonia.Point)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.SwipeGestureEventArgs.get_StartPoint</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.TextInput.TextInputMethodClient.ShowInputPanel</Target>
@ -1375,6 +1519,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.GlyphTypeface@)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
@ -1555,6 +1705,42 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.Start</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.Stop</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.SceneInvalidatedEventArgs.#ctor(Avalonia.Rendering.IRenderRoot,Avalonia.Rect)</Target>
@ -1567,6 +1753,30 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.SleepLoopRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.SleepLoopRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.ThreadProxyRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.ThreadProxyRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Utilities.AvaloniaResourcesIndexReaderWriter.WriteResources(System.IO.Stream,System.Collections.Generic.List{System.ValueTuple{System.String,System.Int32,System.Func{System.IO.Stream}}})</Target>
@ -1639,6 +1849,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.DrawerPage.DrawerBreakpointWidthProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NativeMenuBar.EnableMenuItemClickForwardingProperty</Target>
@ -1651,6 +1867,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Primitives.FlyoutBase.IsOpenProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Primitives.Popup.PlacementModeProperty</Target>
@ -1681,6 +1903,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.TabItem.IconProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.TextBlock.LetterSpacingProperty</Target>
@ -1819,6 +2047,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.DrawerPage.get_DrawerBreakpointWidth</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.DrawerPage.set_DrawerBreakpointWidth(System.Double)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.get_Surfaces</Target>
@ -1855,6 +2095,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PageSelectionChangedEventArgs.#ctor(Avalonia.Controls.Page,Avalonia.Controls.Page)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Platform.DefaultMenuInteractionHandler.GotFocus(System.Object,Avalonia.Input.GotFocusEventArgs)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Platform.IInsetsManager.get_DisplayEdgeToEdge</Target>
@ -1957,12 +2209,36 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Interactivity.Interactive)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.GetTextBinding(Avalonia.Interactivity.Interactive)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Controls.Control,System.String)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Interactivity.Interactive,System.String)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.SetTextBinding(Avalonia.Interactivity.Interactive,Avalonia.Data.BindingBase)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.ToggleButton.add_Checked(System.EventHandler{Avalonia.Interactivity.RoutedEventArgs})</Target>
@ -2029,6 +2305,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.VisualLayerManager.get_IsPopup</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.VisualLayerManager.get_LightDismissOverlayLayer</Target>
@ -2047,12 +2329,30 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.VisualLayerManager.set_IsPopup(System.Boolean)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Screens.ScreenFromWindow(Avalonia.Platform.IWindowBaseImpl)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.TabbedPage.FindNextEnabledTab(System.Int32,System.Int32)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.TabItem.get_Icon</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.TabItem.SubscribeToOwnerProperties(Avalonia.AvaloniaObject)</Target>
@ -2355,31 +2655,55 @@
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Input.HoldingState.Cancelled</Target>
<Target>F:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.CrossAxisCancelThresholdProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.DrawingImage.ViewboxProperty</Target>
<Target>F:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.EdgeSizeProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
<Target>F:Avalonia.Input.HoldingState.Cancelled</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.RadialGradientBrush.RadiusProperty</Target>
<Target>F:Avalonia.Input.InputElement.GotFocusEvent</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Animation.Animation.SetAnimator(Avalonia.Animation.IAnimationSetter,Avalonia.Animation.CustomAnimatorBase)</Target>
<Target>F:Avalonia.Input.InputElement.LostFocusEvent</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.DrawingImage.ViewboxProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.RadialGradientBrush.RadiusProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Animation.Animation.SetAnimator(Avalonia.Animation.IAnimationSetter,Avalonia.Animation.CustomAnimatorBase)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
@ -2467,12 +2791,72 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.#ctor(Avalonia.Input.IInputElement)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.ClearFocus</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.ClearFocusOnElementRemoved(Avalonia.Input.IInputElement,Avalonia.Visual)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.FindNextElement(Avalonia.Input.NavigationDirection)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.FocusManager.TryMoveFocus(Avalonia.Input.NavigationDirection)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.get_CrossAxisCancelThreshold</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.get_EdgeSize</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.set_CrossAxisCancelThreshold(System.Double)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.GestureRecognizers.SwipeGestureRecognizer.set_EdgeSize(System.Double)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.HoldingRoutedEventArgs.#ctor(Avalonia.Input.HoldingState,Avalonia.Point,Avalonia.Input.PointerType)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.ClearFocus</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.IInputRoot.get_KeyboardNavigationHandler</Target>
@ -2575,6 +2959,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.InputElement.OnGotFocus(Avalonia.Input.GotFocusEventArgs)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.InputElement.OnLostFocus(Avalonia.Interactivity.RoutedEventArgs)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.InputElement.RemovePinchEndedHandler(Avalonia.Interactivity.Interactive,System.EventHandler{Avalonia.Input.PinchEndedEventArgs})</Target>
@ -2713,6 +3109,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.SwipeGestureEventArgs.#ctor(System.Int32,Avalonia.Input.SwipeDirection,Avalonia.Vector,Avalonia.Point)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.SwipeGestureEventArgs.get_StartPoint</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Input.TextInput.TextInputMethodClient.ShowInputPanel</Target>
@ -2773,6 +3181,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.GlyphTypeface@)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
@ -2953,6 +3367,42 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.Start</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.DefaultRenderTimer.Stop</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.SceneInvalidatedEventArgs.#ctor(Avalonia.Rendering.IRenderRoot,Avalonia.Rect)</Target>
@ -2965,6 +3415,30 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.SleepLoopRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.SleepLoopRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.ThreadProxyRenderTimer.add_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Rendering.ThreadProxyRenderTimer.remove_Tick(System.Action{System.TimeSpan})</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Utilities.AvaloniaResourcesIndexReaderWriter.WriteResources(System.IO.Stream,System.Collections.Generic.List{System.ValueTuple{System.String,System.Int32,System.Func{System.IO.Stream}}})</Target>
@ -3037,6 +3511,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.DrawerPage.DrawerBreakpointWidthProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NativeMenuBar.EnableMenuItemClickForwardingProperty</Target>
@ -3049,6 +3529,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Primitives.FlyoutBase.IsOpenProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.Primitives.Popup.PlacementModeProperty</Target>
@ -3079,6 +3565,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.TabItem.IconProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.TextBlock.LetterSpacingProperty</Target>
@ -3217,6 +3709,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.DrawerPage.get_DrawerBreakpointWidth</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.DrawerPage.set_DrawerBreakpointWidth(System.Double)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.get_Surfaces</Target>
@ -3253,6 +3757,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PageSelectionChangedEventArgs.#ctor(Avalonia.Controls.Page,Avalonia.Controls.Page)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Platform.DefaultMenuInteractionHandler.GotFocus(System.Object,Avalonia.Input.GotFocusEventArgs)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Platform.IInsetsManager.get_DisplayEdgeToEdge</Target>
@ -3355,12 +3871,36 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Interactivity.Interactive)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.GetTextBinding(Avalonia.Interactivity.Interactive)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Controls.Control,System.String)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Interactivity.Interactive,System.String)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.TextSearch.SetTextBinding(Avalonia.Interactivity.Interactive,Avalonia.Data.BindingBase)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.ToggleButton.add_Checked(System.EventHandler{Avalonia.Interactivity.RoutedEventArgs})</Target>
@ -3427,6 +3967,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.VisualLayerManager.get_IsPopup</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.VisualLayerManager.get_LightDismissOverlayLayer</Target>
@ -3445,12 +3991,30 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Primitives.VisualLayerManager.set_IsPopup(System.Boolean)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.Screens.ScreenFromWindow(Avalonia.Platform.IWindowBaseImpl)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.TabbedPage.FindNextEnabledTab(System.Int32,System.Int32)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.TabItem.get_Icon</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.TabItem.SubscribeToOwnerProperties(Avalonia.AvaloniaObject)</Target>
@ -3787,6 +4351,48 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>E:Avalonia.Input.IInputElement.GotFocus</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>E:Avalonia.Input.IInputElement.LostFocus</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.FindFirstFocusableElement</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.FindLastFocusableElement</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.FindNextElement(Avalonia.Input.NavigationDirection,Avalonia.Input.FindNextElementOptions)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.Focus(Avalonia.Input.IInputElement,Avalonia.Input.NavigationMethod,Avalonia.Input.KeyModifiers)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.TryMoveFocus(Avalonia.Input.NavigationDirection,Avalonia.Input.FindNextElementOptions)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers,System.Nullable{Avalonia.Input.KeyDeviceType})</Target>
@ -3883,6 +4489,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.Start</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.Stop</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Input.IInputRoot.FocusRoot</Target>
@ -4051,6 +4669,48 @@
<Left>baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>E:Avalonia.Input.IInputElement.GotFocus</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>E:Avalonia.Input.IInputElement.LostFocus</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.FindFirstFocusableElement</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.FindLastFocusableElement</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.FindNextElement(Avalonia.Input.NavigationDirection,Avalonia.Input.FindNextElementOptions)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.Focus(Avalonia.Input.IInputElement,Avalonia.Input.NavigationMethod,Avalonia.Input.KeyModifiers)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IFocusManager.TryMoveFocus(Avalonia.Input.NavigationDirection,Avalonia.Input.FindNextElementOptions)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers,System.Nullable{Avalonia.Input.KeyDeviceType})</Target>
@ -4183,6 +4843,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.Start</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Rendering.IRenderTimer.Stop</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Input.IInputRoot.FocusRoot</Target>
@ -4969,4 +5641,4 @@
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
</Suppressions>
</Suppressions>

2
build/SharedVersion.props

@ -8,7 +8,7 @@
<PackageProjectUrl>https://avaloniaui.net/?utm_source=nuget&amp;utm_medium=referral&amp;utm_content=project_homepage_link</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<NoWarn>$(NoWarn);CS1591;NU5104</NoWarn>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon>
<PackageDescription>Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS and with experimental support for Android, iOS and WebAssembly.</PackageDescription>

1
external/Numerge

@ -1 +0,0 @@
Subproject commit 5530e1cbe9e105ff4ebc9da1f4af3253a8756754

2
global.json

@ -1,6 +1,6 @@
{
"sdk": {
"version": "10.0.101",
"version": "10.0.201",
"rollForward": "latestFeature"
},
"test": {

4
native/Avalonia.Native/src/OSX/WindowImpl.mm

@ -563,6 +563,10 @@ NSWindowStyleMask WindowImpl::CalculateStyleMask() {
case SystemDecorationsBorderOnly:
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
if (_canResize && _isEnabled) {
s = s | NSWindowStyleMaskResizable;
}
break;
case SystemDecorationsFull:

15
native/Avalonia.Native/src/OSX/metal.mm

@ -87,11 +87,12 @@ public:
return (__bridge void*) queue;
}
HRESULT ImportIOSurface(void *handle, AvnPixelFormat pixelFormat, IAvnMetalTexture **ppv) override {
HRESULT ImportIOSurface(void *handle, AvnPixelFormat pixelFormat, IAvnMetalTexture **ppv) override {
START_COM_ARP_CALL;
auto surf = (IOSurfaceRef)handle;
auto width = IOSurfaceGetWidth(surf);
auto height = IOSurfaceGetHeight(surf);
auto desc = [MTLTextureDescriptor new];
if(pixelFormat == kAvnRgba8888)
desc.pixelFormat = MTLPixelFormatRGBA8Unorm;
@ -106,13 +107,12 @@ public:
desc.mipmapLevelCount = 1;
desc.sampleCount = 1;
desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
auto texture = [device newTextureWithDescriptor:desc iosurface:surf plane:0];
if(texture == nullptr)
return E_FAIL;
*ppv = new AvnMetalTexture(texture);
return S_OK;
}
HRESULT ImportSharedEvent(void *mtlSharedEventInstance, IAvnMTLSharedEvent**ppv) override {
@ -132,11 +132,12 @@ public:
HRESULT SignalOrWait(IAvnMTLSharedEvent *ev, uint64_t value, bool wait)
{
START_ARP_CALL;
if (@available(macOS 12.0, *))
{
auto e = dynamic_cast<AvnMTLSharedEvent*>(ev);
if(e == nullptr)
return E_FAIL;;
return E_FAIL;
auto buf = [queue commandBuffer];
if(wait)
[buf encodeWaitForEvent:e->GetEvent() value:value];
@ -204,6 +205,7 @@ public:
~AvnMetalRenderSession()
{
START_ARP_CALL;
auto buffer = [_queue commandBuffer];
[buffer presentDrawable: _drawable];
[buffer commit];
@ -227,6 +229,7 @@ public:
}
HRESULT BeginDrawing(IAvnMetalRenderingSession **ret) override {
START_COM_ARP_CALL;
if([NSThread isMainThread])
{
// Flush all existing rendering
@ -289,7 +292,7 @@ class AvnMetalDisplay : public ComSingleObject<IAvnMetalDisplay, &IID_IAvnMetalD
public:
FORWARD_IUNKNOWN()
HRESULT CreateDevice(IAvnMetalDevice **ret) override {
START_COM_ARP_CALL;
auto device = MTLCreateSystemDefaultDevice();
if(device == nil) {
ret = nil;

6
nukebuild/_build.csproj

@ -12,6 +12,7 @@
<ItemGroup>
<PackageReference Include="Nuke.Common" />
<PackageReference Include="MicroCom.CodeGenerator" />
<PackageReference Include="Numerge" />
<!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Mono.Cecil" />
<PackageReference Include="Microsoft.Build.Framework" PrivateAssets="All" />
@ -24,11 +25,6 @@
<ItemGroup>
<NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" />
<NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />
<!-- Common build related files -->
<Compile Include="../external/Numerge/Numerge/**/*.cs"
Exclude="../external/Numerge/Numerge/obj/**/*.cs"
LinkBase="Numerge" />
<EmbeddedResource Include="../build/avalonia.snk" />
</ItemGroup>

BIN
samples/ControlCatalog/Assets/Sanctuary/city_bg.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

BIN
samples/ControlCatalog/Assets/Sanctuary/forest_bg.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

BIN
samples/ControlCatalog/Assets/Sanctuary/main_arctic_silence.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

BIN
samples/ControlCatalog/Assets/Sanctuary/main_deep_forest.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 KiB

BIN
samples/ControlCatalog/Assets/Sanctuary/main_desert_sands.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

BIN
samples/ControlCatalog/Assets/Sanctuary/main_hero.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

BIN
samples/ControlCatalog/Assets/Sanctuary/mountain_bg.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

9
samples/ControlCatalog/ControlCatalog.csproj

@ -11,14 +11,7 @@
<AvaloniaXaml Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
<AvaloniaResource Include="Assets\*" />
<AvaloniaResource Include="Assets\Fonts\*" />
<AvaloniaResource Include="Assets\Restaurant\*" />
<AvaloniaResource Include="Assets\Pulse\*" />
<AvaloniaResource Include="Assets\Movies\*" />
<AvaloniaResource Include="Assets\CurvedHeader\*" />
<AvaloniaResource Include="Assets\RetroGaming\*" />
<AvaloniaResource Include="Assets\ModernApp\*" />
<AvaloniaResource Include="Assets\**\*" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\image1.jpg" />

14
samples/ControlCatalog/MainView.xaml

@ -54,8 +54,15 @@
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<pages:CommandBarPage />
</TabItem>
<TabItem Header="Carousel">
<pages:CarouselPage />
<TabItem Header="Carousel"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<pages:CarouselDemoPage />
</TabItem>
<TabItem Header="CarouselPage"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<pages:CarouselDemoPage />
</TabItem>
<TabItem Header="CheckBox">
@ -161,6 +168,9 @@
<TabItem Header="OpenGL Lease">
<pages:OpenGlLeasePage />
</TabItem>
<TabItem Header="PipsPager">
<pages:PipsPagerPage />
</TabItem>
<TabItem Header="Platform Information">
<pages:PlatformInfoPage />
</TabItem>

11
samples/ControlCatalog/Pages/CarouselDemoPage.xaml

@ -0,0 +1,11 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselDemoPage">
<NavigationPage x:Name="SampleNav">
<NavigationPage.Styles>
<Style Selector="NavigationPage#SampleNav /template/ Border#PART_NavigationBar">
<Setter Property="Background" Value="Transparent" />
</Style>
</NavigationPage.Styles>
</NavigationPage>
</UserControl>

91
samples/ControlCatalog/Pages/CarouselDemoPage.xaml.cs

@ -0,0 +1,91 @@
using System;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselDemoPage : UserControl
{
private static readonly (string Group, string Title, string Description, Func<UserControl> Factory)[] Demos =
{
// Overview
("Overview", "First Look",
"Basic CarouselPage with three pages and page indicator.",
() => new CarouselPageFirstLookPage()),
// Populate
("Populate", "Data Templates",
"Bind CarouselPage to an ObservableCollection, add or remove pages at runtime, and switch the page template.",
() => new CarouselPageDataTemplatePage()),
// Appearance
("Appearance", "Customization",
"Switch slide direction between horizontal and vertical with PageSlide. Page indicator dots update on each selection.",
() => new CarouselPageCustomizationPage()),
// Features
("Features", "Page Transitions",
"Animate page switches with CrossFade or PageSlide.",
() => new CarouselPageTransitionsPage()),
("Features", "Programmatic Selection",
"Jump to any page programmatically with SelectedIndex and respond to SelectionChanged events.",
() => new CarouselPageSelectionPage()),
("Features", "Gesture & Keyboard",
"Swipe left/right to navigate pages. Toggle IsGestureEnabled and IsKeyboardNavigationEnabled.",
() => new CarouselPageGesturePage()),
("Features", "Events",
"SelectionChanged, NavigatedTo, and NavigatedFrom events. Swipe or navigate to see the live event log.",
() => new CarouselPageEventsPage()),
// Performance
("Performance", "Performance Monitor",
"Track page count, live page instances, and managed heap size. Observe how GC reclaims memory after removing pages.",
() => new CarouselPagePerformancePage()),
// Showcases
("Showcases", "Sanctuary",
"Travel discovery app with 3 full-screen immersive pages. Each page has a real background photo, gradient overlay, and themed content. Built as a 1:1 replica of a Stitch design.",
() => new SanctuaryShowcasePage()),
("Showcases", "Care Companion",
"Healthcare onboarding with CarouselPage (3 pages), then a TabbedPage patient dashboard. Skip or complete onboarding to navigate to the dashboard via RemovePage.",
() => new CareCompanionAppPage()),
// Carousel (ItemsControl) demos
("Carousel", "Getting Started",
"Basic Carousel with image items and previous/next navigation buttons.",
() => new CarouselGettingStartedPage()),
("Carousel", "Transitions",
"Configure page transitions: PageSlide, CrossFade, 3D Rotation, or None.",
() => new CarouselTransitionsPage()),
("Carousel", "Customization",
"Adjust orientation and transition type to tailor the carousel layout.",
() => new CarouselCustomizationPage()),
("Carousel", "Gestures & Keyboard",
"Navigate items via swipe gesture and arrow keys. Toggle each input mode on and off.",
() => new CarouselGesturesPage()),
("Carousel", "Vertical Orientation",
"Carousel with Orientation set to Vertical, navigated with Up/Down keys, swipe, or buttons.",
() => new CarouselVerticalPage()),
("Carousel", "Multi-Item Peek",
"Adjust ViewportFraction to show multiple items simultaneously with adjacent cards peeking.",
() => new CarouselMultiItemPage()),
("Carousel", "Data Binding",
"Bind Carousel to an ObservableCollection and add, remove, or shuffle items at runtime.",
() => new CarouselDataBindingPage()),
("Carousel", "Curated Gallery",
"Editorial art gallery app with DrawerPage navigation, hero Carousel with PipsPager dots, and a horizontal peek carousel for collection highlights.",
() => new CarouselGalleryAppPage()),
};
public CarouselDemoPage()
{
InitializeComponent();
Loaded += OnLoaded;
}
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
await SampleNav.PushAsync(NavigationDemoHelper.CreateGalleryHomePage(SampleNav, Demos), null);
}
}
}

117
samples/ControlCatalog/Pages/CarouselPage.xaml

@ -1,44 +1,117 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">An items control that displays its items as pages that fill the control.</TextBlock>
<StackPanel Orientation="Vertical" Spacing="4" HorizontalAlignment="Stretch">
<TextBlock Classes="h2">A swipeable items control that can reveal adjacent pages with ViewportFraction.</TextBlock>
<Grid ColumnDefinitions="Auto,*,Auto"
MaxWidth="660"
<Grid Name="layoutGrid" ColumnDefinitions="Auto,*,Auto" RowDefinitions="*,Auto,*"
MaxWidth="760"
HorizontalAlignment="Stretch" Margin="0 16 0 0">
<Button Name="left" Grid.Column="0" VerticalAlignment="Center" Padding="10,20" Margin="4">
<Path Data="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" Fill="Black"/>
<Button Name="left" Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="10,20" Margin="4">
<Path Name="leftArrow" Data="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" Fill="Black"/>
</Button>
<Carousel Name="carousel" Grid.Column="1">
<Carousel Name="carousel" Grid.Column="1" Grid.Row="1" Background="Transparent" Height="400" Focusable="True" ViewportFraction="1.0">
<Carousel.PageTransition>
<PageSlide Duration="0.25" Orientation="Horizontal" />
</Carousel.PageTransition>
<Image Source="/Assets/delicate-arch-896885_640.jpg"/>
<Image Source="/Assets/hirsch-899118_640.jpg"/>
<Image Source="/Assets/maple-leaf-888807_640.jpg"/>
<Border Margin="14,12" CornerRadius="18" ClipToBounds="True">
<Grid>
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill"/>
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 1: Delicate Arch" Foreground="White" HorizontalAlignment="Center" FontWeight="SemiBold"/>
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="18" ClipToBounds="True">
<Grid>
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill"/>
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 2: Hirsch" Foreground="White" HorizontalAlignment="Center" FontWeight="SemiBold"/>
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="18" ClipToBounds="True">
<Grid>
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill"/>
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 3: Maple Leaf" Foreground="White" HorizontalAlignment="Center" FontWeight="SemiBold"/>
</Border>
</Grid>
</Border>
</Carousel>
<Button Name="right" Grid.Column="2" VerticalAlignment="Center" Padding="10,20" Margin="4">
<Path Data="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" Fill="Black"/>
<Button Name="right" Grid.Column="2" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="10,20" Margin="4">
<Path Name="rightArrow" Data="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" Fill="Black"/>
</Button>
</Grid>
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock VerticalAlignment="Center">Transition</TextBlock>
<ComboBox Name="transition" SelectedIndex="1" VerticalAlignment="Center">
<Separator Margin="0 4"/>
<Grid ColumnDefinitions="160,420" RowDefinitions="Auto, Auto, Auto" RowSpacing="8"
Margin="0 4" MaxWidth="580" HorizontalAlignment="Left">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center">Transition</TextBlock>
<ComboBox SelectedIndex="1" Name="transition" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch">
<ComboBoxItem>None</ComboBoxItem>
<ComboBoxItem>Slide</ComboBoxItem>
<ComboBoxItem>Crossfade</ComboBoxItem>
<ComboBoxItem>3D Rotation</ComboBoxItem>
<ComboBoxItem>Page Slide</ComboBoxItem>
<ComboBoxItem>Cross Fade</ComboBoxItem>
<ComboBoxItem>Rotate 3D</ComboBoxItem>
<ComboBoxItem>Card Stack</ComboBoxItem>
<ComboBoxItem>Wave Reveal</ComboBoxItem>
<ComboBoxItem>Composite (Slide + Fade)</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock VerticalAlignment="Center">Orientation</TextBlock>
<ComboBox Name="orientation" SelectedIndex="0" VerticalAlignment="Center">
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Orientation</TextBlock>
<ComboBox Name="orientation" Grid.Row="1" Grid.Column="1" SelectedIndex="0" HorizontalAlignment="Stretch">
<ComboBoxItem>Horizontal</ComboBoxItem>
<ComboBoxItem>Vertical</ComboBoxItem>
</ComboBox>
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">Viewport Fraction</TextBlock>
<StackPanel Grid.Row="2" Grid.Column="1" Spacing="4" HorizontalAlignment="Stretch">
<Grid ColumnDefinitions="*,56" ColumnSpacing="12">
<Slider Name="viewportFraction"
Minimum="0.33"
Maximum="1"
Value="1.0"
TickFrequency="0.01"
HorizontalAlignment="Stretch" />
<TextBlock Name="viewportFractionIndicator"
Grid.Column="1"
HorizontalAlignment="Stretch"
TextAlignment="Right"
VerticalAlignment="Center"
FontWeight="SemiBold">1.00</TextBlock>
</Grid>
<TextBlock Name="viewportFractionHint"
HorizontalAlignment="Stretch"
Opacity="0.75"
TextWrapping="Wrap"
Text="Values below 1 reveal adjacent pages." />
</StackPanel>
</Grid>
<Separator Margin="0 8"/>
<StackPanel Orientation="Horizontal" Spacing="24" Margin="0 4" MaxWidth="580" HorizontalAlignment="Left">
<CheckBox Name="wrapSelection">Wrap Selection</CheckBox>
<CheckBox Name="swipeEnabled">Swipe Enabled</CheckBox>
</StackPanel>
<Separator Margin="0 8"/>
<StackPanel Spacing="12" MaxWidth="580" HorizontalAlignment="Left">
<StackPanel Orientation="Horizontal" Spacing="24">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock>Total Items:</TextBlock>
<TextBlock Name="itemsCountIndicator" FontWeight="Bold">0</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock>Selected Index:</TextBlock>
<TextBlock Name="selectedIndexIndicator" FontWeight="Bold">0</TextBlock>
</StackPanel>
</StackPanel>
</StackPanel>
</StackPanel>

116
samples/ControlCatalog/Pages/CarouselPage.xaml.cs

@ -1,6 +1,9 @@
using System;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using ControlCatalog.Pages.Transitions;
namespace ControlCatalog.Pages
{
@ -9,28 +12,137 @@ namespace ControlCatalog.Pages
public CarouselPage()
{
InitializeComponent();
left.Click += (s, e) => carousel.Previous();
right.Click += (s, e) => carousel.Next();
transition.SelectionChanged += TransitionChanged;
orientation.SelectionChanged += TransitionChanged;
viewportFraction.ValueChanged += ViewportFractionChanged;
wrapSelection.IsChecked = carousel.WrapSelection;
wrapSelection.IsCheckedChanged += (s, e) =>
{
carousel.WrapSelection = wrapSelection.IsChecked ?? false;
UpdateButtonState();
};
swipeEnabled.IsChecked = carousel.IsSwipeEnabled;
swipeEnabled.IsCheckedChanged += (s, e) =>
{
carousel.IsSwipeEnabled = swipeEnabled.IsChecked ?? false;
};
carousel.PropertyChanged += (s, e) =>
{
if (e.Property == SelectingItemsControl.SelectedIndexProperty)
{
UpdateButtonState();
}
else if (e.Property == Carousel.ViewportFractionProperty)
{
UpdateViewportFractionDisplay();
}
};
carousel.ViewportFraction = viewportFraction.Value;
UpdateButtonState();
UpdateViewportFractionDisplay();
}
private void UpdateButtonState()
{
itemsCountIndicator.Text = carousel.ItemCount.ToString();
selectedIndexIndicator.Text = carousel.SelectedIndex.ToString();
var wrap = carousel.WrapSelection;
left.IsEnabled = wrap || carousel.SelectedIndex > 0;
right.IsEnabled = wrap || carousel.SelectedIndex < carousel.ItemCount - 1;
}
private void ViewportFractionChanged(object? sender, RangeBaseValueChangedEventArgs e)
{
carousel.ViewportFraction = Math.Round(e.NewValue, 2);
UpdateViewportFractionDisplay();
}
private void UpdateViewportFractionDisplay()
{
var value = carousel.ViewportFraction;
viewportFractionIndicator.Text = value.ToString("0.00");
var pagesInView = 1d / value;
viewportFractionHint.Text = value >= 1d
? "1.00 shows a single full page."
: $"{pagesInView:0.##} pages fit in view. Try 0.80 for peeking or 0.33 for three full items.";
}
private void TransitionChanged(object? sender, SelectionChangedEventArgs e)
{
var isVertical = orientation.SelectedIndex == 1;
var axis = isVertical ? PageSlide.SlideAxis.Vertical : PageSlide.SlideAxis.Horizontal;
switch (transition.SelectedIndex)
{
case 0:
carousel.PageTransition = null;
break;
case 1:
carousel.PageTransition = new PageSlide(TimeSpan.FromSeconds(0.25), orientation.SelectedIndex == 0 ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical);
carousel.PageTransition = new PageSlide(TimeSpan.FromSeconds(0.25), axis);
break;
case 2:
carousel.PageTransition = new CrossFade(TimeSpan.FromSeconds(0.25));
break;
case 3:
carousel.PageTransition = new Rotate3DTransition(TimeSpan.FromSeconds(0.5), orientation.SelectedIndex == 0 ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical);
carousel.PageTransition = new Rotate3DTransition(TimeSpan.FromSeconds(0.5), axis);
break;
case 4:
carousel.PageTransition = new CardStackPageTransition(TimeSpan.FromSeconds(0.5), axis);
break;
case 5:
carousel.PageTransition = new WaveRevealPageTransition(TimeSpan.FromSeconds(0.8), axis);
break;
case 6:
carousel.PageTransition = new CompositePageTransition
{
PageTransitions =
{
new PageSlide(TimeSpan.FromSeconds(0.25), axis),
new CrossFade(TimeSpan.FromSeconds(0.25)),
}
};
break;
}
UpdateLayoutForOrientation(isVertical);
}
private void UpdateLayoutForOrientation(bool isVertical)
{
if (isVertical)
{
Grid.SetColumn(left, 1);
Grid.SetRow(left, 0);
Grid.SetColumn(right, 1);
Grid.SetRow(right, 2);
left.Padding = new Thickness(20, 10);
right.Padding = new Thickness(20, 10);
leftArrow.RenderTransform = new Avalonia.Media.RotateTransform(90);
rightArrow.RenderTransform = new Avalonia.Media.RotateTransform(90);
}
else
{
Grid.SetColumn(left, 0);
Grid.SetRow(left, 1);
Grid.SetColumn(right, 2);
Grid.SetRow(right, 1);
left.Padding = new Thickness(10, 20);
right.Padding = new Thickness(10, 20);
leftArrow.RenderTransform = null;
rightArrow.RenderTransform = null;
}
}
}

98
samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml

@ -0,0 +1,98 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CareCompanionAppPage">
<UserControl.Styles>
<Style Selector="PipsPager /template/ ListBox ListBoxItem">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="2,0" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Grid Background="Transparent">
<Border Name="Pip"
Width="6" Height="6" CornerRadius="3"
HorizontalAlignment="Center" VerticalAlignment="Center"
Background="#d1d5db">
<Border.Transitions>
<Transitions>
<DoubleTransition Property="Width" Duration="0:0:0.2" Easing="CubicEaseOut" />
<DoubleTransition Property="Height" Duration="0:0:0.2" Easing="CubicEaseOut" />
<CornerRadiusTransition Property="CornerRadius" Duration="0:0:0.2" Easing="CubicEaseOut" />
<BrushTransition Property="Background" Duration="0:0:0.2" />
</Transitions>
</Border.Transitions>
</Border>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pointerover /template/ Border#Pip">
<Setter Property="Width" Value="8" />
<Setter Property="Height" Value="8" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Background" Value="#b0b0b0" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected /template/ Border#Pip">
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="6" />
<Setter Property="CornerRadius" Value="3" />
<Setter Property="Background" Value="#137fec" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected:pointerover /template/ Border#Pip">
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="6" />
<Setter Property="CornerRadius" Value="3" />
<Setter Property="Background" Value="#0a5bb5" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pressed /template/ Border#Pip">
<Setter Property="Width" Value="6" />
<Setter Property="Height" Value="6" />
<Setter Property="Background" Value="#909090" />
</Style>
</UserControl.Styles>
<DockPanel>
<ScrollViewer x:Name="InfoPanel" DockPanel.Dock="Right" Width="300">
<StackPanel Margin="16" Spacing="16">
<TextBlock Text="Care Companion" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="A patient-focused healthcare companion app. CarouselPage handles onboarding (swipe or tap Next) with PipsPager as custom pill-shaped page indicators. Tapping Skip or Get Started pushes the TabbedPage dashboard and removes the onboarding from the navigation stack." />
<Separator />
<TextBlock Text="Navigation Flow" FontSize="13" FontWeight="SemiBold" />
<StackPanel Spacing="4">
<TextBlock FontSize="12" TextWrapping="Wrap" Text="1. CarouselPage is the NavigationPage root" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="2. Swipe or tap Next to advance pages" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="3. Skip jumps to Get Started page" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="4. Get Started pushes TabbedPage dashboard" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="5. RemovePage(carousel) cleans the stack" />
</StackPanel>
<Separator />
<TextBlock Text="Design" FontSize="13" FontWeight="SemiBold" />
<StackPanel Spacing="4">
<TextBlock FontSize="12" Text="Primary: #137fec (healthcare blue)" />
<TextBlock FontSize="12" Text="Background: #f6f7f8 (off-white)" />
<TextBlock FontSize="12" Text="Cards: #ffffff with border" />
<TextBlock FontSize="12" Text="Success: #10b981 (streak/done)" />
<TextBlock FontSize="12" Text="Roundness: 12-16px corners" />
</StackPanel>
</StackPanel>
</ScrollViewer>
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="8" ClipToBounds="True">
<NavigationPage x:Name="NavPage" />
</Border>
</DockPanel>
</UserControl>

1068
samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs

File diff suppressed because it is too large

119
samples/ControlCatalog/Pages/CarouselPage/CarouselCustomizationPage.xaml

@ -0,0 +1,119 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselCustomizationPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
<Button x:Name="PreviousButton"
Content="Previous"
HorizontalAlignment="Stretch" />
<Button x:Name="NextButton"
Content="Next"
HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Orientation" FontWeight="SemiBold" FontSize="13" />
<ComboBox x:Name="OrientationCombo"
HorizontalAlignment="Stretch"
SelectedIndex="0">
<ComboBoxItem>Horizontal</ComboBoxItem>
<ComboBoxItem>Vertical</ComboBoxItem>
</ComboBox>
<TextBlock Text="Viewport Fraction" FontWeight="SemiBold" FontSize="13" />
<Grid ColumnDefinitions="*,48" ColumnSpacing="8">
<Slider x:Name="ViewportSlider"
Minimum="0.33"
Maximum="1.0"
Value="1.0"
TickFrequency="0.01"
HorizontalAlignment="Stretch" />
<TextBlock x:Name="ViewportLabel"
Grid.Column="1"
Text="1.00"
VerticalAlignment="Center"
HorizontalAlignment="Right"
FontWeight="SemiBold" />
</Grid>
<TextBlock x:Name="ViewportHint"
Text="1.00 shows a single full page."
FontSize="11"
Opacity="0.6"
TextWrapping="Wrap" />
<Separator />
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="14" />
<CheckBox x:Name="WrapSelectionCheck"
Content="Wrap Selection"
IsChecked="False"
IsCheckedChanged="OnWrapSelectionChanged" />
<CheckBox x:Name="SwipeEnabledCheck"
Content="Swipe Enabled"
IsChecked="False"
IsCheckedChanged="OnSwipeEnabledChanged" />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="StatusText"
Text="Orientation: Horizontal"
Opacity="0.7"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Carousel x:Name="DemoCarousel" Height="300">
<Carousel.PageTransition>
<PageSlide Duration="0.25" Orientation="Horizontal" />
</Carousel.PageTransition>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 1: Delicate Arch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 2: Hirsch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 3: Maple Leaf" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
</Carousel>
</Border>
</DockPanel>
</UserControl>

48
samples/ControlCatalog/Pages/CarouselPage/CarouselCustomizationPage.xaml.cs

@ -0,0 +1,48 @@
using System;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselCustomizationPage : UserControl
{
public CarouselCustomizationPage()
{
InitializeComponent();
PreviousButton.Click += (_, _) => DemoCarousel.Previous();
NextButton.Click += (_, _) => DemoCarousel.Next();
OrientationCombo.SelectionChanged += (_, _) => ApplyOrientation();
ViewportSlider.ValueChanged += OnViewportFractionChanged;
}
private void ApplyOrientation()
{
var horizontal = OrientationCombo.SelectedIndex == 0;
var axis = horizontal ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical;
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromSeconds(0.25), axis);
StatusText.Text = $"Orientation: {(horizontal ? "Horizontal" : "Vertical")}";
}
private void OnViewportFractionChanged(object? sender, RangeBaseValueChangedEventArgs e)
{
var value = Math.Round(e.NewValue, 2);
DemoCarousel.ViewportFraction = value;
ViewportLabel.Text = value.ToString("0.00");
ViewportHint.Text = value >= 1d ?
"1.00 shows a single full page." :
$"{1d / value:0.##} pages fit in view. Try 0.80 for peeking.";
}
private void OnWrapSelectionChanged(object? sender, RoutedEventArgs e)
{
DemoCarousel.WrapSelection = WrapSelectionCheck.IsChecked == true;
}
private void OnSwipeEnabledChanged(object? sender, RoutedEventArgs e)
{
DemoCarousel.IsSwipeEnabled = SwipeEnabledCheck.IsChecked == true;
}
}
}

60
samples/ControlCatalog/Pages/CarouselPage/CarouselDataBindingPage.xaml

@ -0,0 +1,60 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:pages="clr-namespace:ControlCatalog.Pages"
x:Class="ControlCatalog.Pages.CarouselDataBindingPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Collection" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
<Button x:Name="PreviousButton" Content="Previous" HorizontalAlignment="Stretch" />
<Button x:Name="NextButton" Content="Next" HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Modify Items" FontWeight="SemiBold" FontSize="13" />
<TextBlock TextWrapping="Wrap" FontSize="11" Opacity="0.6"
Text="The Carousel is bound to an ObservableCollection. Changes reflect immediately." />
<Button x:Name="AddButton" Content="Add Item" HorizontalAlignment="Stretch" />
<Button x:Name="RemoveButton" Content="Remove Current" HorizontalAlignment="Stretch" />
<Button x:Name="ShuffleButton" Content="Shuffle" HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="StatusText" Text="Item: 1 / 4"
Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="6" ClipToBounds="True">
<Carousel x:Name="DemoCarousel"
Height="280"
IsSwipeEnabled="True">
<Carousel.PageTransition>
<CrossFade Duration="0.3" />
</Carousel.PageTransition>
<Carousel.ItemTemplate>
<DataTemplate x:DataType="pages:CarouselCardItem">
<Border CornerRadius="14" Margin="14,12" ClipToBounds="True"
Background="{Binding Background}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8">
<TextBlock Text="{Binding Number}" FontSize="52" FontWeight="Bold"
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="{Binding Title}" FontSize="15" FontWeight="SemiBold"
Foreground="{Binding Accent}" HorizontalAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</Carousel.ItemTemplate>
</Carousel>
</Border>
</DockPanel>
</UserControl>

95
samples/ControlCatalog/Pages/CarouselPage/CarouselDataBindingPage.xaml.cs

@ -0,0 +1,95 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;
namespace ControlCatalog.Pages
{
public class CarouselCardItem
{
public string Number { get; set; } = "";
public string Title { get; set; } = "";
public IBrush Background { get; set; } = Brushes.Gray;
public IBrush Accent { get; set; } = Brushes.White;
}
public partial class CarouselDataBindingPage : UserControl
{
private static readonly (string Title, string Color, string Accent)[] Palette =
{
("Neon Pulse", "#3525CD", "#C3C0FF"), ("Ephemeral Blue", "#0891B2", "#BAF0FA"),
("Forest Forms", "#059669", "#A7F3D0"), ("Golden Hour", "#D97706", "#FDE68A"),
("Crimson Wave", "#BE185D", "#FBCFE8"), ("Stone Age", "#57534E", "#D6D3D1"),
};
private readonly ObservableCollection<CarouselCardItem> _items = new();
private int _addCounter;
public CarouselDataBindingPage()
{
InitializeComponent();
DemoCarousel.ItemsSource = _items;
DemoCarousel.SelectionChanged += OnSelectionChanged;
for (var i = 0; i < 4; i++)
AppendItem();
PreviousButton.Click += (_, _) => DemoCarousel.Previous();
NextButton.Click += (_, _) => DemoCarousel.Next();
AddButton.Click += OnAddItem;
RemoveButton.Click += OnRemoveCurrent;
ShuffleButton.Click += OnShuffle;
UpdateStatus();
}
private void AppendItem()
{
var (title, color, accent) = Palette[_addCounter % Palette.Length];
_items.Add(new CarouselCardItem
{
Number = $"{_items.Count + 1:D2}",
Title = title,
Background = new SolidColorBrush(Color.Parse(color)),
Accent = new SolidColorBrush(Color.Parse(accent)),
});
_addCounter++;
}
private void OnAddItem(object? sender, RoutedEventArgs e)
{
AppendItem();
UpdateStatus();
}
private void OnRemoveCurrent(object? sender, RoutedEventArgs e)
{
if (_items.Count == 0)
return;
var idx = Math.Clamp(DemoCarousel.SelectedIndex, 0, _items.Count - 1);
_items.RemoveAt(idx);
UpdateStatus();
}
private void OnShuffle(object? sender, RoutedEventArgs e)
{
var rng = new Random();
var shuffled = _items.OrderBy(_ => rng.Next()).ToList();
_items.Clear();
foreach (var item in shuffled)
_items.Add(item);
UpdateStatus();
}
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
UpdateStatus();
}
private void UpdateStatus()
{
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {_items.Count}";
}
}
}

557
samples/ControlCatalog/Pages/CarouselPage/CarouselGalleryAppPage.xaml

@ -0,0 +1,557 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselGalleryAppPage"
Background="#F8F9FB">
<UserControl.Resources>
<!-- White pip colors for the hero dark background -->
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForeground" Color="#7FFFFFFF" />
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundPointerOver" Color="#BFFFFFFF" />
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundPressed" Color="#BFFFFFFF" />
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundSelected" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundDisabled" Color="#3FFFFFFF" />
<SolidColorBrush x:Key="PipsPagerNavigationButtonForeground" Color="#7FFFFFFF" />
<SolidColorBrush x:Key="PipsPagerNavigationButtonForegroundPointerOver" Color="#BFFFFFFF" />
<SolidColorBrush x:Key="PipsPagerNavigationButtonForegroundPressed" Color="#BFFFFFFF" />
</UserControl.Resources>
<DockPanel>
<!-- Right info panel — visible when width >= 640px -->
<ScrollViewer x:Name="InfoPanel" DockPanel.Dock="Right" Width="290" IsVisible="False">
<StackPanel Margin="16" Spacing="16">
<TextBlock Text="Curated Gallery" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Art gallery editorial app showcasing a full-bleed hero Carousel synced with a pill-shaped PipsPager, a peek Collection Highlights scroll list, Curators' Choice cards, and a Join the Circle subscription section. Navigation via DrawerPage side menu." />
<Separator />
<TextBlock Text="Navigation Flow" FontSize="13" FontWeight="SemiBold" />
<StackPanel Spacing="4">
<TextBlock FontSize="12" TextWrapping="Wrap" Text="1. DrawerPage: root, side placement" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="2. Hamburger overlaid on hero opens the drawer pane" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="3. Hero: full-bleed Carousel + PipsPager (pill dots)" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="4. PipsPager synced bidirectionally with Carousel" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="5. Mouse drag on hero navigates carousel slides" />
</StackPanel>
<Separator />
<TextBlock Text="Key Code" FontSize="13" FontWeight="SemiBold" />
<Border Background="{DynamicResource SystemControlBackgroundBaseLowBrush}"
CornerRadius="4" Padding="8">
<TextBlock FontFamily="Cascadia Code,Consolas,Menlo,monospace"
FontSize="10" TextWrapping="Wrap"
Text="HeroCarousel.SelectionChanged&#xA; += OnHeroSelectionChanged;&#xA;HeroPager.SelectedIndexChanged&#xA; += OnPagerIndexChanged;&#xA;&#xA;// Bidirectional sync guard&#xA;if (_syncing) return;&#xA;_syncing = true;&#xA;HeroPager.SelectedPageIndex&#xA; = HeroCarousel.SelectedIndex;&#xA;_syncing = false;" />
</Border>
</StackPanel>
</ScrollViewer>
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="8" ClipToBounds="True">
<DrawerPage x:Name="RootDrawer"
DrawerLength="260"
IsGestureEnabled="True">
<DrawerPage.Styles>
<!-- Hide the DrawerPage built-in top bar so only our custom hero overlay bar is shown -->
<Style Selector="DrawerPage#RootDrawer /template/ Border#PART_TopBar">
<Setter Property="IsVisible" Value="False" />
</Style>
</DrawerPage.Styles>
<!-- Drawer header -->
<DrawerPage.DrawerHeader>
<Border Background="#3525CD" Padding="20,32,20,20">
<StackPanel Spacing="4">
<TextBlock Text="CURATED"
FontSize="20"
FontWeight="Bold"
Foreground="White"
LetterSpacing="-0.4" />
<TextBlock Text="The Digital Gallery"
FontSize="12"
Foreground="#C3C0FF"
Opacity="0.85" />
</StackPanel>
</Border>
</DrawerPage.DrawerHeader>
<!-- Drawer menu -->
<DrawerPage.Drawer>
<StackPanel Background="#F8F9FB">
<ListBox x:Name="DrawerMenu"
Background="Transparent"
SelectionChanged="OnDrawerMenuSelectionChanged">
<ListBoxItem Padding="20,14">
<StackPanel Orientation="Horizontal" Spacing="16">
<Path Data="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"
Fill="#3525CD" Width="20" Height="20" Stretch="Uniform" />
<TextBlock Text="Discover" FontSize="15" FontWeight="SemiBold"
Foreground="#191C1E" VerticalAlignment="Center" />
</StackPanel>
</ListBoxItem>
<ListBoxItem Padding="20,14">
<StackPanel Orientation="Horizontal" Spacing="16">
<Path Data="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"
Fill="#464555" Width="20" Height="20" Stretch="Uniform" />
<TextBlock Text="Collection" FontSize="15"
Foreground="#464555" VerticalAlignment="Center" />
</StackPanel>
</ListBoxItem>
<ListBoxItem Padding="20,14">
<StackPanel Orientation="Horizontal" Spacing="16">
<Path Data="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 14l-5-5 1.41-1.41L12 14.17l7.59-7.59L21 8l-9 9z"
Fill="#464555" Width="20" Height="20" Stretch="Uniform" />
<TextBlock Text="Archive" FontSize="15"
Foreground="#464555" VerticalAlignment="Center" />
</StackPanel>
</ListBoxItem>
<ListBoxItem Padding="20,14">
<StackPanel Orientation="Horizontal" Spacing="16">
<Path Data="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"
Fill="#464555" Width="20" Height="20" Stretch="Uniform" />
<TextBlock Text="Profile" FontSize="15"
Foreground="#464555" VerticalAlignment="Center" />
</StackPanel>
</ListBoxItem>
</ListBox>
<Separator Margin="20,8" />
<StackPanel Margin="20,8" Spacing="0">
<TextBlock Text="EXHIBITIONS"
FontSize="11"
FontWeight="Bold"
Foreground="#777587"
LetterSpacing="1.2"
Margin="0,0,0,16" />
<Grid ColumnDefinitions="4,*" Margin="0,0,0,14">
<Border Grid.Column="0" Width="4" Height="38"
CornerRadius="2" Background="#3525CD"
VerticalAlignment="Center" Margin="0,0,14,0" />
<StackPanel Grid.Column="1" Spacing="2" VerticalAlignment="Center">
<TextBlock Text="Neon Pulse" FontSize="14" FontWeight="SemiBold"
Foreground="#191C1E" />
<TextBlock Text="Opens March 20" FontSize="11" Foreground="#777587" />
</StackPanel>
</Grid>
<Grid ColumnDefinitions="4,*" Margin="0,0,0,14">
<Border Grid.Column="0" Width="4" Height="38"
CornerRadius="2" Background="#4F46E5"
VerticalAlignment="Center" Margin="0,0,14,0" />
<StackPanel Grid.Column="1" Spacing="2" VerticalAlignment="Center">
<TextBlock Text="Fragmented Forms" FontSize="14" FontWeight="SemiBold"
Foreground="#191C1E" />
<TextBlock Text="Now Open" FontSize="11" Foreground="#4F46E5" />
</StackPanel>
</Grid>
<Grid ColumnDefinitions="4,*">
<Border Grid.Column="0" Width="4" Height="38"
CornerRadius="2" Background="#B84B00"
VerticalAlignment="Center" Margin="0,0,14,0" />
<StackPanel Grid.Column="1" Spacing="2" VerticalAlignment="Center">
<TextBlock Text="The Digital Horizon" FontSize="14" FontWeight="SemiBold"
Foreground="#191C1E" />
<TextBlock Text="Closing Soon" FontSize="11" Foreground="#B84B00" />
</StackPanel>
</Grid>
</StackPanel>
</StackPanel>
</DrawerPage.Drawer>
<!-- Main content: hero carousel IS the header -->
<DrawerPage.Content>
<Grid RowDefinitions="Auto,*">
<!-- Row 0: Hero carousel header — also handles mouse drag for swipe navigation -->
<Grid Height="320"
PointerPressed="OnHeroPointerPressed"
PointerReleased="OnHeroPointerReleased"
PointerCaptureLost="OnHeroPointerCaptureLost">
<!-- Full-bleed hero carousel -->
<Carousel x:Name="HeroCarousel"
IsSwipeEnabled="True">
<Carousel.PageTransition>
<PageSlide Duration="0.35" Orientation="Horizontal" />
</Carousel.PageTransition>
<!-- Hero 1 -->
<Grid>
<Image Source="/Assets/ModernApp/gallery_city.jpg" Stretch="UniformToFill" />
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#88000000" Offset="0" />
<GradientStop Color="#00000000" Offset="0.35" />
<GradientStop Color="#00000000" Offset="0.55" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel VerticalAlignment="Bottom" Margin="20,0,20,44" Spacing="4">
<TextBlock Text="FEATURED EXHIBITION"
FontSize="11" FontWeight="Bold"
Foreground="#C3C0FF" LetterSpacing="1.5" />
<TextBlock Text="Neon Pulse: The New Abstract"
FontSize="22" FontWeight="Bold"
Foreground="White" TextWrapping="Wrap" LetterSpacing="-0.4" />
</StackPanel>
</Grid>
<!-- Hero 2 -->
<Grid>
<Image Source="/Assets/ModernApp/gallery_alpine.jpg" Stretch="UniformToFill" />
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#88000000" Offset="0" />
<GradientStop Color="#00000000" Offset="0.35" />
<GradientStop Color="#00000000" Offset="0.55" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel VerticalAlignment="Bottom" Margin="20,0,20,44" Spacing="4">
<TextBlock Text="NOW OPEN"
FontSize="11" FontWeight="Bold"
Foreground="#C3C0FF" LetterSpacing="1.5" />
<TextBlock Text="Fragmented Forms: Sculpture Today"
FontSize="22" FontWeight="Bold"
Foreground="White" TextWrapping="Wrap" LetterSpacing="-0.4" />
</StackPanel>
</Grid>
<!-- Hero 3 -->
<Grid>
<Image Source="/Assets/ModernApp/gallery_venice.jpg" Stretch="UniformToFill" />
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#88000000" Offset="0" />
<GradientStop Color="#00000000" Offset="0.35" />
<GradientStop Color="#00000000" Offset="0.55" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel VerticalAlignment="Bottom" Margin="20,0,20,44" Spacing="4">
<TextBlock Text="CLOSING SOON"
FontSize="11" FontWeight="Bold"
Foreground="#FFCDD2" LetterSpacing="1.5" />
<TextBlock Text="The Digital Horizon: Web3 &amp; Generative Art"
FontSize="22" FontWeight="Bold"
Foreground="White" TextWrapping="Wrap" LetterSpacing="-0.4" />
</StackPanel>
</Grid>
</Carousel>
<!-- PipsPager overlaid near bottom of hero — pill-shaped, no nav arrows -->
<PipsPager x:Name="HeroPager"
NumberOfPages="3"
IsPreviousButtonVisible="False"
IsNextButtonVisible="False"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,18">
<PipsPager.Styles>
<Style Selector="PipsPager /template/ ListBox ListBoxItem">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="2,0" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Grid Background="Transparent">
<Border Name="Pip"
Width="6" Height="6" CornerRadius="3"
HorizontalAlignment="Center" VerticalAlignment="Center"
Background="#7FFFFFFF">
<Border.Transitions>
<Transitions>
<DoubleTransition Property="Width" Duration="0:0:0.2" Easing="CubicEaseOut" />
<CornerRadiusTransition Property="CornerRadius" Duration="0:0:0.2" Easing="CubicEaseOut" />
<BrushTransition Property="Background" Duration="0:0:0.2" />
</Transitions>
</Border.Transitions>
</Border>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pointerover /template/ Border#Pip">
<Setter Property="Width" Value="8" />
<Setter Property="Height" Value="8" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Background" Value="#BFFFFFFF" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected /template/ Border#Pip">
<Setter Property="Width" Value="22" />
<Setter Property="Height" Value="6" />
<Setter Property="CornerRadius" Value="3" />
<Setter Property="Background" Value="#FFFFFFFF" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected:pointerover /template/ Border#Pip">
<Setter Property="Width" Value="22" />
<Setter Property="Height" Value="6" />
<Setter Property="CornerRadius" Value="3" />
<Setter Property="Background" Value="#E8FFFFFF" />
</Style>
</PipsPager.Styles>
</PipsPager>
<!-- Top bar overlaid on hero -->
<Grid ColumnDefinitions="Auto,*,Auto"
VerticalAlignment="Top"
Margin="4,8,4,0">
<Button Grid.Column="0"
Background="Transparent"
BorderThickness="0"
Padding="12,8"
Click="OnHamburgerClick">
<Path Data="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"
Fill="White" Width="22" Height="22" Stretch="Uniform" />
</Button>
<TextBlock Grid.Column="1"
Text="Curated"
FontSize="18"
FontWeight="Bold"
Foreground="White"
VerticalAlignment="Center"
HorizontalAlignment="Center"
LetterSpacing="-0.3" />
<Button Grid.Column="2"
Background="Transparent"
BorderThickness="0"
Padding="12,8">
<Path Data="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"
Fill="White" Width="22" Height="22" Stretch="Uniform" />
</Button>
</Grid>
</Grid>
<!-- Row 1: Scrollable body -->
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<StackPanel>
<!-- Collection Highlights -->
<StackPanel Margin="0,28,0,0">
<Grid ColumnDefinitions="*,Auto" Margin="20,0,20,16">
<TextBlock Text="Collection Highlights"
FontSize="18" FontWeight="Bold"
Foreground="#191C1E" LetterSpacing="-0.3" />
<TextBlock Grid.Column="1"
Text="SEE ALL"
FontSize="12" FontWeight="Bold"
Foreground="#3525CD" LetterSpacing="0.8"
VerticalAlignment="Center" />
</Grid>
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled"
Margin="20,0,0,0">
<StackPanel Orientation="Horizontal" Spacing="10">
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/ModernApp/gallery_paris.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10">
<StackPanel Spacing="2">
<TextBlock Text="SCULPTURE" FontSize="10" FontWeight="Bold"
Foreground="#C3C0FF" LetterSpacing="1" />
<TextBlock Text="Fragmented Grace" FontSize="13"
FontWeight="SemiBold" Foreground="White" />
</StackPanel>
</Border>
</Grid>
</Border>
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/ModernApp/gallery_bay.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10">
<StackPanel Spacing="2">
<TextBlock Text="OIL PAINTING" FontSize="10" FontWeight="Bold"
Foreground="#C3C0FF" LetterSpacing="1" />
<TextBlock Text="Ephemeral Blue" FontSize="13"
FontWeight="SemiBold" Foreground="White" />
</StackPanel>
</Border>
</Grid>
</Border>
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/ModernApp/gallery_tropical.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10">
<StackPanel Spacing="2">
<TextBlock Text="TEXTILE" FontSize="10" FontWeight="Bold"
Foreground="#C3C0FF" LetterSpacing="1" />
<TextBlock Text="Interwoven Lines" FontSize="13"
FontWeight="SemiBold" Foreground="White" />
</StackPanel>
</Border>
</Grid>
</Border>
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/ModernApp/gallery_alpine.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10">
<StackPanel Spacing="2">
<TextBlock Text="PHOTOGRAPHY" FontSize="10" FontWeight="Bold"
Foreground="#C3C0FF" LetterSpacing="1" />
<TextBlock Text="Silent Mountains" FontSize="13"
FontWeight="SemiBold" Foreground="White" />
</StackPanel>
</Border>
</Grid>
</Border>
<!-- Padding card to reveal peek of last item -->
<Border Width="20" Height="210" />
</StackPanel>
</ScrollViewer>
</StackPanel>
<!-- Curators' Choice -->
<StackPanel Margin="20,32,20,0" Spacing="12">
<TextBlock Text="Curators' Choice"
FontSize="20" FontWeight="Bold"
Foreground="#191C1E" HorizontalAlignment="Center"
LetterSpacing="-0.3" />
<TextBlock Text="Hand-picked selections from our global network of artists."
FontSize="13" Foreground="#777587"
HorizontalAlignment="Center" TextAlignment="Center"
TextWrapping="Wrap" Margin="0,0,0,8" />
<!-- Two-column layout: large card left, two stacked badge cards right -->
<Grid ColumnDefinitions="*,130">
<!-- Left: main feature card -->
<Border Grid.Column="0" Background="White" CornerRadius="16"
Padding="20" Margin="0,0,10,0"
BoxShadow="0 2 16 0 #12191C1E">
<StackPanel Spacing="10">
<Path Data="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5z"
Fill="#3525CD" Width="22" Height="22" Stretch="Uniform"
HorizontalAlignment="Left" />
<TextBlock Text="The Digital Horizon"
FontSize="17" FontWeight="Bold"
Foreground="#191C1E" TextWrapping="Wrap" />
<TextBlock Text="Exploring Web3 and Generative Art"
FontSize="13" Foreground="#777587" TextWrapping="Wrap" />
<Button Content="EXPLORE"
Margin="0,10,0,0" Padding="20,11"
FontSize="11" FontWeight="Bold" LetterSpacing="0.8"
CornerRadius="22" Foreground="White" HorizontalAlignment="Left">
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#3525CD" Offset="0" />
<GradientStop Color="#4F46E5" Offset="1" />
</LinearGradientBrush>
</Button.Background>
</Button>
</StackPanel>
</Border>
<!-- Right: two stacked badge cards -->
<StackPanel Grid.Column="1" Spacing="10">
<Border Background="White" CornerRadius="16"
BoxShadow="0 2 16 0 #12191C1E"
Padding="12">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="8" Margin="0,12">
<Path Data="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z"
Fill="#B84B00" Width="28" Height="28" Stretch="Uniform"
HorizontalAlignment="Center" />
<TextBlock Text="TRENDING"
FontSize="10" FontWeight="Bold"
Foreground="#B84B00" LetterSpacing="1"
HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Background="#EDEEF0" CornerRadius="16" Padding="12">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="8" Margin="0,12">
<Path Data="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1.41 14.06L6.17 11.64l1.42-1.41 2.99 3 6.01-6.01 1.42 1.41-7.42 7.43z"
Fill="#464555" Width="28" Height="28" Stretch="Uniform"
HorizontalAlignment="Center" />
<TextBlock Text="VERIFIED"
FontSize="10" FontWeight="Bold"
Foreground="#464555" LetterSpacing="1"
HorizontalAlignment="Center" />
</StackPanel>
</Border>
</StackPanel>
</Grid>
</StackPanel>
<!-- Join the Circle -->
<Border Margin="20,32,20,32" CornerRadius="20" Padding="24" ClipToBounds="True">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#3525CD" Offset="0" />
<GradientStop Color="#4F46E5" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel Spacing="10">
<TextBlock Text="Join the Circle"
FontSize="20" FontWeight="Bold"
Foreground="White" LetterSpacing="-0.3" />
<TextBlock Text="Receive exclusive invitations to private viewings and new drop alerts."
FontSize="13" Foreground="#C3C0FF"
TextWrapping="Wrap" Opacity="0.9" LineHeight="20" />
<TextBox PlaceholderText="Your email address"
Margin="0,6,0,0"
CornerRadius="12"
BorderThickness="1"
Padding="14,12"
Foreground="White"
PlaceholderForeground="#9896D8">
<TextBox.Resources>
<SolidColorBrush x:Key="TextControlBackground" Color="#3C38B5" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver" Color="#4440BE" />
<SolidColorBrush x:Key="TextControlBackgroundFocused" Color="#3C38B5" />
<SolidColorBrush x:Key="TextControlBorderBrush" Color="#5552C8" />
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver" Color="#7370D8" />
<SolidColorBrush x:Key="TextControlBorderBrushFocused" Color="#8B88E8" />
</TextBox.Resources>
</TextBox>
<Button Content="SUBSCRIBE"
Margin="0,2,0,0" Padding="24,12"
FontSize="12" FontWeight="Bold" LetterSpacing="1"
CornerRadius="24" Foreground="#3525CD" Background="White"
HorizontalAlignment="Left" />
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
</DrawerPage.Content>
</DrawerPage>
</Border>
</DockPanel>
</UserControl>

101
samples/ControlCatalog/Pages/CarouselPage/CarouselGalleryAppPage.xaml.cs

@ -0,0 +1,101 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselGalleryAppPage : UserControl
{
private bool _syncing;
private Point _dragStart;
private bool _isDragging;
private const double SwipeThreshold = 50;
private ScrollViewer? _infoPanel;
public CarouselGalleryAppPage()
{
InitializeComponent();
_infoPanel = this.FindControl<ScrollViewer>("InfoPanel");
HeroCarousel.SelectionChanged += OnHeroSelectionChanged;
HeroPager.SelectedIndexChanged += OnPagerIndexChanged;
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
UpdateInfoPanelVisibility();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == BoundsProperty)
UpdateInfoPanelVisibility();
}
private void UpdateInfoPanelVisibility()
{
if (_infoPanel != null)
_infoPanel.IsVisible = Bounds.Width >= 640;
}
private void OnHamburgerClick(object? sender, RoutedEventArgs e)
{
RootDrawer.IsOpen = !RootDrawer.IsOpen;
}
private void OnHeroSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (_syncing)
return;
_syncing = true;
HeroPager.SelectedPageIndex = HeroCarousel.SelectedIndex;
_syncing = false;
}
private void OnPagerIndexChanged(object? sender, PipsPagerSelectedIndexChangedEventArgs e)
{
if (_syncing)
return;
_syncing = true;
HeroCarousel.SelectedIndex = e.NewIndex;
_syncing = false;
}
private void OnDrawerMenuSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
RootDrawer.IsOpen = false;
DrawerMenu.SelectedItem = null;
}
private void OnHeroPointerPressed(object? sender, PointerPressedEventArgs e)
{
if (!e.GetCurrentPoint(null).Properties.IsLeftButtonPressed)
return;
_dragStart = e.GetPosition((Visual?)sender);
_isDragging = true;
}
private void OnHeroPointerReleased(object? sender, PointerReleasedEventArgs e)
{
if (!_isDragging)
return;
_isDragging = false;
var delta = e.GetPosition((Visual?)sender).X - _dragStart.X;
if (Math.Abs(delta) < SwipeThreshold)
return;
if (delta < 0)
HeroCarousel.Next();
else
HeroCarousel.Previous();
}
private void OnHeroPointerCaptureLost(object? sender, PointerCaptureLostEventArgs e)
{
_isDragging = false;
}
}
}

93
samples/ControlCatalog/Pages/CarouselPage/CarouselGesturesPage.xaml

@ -0,0 +1,93 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselGesturesPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="13" />
<CheckBox x:Name="SwipeCheck"
Content="Swipe Gesture"
IsChecked="True"
IsCheckedChanged="OnSwipeEnabledChanged" />
<CheckBox x:Name="WrapCheck"
Content="Wrap Selection"
IsChecked="False"
IsCheckedChanged="OnWrapSelectionChanged" />
<CheckBox x:Name="KeyboardCheck"
Content="Keyboard Navigation"
IsChecked="True"
IsCheckedChanged="OnKeyboardEnabledChanged" />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="StatusText"
Text="Item: 1 / 3"
Opacity="0.7"
TextWrapping="Wrap" />
<TextBlock x:Name="LastActionText"
Text="Action: —"
Opacity="0.7"
TextWrapping="Wrap" />
<TextBlock Text="Swipe left/right or use arrow keys to navigate."
FontSize="11"
Opacity="0.5"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Carousel x:Name="DemoCarousel"
Focusable="True"
IsSwipeEnabled="True"
Height="300">
<Carousel.PageTransition>
<PageSlide Duration="0.25" Orientation="Horizontal" />
</Carousel.PageTransition>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 1: Delicate Arch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 2: Hirsch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 3: Maple Leaf" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
</Carousel>
</Border>
</DockPanel>
</UserControl>

59
samples/ControlCatalog/Pages/CarouselPage/CarouselGesturesPage.xaml.cs

@ -0,0 +1,59 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselGesturesPage : UserControl
{
private bool _keyboardEnabled = true;
public CarouselGesturesPage()
{
InitializeComponent();
DemoCarousel.AddHandler(InputElement.KeyDownEvent, OnKeyDown, handledEventsToo: true);
DemoCarousel.SelectionChanged += OnSelectionChanged;
DemoCarousel.Loaded += (_, _) => DemoCarousel.Focus();
}
private void OnKeyDown(object? sender, KeyEventArgs e)
{
if (!_keyboardEnabled)
return;
switch (e.Key)
{
case Key.Left:
case Key.Up:
LastActionText.Text = $"Action: Key {e.Key} (Previous)";
break;
case Key.Right:
case Key.Down:
LastActionText.Text = $"Action: Key {e.Key} (Next)";
break;
}
}
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {DemoCarousel.ItemCount}";
if (DemoCarousel.IsSwiping)
LastActionText.Text = "Action: Swipe";
}
private void OnSwipeEnabledChanged(object? sender, RoutedEventArgs e)
{
DemoCarousel.IsSwipeEnabled = SwipeCheck.IsChecked == true;
}
private void OnWrapSelectionChanged(object? sender, RoutedEventArgs e)
{
DemoCarousel.WrapSelection = WrapCheck.IsChecked == true;
}
private void OnKeyboardEnabledChanged(object? sender, RoutedEventArgs e)
{
_keyboardEnabled = KeyboardCheck.IsChecked == true;
}
}
}

74
samples/ControlCatalog/Pages/CarouselPage/CarouselGettingStartedPage.xaml

@ -0,0 +1,74 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselGettingStartedPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
<Button x:Name="PreviousButton"
Content="Previous"
HorizontalAlignment="Stretch" />
<Button x:Name="NextButton"
Content="Next"
HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="StatusText"
Text="Item: 1 / 3"
Opacity="0.7"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Carousel x:Name="DemoCarousel" Height="300" IsSwipeEnabled="True">
<Carousel.PageTransition>
<PageSlide Duration="0.25" Orientation="Horizontal" />
</Carousel.PageTransition>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 1: Delicate Arch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 2: Hirsch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 3: Maple Leaf" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
</Carousel>
</Border>
</DockPanel>
</UserControl>

40
samples/ControlCatalog/Pages/CarouselPage/CarouselGettingStartedPage.xaml.cs

@ -0,0 +1,40 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselGettingStartedPage : UserControl
{
public CarouselGettingStartedPage()
{
InitializeComponent();
PreviousButton.Click += OnPrevious;
NextButton.Click += OnNext;
DemoCarousel.SelectionChanged += OnSelectionChanged;
}
private void OnPrevious(object? sender, RoutedEventArgs e)
{
DemoCarousel.Previous();
UpdateStatus();
}
private void OnNext(object? sender, RoutedEventArgs e)
{
DemoCarousel.Next();
UpdateStatus();
}
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
UpdateStatus();
}
private void UpdateStatus()
{
var index = DemoCarousel.SelectedIndex + 1;
var count = DemoCarousel.ItemCount;
StatusText.Text = $"Item: {index} / {count}";
}
}
}

140
samples/ControlCatalog/Pages/CarouselPage/CarouselMultiItemPage.xaml

@ -0,0 +1,140 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselMultiItemPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
<Button x:Name="PreviousButton" Content="Previous" HorizontalAlignment="Stretch" />
<Button x:Name="NextButton" Content="Next" HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Viewport Fraction" FontWeight="SemiBold" FontSize="13" />
<TextBlock TextWrapping="Wrap" FontSize="11" Opacity="0.6"
Text="Values below 1.0 show adjacent items peeking into the viewport." />
<Grid ColumnDefinitions="*,48" ColumnSpacing="8">
<Slider x:Name="ViewportSlider"
Minimum="0.2" Maximum="1.0" Value="0.5"
TickFrequency="0.01" IsSnapToTickEnabled="True"
HorizontalAlignment="Stretch"
ValueChanged="OnViewportFractionChanged" />
<TextBlock x:Name="ViewportLabel" Grid.Column="1"
Text="0.50" VerticalAlignment="Center"
HorizontalAlignment="Right" FontWeight="SemiBold" />
</Grid>
<TextBlock x:Name="ViewportHint"
Text="~2 items visible."
FontSize="11" Opacity="0.6" TextWrapping="Wrap" />
<Separator />
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="13" />
<CheckBox x:Name="WrapCheck" Content="Wrap Selection" IsChecked="False"
IsCheckedChanged="OnWrapChanged" />
<CheckBox x:Name="SwipeCheck" Content="Swipe / Drag" IsChecked="True"
IsCheckedChanged="OnSwipeChanged" />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="StatusText" Text="Item: 1 / 5"
Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="6" ClipToBounds="True">
<Carousel x:Name="DemoCarousel"
Height="280"
ViewportFraction="0.5"
IsSwipeEnabled="True">
<Carousel.PageTransition>
<PageSlide Duration="0.3" Orientation="Horizontal" />
</Carousel.PageTransition>
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#3525CD" Offset="0" />
<GradientStop Color="#6B5CE7" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8">
<TextBlock Text="01" FontSize="52" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Neon Pulse" FontSize="15" FontWeight="SemiBold"
Foreground="#C3C0FF" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#0891B2" Offset="0" />
<GradientStop Color="#06B6D4" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8">
<TextBlock Text="02" FontSize="52" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Ephemeral Blue" FontSize="15" FontWeight="SemiBold"
Foreground="#BAF0FA" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#059669" Offset="0" />
<GradientStop Color="#10B981" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8">
<TextBlock Text="03" FontSize="52" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Forest Forms" FontSize="15" FontWeight="SemiBold"
Foreground="#A7F3D0" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#D97706" Offset="0" />
<GradientStop Color="#F59E0B" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8">
<TextBlock Text="04" FontSize="52" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Golden Hour" FontSize="15" FontWeight="SemiBold"
Foreground="#FDE68A" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#BE185D" Offset="0" />
<GradientStop Color="#EC4899" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8">
<TextBlock Text="05" FontSize="52" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Crimson Wave" FontSize="15" FontWeight="SemiBold"
Foreground="#FBCFE8" HorizontalAlignment="Center" />
</StackPanel>
</Border>
</Carousel>
</Border>
</DockPanel>
</UserControl>

47
samples/ControlCatalog/Pages/CarouselPage/CarouselMultiItemPage.xaml.cs

@ -0,0 +1,47 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselMultiItemPage : UserControl
{
public CarouselMultiItemPage()
{
InitializeComponent();
PreviousButton.Click += (_, _) => DemoCarousel.Previous();
NextButton.Click += (_, _) => DemoCarousel.Next();
DemoCarousel.SelectionChanged += OnSelectionChanged;
}
private void OnViewportFractionChanged(object? sender, RangeBaseValueChangedEventArgs e)
{
if (DemoCarousel is null)
return;
var value = Math.Round(e.NewValue, 2);
DemoCarousel.ViewportFraction = value;
ViewportLabel.Text = value.ToString("0.00");
ViewportHint.Text = value >= 1d ? "1.00 — single full item." : $"~{1d / value:0.#} items visible.";
}
private void OnWrapChanged(object? sender, RoutedEventArgs e)
{
if (DemoCarousel is null)
return;
DemoCarousel.WrapSelection = WrapCheck.IsChecked == true;
}
private void OnSwipeChanged(object? sender, RoutedEventArgs e)
{
if (DemoCarousel is null)
return;
DemoCarousel.IsSwipeEnabled = SwipeCheck.IsChecked == true;
}
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {DemoCarousel.ItemCount}";
}
}
}

115
samples/ControlCatalog/Pages/CarouselPage/CarouselPageCustomizationPage.xaml

@ -0,0 +1,115 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPageCustomizationPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Slide Direction" FontWeight="SemiBold" FontSize="13" />
<ComboBox x:Name="OrientationCombo" SelectedIndex="0"
SelectionChanged="OnOrientationChanged"
HorizontalAlignment="Stretch">
<ComboBoxItem Content="Horizontal" />
<ComboBoxItem Content="Vertical" />
</ComboBox>
<Separator />
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="6">
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" />
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" />
</StackPanel>
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" />
<TextBlock x:Name="StatusText" Text="—" Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Panel>
<CarouselPage x:Name="DemoCarousel">
<ContentPage Header="Sunrise"
Background="#FFFDE68A"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8">
<Border Width="64" Height="64" CornerRadius="32"
Background="#F59E0B" />
<TextBlock Text="Sunrise" FontSize="28" FontWeight="Bold"
Foreground="#92400E" HorizontalAlignment="Center" />
<TextBlock Text="A new day begins. Warm golden hues fill the horizon."
FontSize="13" Foreground="#92400E" Opacity="0.8"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" />
</StackPanel>
</ContentPage>
<ContentPage Header="Ocean"
Background="#FFBFDBFE"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8">
<Border Width="64" Height="64" CornerRadius="32"
Background="#3B82F6" />
<TextBlock Text="Ocean" FontSize="28" FontWeight="Bold"
Foreground="#1E3A5F" HorizontalAlignment="Center" />
<TextBlock Text="Vast blue waters stretch beyond what the eye can see."
FontSize="13" Foreground="#1E3A5F" Opacity="0.8"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" />
</StackPanel>
</ContentPage>
<ContentPage Header="Forest"
Background="#FFBBF7D0"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8">
<Border Width="64" Height="64" CornerRadius="32"
Background="#22C55E" />
<TextBlock Text="Forest" FontSize="28" FontWeight="Bold"
Foreground="#14532D" HorizontalAlignment="Center" />
<TextBlock Text="Ancient trees whisper in the quiet woodland breeze."
FontSize="13" Foreground="#14532D" Opacity="0.8"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" />
</StackPanel>
</ContentPage>
<ContentPage Header="Night"
Background="#1E1B4B"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8">
<Border Width="64" Height="64" CornerRadius="32"
Background="#6366F1" />
<TextBlock Text="Night" FontSize="28" FontWeight="Bold"
Foreground="#C7D2FE" HorizontalAlignment="Center" />
<TextBlock Text="Stars emerge as the world quiets into peaceful darkness."
FontSize="13" Foreground="#C7D2FE" Opacity="0.8"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" />
</StackPanel>
</ContentPage>
</CarouselPage>
<!-- Page indicator dots -->
<Border VerticalAlignment="Bottom" HorizontalAlignment="Center"
Margin="0,0,0,12" CornerRadius="8" Background="#44000000"
Padding="10,4">
<StackPanel Orientation="Horizontal" Spacing="6">
<Ellipse x:Name="Dot0" Width="8" Height="8" Fill="White" />
<Ellipse x:Name="Dot1" Width="8" Height="8" Fill="White" Opacity="0.4" />
<Ellipse x:Name="Dot2" Width="8" Height="8" Fill="White" Opacity="0.4" />
<Ellipse x:Name="Dot3" Width="8" Height="8" Fill="White" Opacity="0.4" />
</StackPanel>
</Border>
</Panel>
</Border>
</DockPanel>
</UserControl>

79
samples/ControlCatalog/Pages/CarouselPage/CarouselPageCustomizationPage.xaml.cs

@ -0,0 +1,79 @@
using System;
using System.Collections;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselPageCustomizationPage : UserControl
{
public CarouselPageCustomizationPage()
{
InitializeComponent();
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
private void OnLoaded(object? sender, RoutedEventArgs e)
{
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromMilliseconds(300), PageSlide.SlideAxis.Horizontal);
DemoCarousel.SelectionChanged += OnSelectionChanged;
UpdateDots(DemoCarousel.SelectedIndex);
UpdateStatus();
}
private void OnUnloaded(object? sender, RoutedEventArgs e)
{
DemoCarousel.SelectionChanged -= OnSelectionChanged;
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
{
UpdateDots(DemoCarousel.SelectedIndex);
UpdateStatus();
}
private void OnOrientationChanged(object? sender, SelectionChangedEventArgs e)
{
if (DemoCarousel == null)
return;
var axis = OrientationCombo.SelectedIndex == 1
? PageSlide.SlideAxis.Vertical
: PageSlide.SlideAxis.Horizontal;
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromMilliseconds(300), axis);
UpdateStatus();
}
private void OnPrevious(object? sender, RoutedEventArgs e)
{
if (DemoCarousel.SelectedIndex > 0)
DemoCarousel.SelectedIndex--;
}
private void OnNext(object? sender, RoutedEventArgs e)
{
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
if (DemoCarousel.SelectedIndex < pageCount - 1)
DemoCarousel.SelectedIndex++;
}
private void UpdateDots(int selectedIndex)
{
Dot0.Opacity = selectedIndex == 0 ? 1.0 : 0.4;
Dot1.Opacity = selectedIndex == 1 ? 1.0 : 0.4;
Dot2.Opacity = selectedIndex == 2 ? 1.0 : 0.4;
Dot3.Opacity = selectedIndex == 3 ? 1.0 : 0.4;
}
private void UpdateStatus()
{
if (StatusText == null) return;
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
var axis = OrientationCombo?.SelectedIndex == 1 ? "Vertical" : "Horizontal";
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount} | {axis}";
}
}
}

44
samples/ControlCatalog/Pages/CarouselPage/CarouselPageDataTemplatePage.xaml

@ -0,0 +1,44 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPageDataTemplatePage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="240">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Data Templates" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="Bind a CarouselPage to a view-model collection, render each item with PageTemplate, and switch templates at runtime." />
<Separator />
<Button Content="Add Page" Click="OnAddPage" HorizontalAlignment="Stretch" />
<Button Content="Remove Last" Click="OnRemovePage" HorizontalAlignment="Stretch" />
<Button Content="Switch Template" Click="OnSwitchTemplate" HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="6">
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" />
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" />
</StackPanel>
<Separator />
<TextBlock x:Name="StatusText" Text="4 pages" Opacity="0.7" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Panel x:Name="CarouselHost" />
</Border>
</DockPanel>
</UserControl>

209
samples/ControlCatalog/Pages/CarouselPage/CarouselPageDataTemplatePage.xaml.cs

@ -0,0 +1,209 @@
using System.Collections.ObjectModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using AvaCarouselPage = Avalonia.Controls.CarouselPage;
namespace ControlCatalog.Pages
{
public partial class CarouselPageDataTemplatePage : UserControl
{
private sealed class CityViewModel
{
public string Name { get; }
public string Color { get; }
public string Description { get; }
public CityViewModel(string name, string color, string description)
{
Name = name;
Color = color;
Description = description;
}
}
private static readonly CityViewModel[] InitialData =
{
new("Tokyo", "#1565C0",
"The neon-lit capital of Japan, where ancient temples meet futuristic skylines."),
new("Amsterdam", "#2E7D32", "A city of canals, bicycles, and world-class museums."),
new("New York", "#6A1B9A", "The city that never sleeps — a cultural and financial powerhouse."),
new("Sydney", "#B71C1C", "Iconic harbour, golden beaches and the world-famous Opera House."),
};
private static readonly CityViewModel[] AddData =
{
new("Paris", "#E65100", "The city of light, love, and the Eiffel Tower."),
new("Barcelona", "#00695C", "Art, architecture, and vibrant street life on the Mediterranean coast."),
new("Kyoto", "#880E4F", "Japan's ancient capital, a living museum of traditional culture."),
};
private readonly ObservableCollection<CityViewModel> _items = new();
private int _addCounter;
private bool _useCardTemplate = true;
private AvaCarouselPage? _carouselPage;
public CarouselPageDataTemplatePage()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_carouselPage != null)
return;
foreach (var vm in InitialData)
_items.Add(vm);
_addCounter = InitialData.Length;
_useCardTemplate = true;
_carouselPage = new AvaCarouselPage { ItemsSource = _items, PageTemplate = CreatePageTemplate() };
_carouselPage.SelectionChanged += OnSelectionChanged;
CarouselHost.Children.Add(_carouselPage);
UpdateStatus();
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) => UpdateStatus();
private void OnAddPage(object? sender, RoutedEventArgs e)
{
var idx = _addCounter % AddData.Length;
var vm = AddData[idx];
var suffix = _addCounter >= AddData.Length ? $" {_addCounter / AddData.Length + 1}" : "";
_items.Add(new CityViewModel(vm.Name + suffix, vm.Color, vm.Description));
_addCounter++;
UpdateStatus();
}
private void OnRemovePage(object? sender, RoutedEventArgs e)
{
if (_items.Count > 0)
{
_items.RemoveAt(_items.Count - 1);
UpdateStatus();
}
}
private void OnSwitchTemplate(object? sender, RoutedEventArgs e)
{
if (_carouselPage == null)
return;
_useCardTemplate = !_useCardTemplate;
_carouselPage.PageTemplate = CreatePageTemplate();
}
private void OnPrevious(object? sender, RoutedEventArgs e)
{
if (_carouselPage == null)
return;
if (_carouselPage.SelectedIndex > 0)
_carouselPage.SelectedIndex--;
}
private void OnNext(object? sender, RoutedEventArgs e)
{
if (_carouselPage == null)
return;
if (_carouselPage.SelectedIndex < _items.Count - 1)
_carouselPage.SelectedIndex++;
}
private void UpdateStatus()
{
var count = _items.Count;
var index = _carouselPage?.SelectedIndex ?? -1;
StatusText.Text = count == 0 ? "No pages" : $"Page {index + 1} of {count} (index {index})";
}
private IDataTemplate CreatePageTemplate()
{
return new FuncDataTemplate<CityViewModel>((vm, _) => CreatePage(vm, _useCardTemplate));
}
private static ContentPage CreatePage(CityViewModel? vm, bool useCardTemplate)
{
if (vm is null)
return new ContentPage();
return new ContentPage
{
Header = vm.Name, Content = useCardTemplate ? CreateCardContent(vm) : CreateFeatureContent(vm)
};
}
private static Control CreateCardContent(CityViewModel vm)
{
return new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Spacing = 8,
Children =
{
new TextBlock
{
Text = vm.Name,
FontSize = 28,
FontWeight = FontWeight.Bold,
Foreground = new SolidColorBrush(Color.Parse(vm.Color)),
HorizontalAlignment = HorizontalAlignment.Center
},
new TextBlock
{
Text = vm.Description,
FontSize = 13,
Opacity = 0.7,
TextWrapping = TextWrapping.Wrap,
TextAlignment = TextAlignment.Center,
MaxWidth = 280
}
}
};
}
private static Control CreateFeatureContent(CityViewModel vm)
{
var accent = Color.Parse(vm.Color);
return new Border
{
Background = new SolidColorBrush(accent),
Padding = new Thickness(32),
Child = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Spacing = 12,
Children =
{
new TextBlock
{
Text = vm.Name.ToUpperInvariant(),
FontSize = 34,
FontWeight = FontWeight.Bold,
Foreground = Brushes.White,
HorizontalAlignment = HorizontalAlignment.Center
},
new TextBlock
{
Text = vm.Description,
FontSize = 15,
Foreground = Brushes.White,
Opacity = 0.88,
TextWrapping = TextWrapping.Wrap,
TextAlignment = TextAlignment.Center,
MaxWidth = 320
}
}
}
};
}
}
}

37
samples/ControlCatalog/Pages/CarouselPage/CarouselPageEventsPage.xaml

@ -0,0 +1,37 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPageEventsPage">
<DockPanel>
<StackPanel DockPanel.Dock="Right" Width="240" Margin="0,0,0,0">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Event Log" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="6">
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" />
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" />
</StackPanel>
<Separator />
<Button Content="Clear Log" Click="OnClearLog" HorizontalAlignment="Stretch" />
</StackPanel>
<Border Height="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<ScrollViewer x:Name="LogScrollViewer" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="EventLog" Margin="12" FontSize="11"
FontFamily="Courier New, Consolas, monospace"
TextWrapping="Wrap" Opacity="0.85" />
</ScrollViewer>
</StackPanel>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="6" ClipToBounds="True">
<CarouselPage x:Name="DemoCarousel" />
</Border>
</DockPanel>
</UserControl>

92
samples/ControlCatalog/Pages/CarouselPage/CarouselPageEventsPage.xaml.cs

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselPageEventsPage : UserControl
{
private readonly List<string> _log = new();
public CarouselPageEventsPage()
{
InitializeComponent();
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
private void OnLoaded(object? sender, RoutedEventArgs e)
{
var pageNames = new[] { "Home", "Explore", "Library", "Profile" };
for (int i = 0; i < pageNames.Length; i++)
{
var name = pageNames[i];
var page = new ContentPage
{
Header = name,
Background = NavigationDemoHelper.GetPageBrush(i),
Content = new TextBlock
{
Text = $"{name}",
FontSize = 28,
FontWeight = Avalonia.Media.FontWeight.Bold,
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center
},
HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Stretch,
VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Stretch
};
page.NavigatedTo += (_, args) =>
AppendLog($"NavigatedTo: {name} (from {(args.PreviousPage as ContentPage)?.Header ?? ""})");
page.NavigatedFrom += (_, args) =>
AppendLog($"NavigatedFrom: {name} (to {(args.DestinationPage as ContentPage)?.Header ?? ""})");
((Avalonia.Collections.AvaloniaList<Page>)DemoCarousel.Pages!).Add(page);
}
DemoCarousel.SelectionChanged += OnSelectionChanged;
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
{
AppendLog($"SelectionChanged: {(e.PreviousPage as ContentPage)?.Header ?? ""} → {(e.CurrentPage as ContentPage)?.Header ?? ""}");
}
private void OnPrevious(object? sender, RoutedEventArgs e)
{
if (DemoCarousel.SelectedIndex > 0)
DemoCarousel.SelectedIndex--;
}
private void OnNext(object? sender, RoutedEventArgs e)
{
var pageCount = ((AvaloniaList<Page>)DemoCarousel.Pages!).Count;
if (DemoCarousel.SelectedIndex < pageCount - 1)
DemoCarousel.SelectedIndex++;
}
private void OnUnloaded(object? sender, RoutedEventArgs e)
{
DemoCarousel.SelectionChanged -= OnSelectionChanged;
}
private void OnClearLog(object? sender, RoutedEventArgs e)
{
_log.Clear();
EventLog.Text = string.Empty;
}
private void AppendLog(string message)
{
var timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
_log.Add($"[{timestamp}] {message}");
if (_log.Count > 50)
_log.RemoveAt(0);
EventLog.Text = string.Join(Environment.NewLine, _log);
LogScrollViewer.ScrollToEnd();
}
}
}

61
samples/ControlCatalog/Pages/CarouselPage/CarouselPageFirstLookPage.xaml

@ -0,0 +1,61 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPageFirstLookPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="6">
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" />
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" />
</StackPanel>
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" />
<TextBlock x:Name="StatusText" Text="Page 1 of 3" Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="6" ClipToBounds="True">
<CarouselPage x:Name="DemoCarousel"
SelectionChanged="OnSelectionChanged">
<ContentPage Header="Welcome">
<StackPanel Margin="24" Spacing="12"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Welcome" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="Swipe left or use the buttons to navigate."
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="280" />
</StackPanel>
</ContentPage>
<ContentPage Header="Explore">
<StackPanel Margin="24" Spacing="12"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Explore" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="CarouselPage supports scroll-based and transition-based navigation modes."
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="280" />
</StackPanel>
</ContentPage>
<ContentPage Header="Get Started">
<StackPanel Margin="24" Spacing="12"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Get Started" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="Use SelectedIndex to jump to any page, or assign a PageTransition for animated switching."
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="280" />
</StackPanel>
</ContentPage>
</CarouselPage>
</Border>
</DockPanel>
</UserControl>

35
samples/ControlCatalog/Pages/CarouselPage/CarouselPageFirstLookPage.xaml.cs

@ -0,0 +1,35 @@
using System.Collections;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselPageFirstLookPage : UserControl
{
public CarouselPageFirstLookPage()
{
InitializeComponent();
}
private void OnPrevious(object? sender, RoutedEventArgs e)
{
if (DemoCarousel.SelectedIndex > 0)
DemoCarousel.SelectedIndex--;
}
private void OnNext(object? sender, RoutedEventArgs e)
{
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
if (DemoCarousel.SelectedIndex < pageCount - 1)
DemoCarousel.SelectedIndex++;
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
{
if (StatusText == null)
return;
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount}";
}
}
}

64
samples/ControlCatalog/Pages/CarouselPage/CarouselPageGesturePage.xaml

@ -0,0 +1,64 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPageGesturePage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Gesture Navigation" FontWeight="SemiBold" FontSize="13" />
<CheckBox x:Name="GestureCheck" Content="IsGestureEnabled"
IsChecked="True" IsCheckedChanged="OnGestureChanged" />
<Separator />
<TextBlock Text="Keyboard Navigation" FontWeight="SemiBold" FontSize="13" />
<CheckBox x:Name="KeyboardCheck" Content="IsKeyboardNavigationEnabled"
IsChecked="True" IsCheckedChanged="OnKeyboardChanged" />
<Separator />
<TextBlock Text="Hints" FontWeight="SemiBold" FontSize="13" />
<TextBlock Text="• Swipe left/right to navigate (touch)" FontSize="11" Opacity="0.7" TextWrapping="Wrap" />
<TextBlock Text="• Mouse drag (left button) to navigate" FontSize="11" Opacity="0.7" TextWrapping="Wrap" />
<TextBlock Text="• Arrow keys / Home / End when focused" FontSize="11" Opacity="0.7" TextWrapping="Wrap" />
<TextBlock Text="• Mouse wheel scrolls pages" FontSize="11" Opacity="0.7" TextWrapping="Wrap" />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" />
<TextBlock x:Name="StatusText" Text="—" Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="6" ClipToBounds="True">
<CarouselPage x:Name="DemoCarousel"
SelectionChanged="OnSelectionChanged">
<CarouselPage.PageTransition>
<PageSlide Duration="0:0:0.3" Orientation="Horizontal" />
</CarouselPage.PageTransition>
<ContentPage Header="Page 1" Background="#BBDEFB">
<TextBlock Text="Page 1 — Swipe or drag to navigate"
HorizontalAlignment="Center" VerticalAlignment="Center"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="200" FontSize="16" />
</ContentPage>
<ContentPage Header="Page 2" Background="#C8E6C9">
<TextBlock Text="Page 2 — Arrow keys also work when focused"
HorizontalAlignment="Center" VerticalAlignment="Center"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="200" FontSize="16" />
</ContentPage>
<ContentPage Header="Page 3" Background="#FFE0B2">
<TextBlock Text="Page 3 — Disable gestures using the panel"
HorizontalAlignment="Center" VerticalAlignment="Center"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="200" FontSize="16" />
</ContentPage>
</CarouselPage>
</Border>
</DockPanel>
</UserControl>

44
samples/ControlCatalog/Pages/CarouselPage/CarouselPageGesturePage.xaml.cs

@ -0,0 +1,44 @@
using System.Collections;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselPageGesturePage : UserControl
{
public CarouselPageGesturePage()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object? sender, RoutedEventArgs e) => UpdateStatus();
private void OnGestureChanged(object? sender, RoutedEventArgs e)
{
if (DemoCarousel == null)
return;
DemoCarousel.IsGestureEnabled = GestureCheck.IsChecked == true;
}
private void OnKeyboardChanged(object? sender, RoutedEventArgs e)
{
if (DemoCarousel == null)
return;
DemoCarousel.IsKeyboardNavigationEnabled = KeyboardCheck.IsChecked == true;
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
{
UpdateStatus();
}
private void UpdateStatus()
{
if (StatusText == null)
return;
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount}";
}
}
}

45
samples/ControlCatalog/Pages/CarouselPage/CarouselPagePerformancePage.xaml

@ -0,0 +1,45 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPagePerformancePage">
<Grid ColumnDefinitions="*,240">
<Border Grid.Column="0" Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<CarouselPage x:Name="DemoCarousel" />
</Border>
<Border Grid.Column="1"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1,0,0,0" Padding="12">
<ScrollViewer>
<StackPanel Spacing="8">
<TextBlock Text="Actions" FontWeight="SemiBold" />
<Button Content="Add 5 Pages" HorizontalAlignment="Stretch" Click="OnAdd5" />
<Button Content="Add 20 Pages" HorizontalAlignment="Stretch" Click="OnAdd20" />
<Button Content="Remove Last 5" HorizontalAlignment="Stretch" Click="OnRemove5" />
<Button Content="Clear All" HorizontalAlignment="Stretch" Click="OnClearAll" />
<Separator />
<Button Content="Force GC" HorizontalAlignment="Stretch" Click="OnForceGC" />
<Button Content="Refresh Stats" HorizontalAlignment="Stretch" Click="OnRefresh" />
<Separator />
<TextBlock Text="Statistics" FontWeight="SemiBold" />
<TextBlock x:Name="PageCountText" Text="Page count: 0" FontSize="12" />
<TextBlock x:Name="LiveCountText" Text="Live instances: 0" FontSize="12" />
<TextBlock x:Name="HeapText" Text="Heap: 0 KB" FontSize="12" />
<TextBlock x:Name="AllocText" Text="Total allocated: 0 KB" FontSize="12" />
<TextBlock x:Name="LastOpTimeText" Text="Last Op: " FontSize="12" />
</StackPanel>
</ScrollViewer>
</Border>
</Grid>
</UserControl>

103
samples/ControlCatalog/Pages/CarouselPage/CarouselPagePerformancePage.xaml.cs

@ -0,0 +1,103 @@
using System;
using System.Collections;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Layout;
namespace ControlCatalog.Pages
{
public partial class CarouselPagePerformancePage : UserControl
{
private readonly NavigationPerformanceMonitorHelper _perf = new();
private int _counter;
public CarouselPagePerformancePage()
{
InitializeComponent();
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
private void OnLoaded(object? sender, RoutedEventArgs e)
{
AddPages(5);
DemoCarousel.SelectionChanged += OnSelectionChanged;
}
private void OnUnloaded(object? sender, RoutedEventArgs e)
{
DemoCarousel.SelectionChanged -= OnSelectionChanged;
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) => RefreshStats();
private void AddPages(int count)
{
var pages = (IList)DemoCarousel.Pages!;
_perf.OpStopwatch.Restart();
for (int i = 0; i < count; i++)
{
var idx = ++_counter;
var page = new ContentPage
{
Header = $"P{idx}",
Content = new TextBlock
{
Text = $"Page {idx}",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
FontSize = 18,
Opacity = 0.7
},
Tag = new byte[51200],
};
_perf.TrackPage(page);
pages.Add(page);
}
_perf.StopMetrics(LastOpTimeText);
RefreshStats();
}
private void RemovePages(int count)
{
var pages = (IList)DemoCarousel.Pages!;
_perf.OpStopwatch.Restart();
for (int i = 0; i < count && pages.Count > 0; i++)
pages.RemoveAt(pages.Count - 1);
_perf.StopMetrics(LastOpTimeText);
RefreshStats();
}
private void OnAdd5(object? sender, RoutedEventArgs e) => AddPages(5);
private void OnAdd20(object? sender, RoutedEventArgs e) => AddPages(20);
private void OnRemove5(object? sender, RoutedEventArgs e) => RemovePages(5);
private void OnClearAll(object? sender, RoutedEventArgs e)
{
var pages = (IList)DemoCarousel.Pages!;
_perf.OpStopwatch.Restart();
while (pages.Count > 0)
pages.RemoveAt(pages.Count - 1);
_perf.StopMetrics(LastOpTimeText);
RefreshStats();
}
private void OnForceGC(object? sender, RoutedEventArgs e)
{
_perf.ForceGC(RefreshStats);
}
private void OnRefresh(object? sender, RoutedEventArgs e) => RefreshStats();
private void RefreshStats()
{
var pages = (IList)DemoCarousel.Pages!;
PageCountText.Text = $"Page count: {pages.Count}";
LiveCountText.Text = $"Live instances: {_perf.CountLiveInstances()} / {_perf.TotalCreated} tracked";
HeapText.Text = $"Heap: {GC.GetTotalMemory(false) / 1024:N0} KB";
AllocText.Text = $"Total allocated: {GC.GetTotalAllocatedBytes() / 1024:N0} KB";
}
}
}

90
samples/ControlCatalog/Pages/CarouselPage/CarouselPageSelectionPage.xaml

@ -0,0 +1,90 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPageSelectionPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Jump to Page" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="6">
<Button Content="Go to Page 1" Click="OnGoTo0" HorizontalAlignment="Stretch" />
<Button Content="Go to Page 2" Click="OnGoTo1" HorizontalAlignment="Stretch" />
<Button Content="Go to Page 3" Click="OnGoTo2" HorizontalAlignment="Stretch" />
<Button Content="Go to Page 4" Click="OnGoTo3" HorizontalAlignment="Stretch" />
</StackPanel>
<Separator />
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="6">
<Button Content="First" Click="OnFirst" HorizontalAlignment="Stretch" />
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" />
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" />
<Button Content="Last" Click="OnLast" HorizontalAlignment="Stretch" />
</StackPanel>
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" />
<TextBlock x:Name="StatusText" Text="—" Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="6" ClipToBounds="True">
<CarouselPage x:Name="DemoCarousel"
SelectionChanged="OnSelectionChanged">
<ContentPage Header="Onboarding" Background="#BBDEFB">
<StackPanel Margin="24" Spacing="8"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Step 1 of 4" FontSize="14" Opacity="0.6"
HorizontalAlignment="Center" />
<TextBlock Text="Onboarding" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="Set SelectedIndex to jump directly to any page."
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" />
</StackPanel>
</ContentPage>
<ContentPage Header="Features" Background="#C8E6C9">
<StackPanel Margin="24" Spacing="8"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Step 2 of 4" FontSize="14" Opacity="0.6"
HorizontalAlignment="Center" />
<TextBlock Text="Features" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="Supports scroll, transition, swipe gesture and keyboard navigation."
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" />
</StackPanel>
</ContentPage>
<ContentPage Header="Customize" Background="#FFE0B2">
<StackPanel Margin="24" Spacing="8"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Step 3 of 4" FontSize="14" Opacity="0.6"
HorizontalAlignment="Center" />
<TextBlock Text="Customize" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="Override the ItemsPanel, add any Avalonia Page as a child."
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" />
</StackPanel>
</ContentPage>
<ContentPage Header="Ready" Background="#E1BEE7">
<StackPanel Margin="24" Spacing="8"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Step 4 of 4" FontSize="14" Opacity="0.6"
HorizontalAlignment="Center" />
<TextBlock Text="Ready!" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="You are all set. Use SelectionChanged to react to navigation."
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" />
</StackPanel>
</ContentPage>
</CarouselPage>
</Border>
</DockPanel>
</UserControl>

56
samples/ControlCatalog/Pages/CarouselPage/CarouselPageSelectionPage.xaml.cs

@ -0,0 +1,56 @@
using System.Collections;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselPageSelectionPage : UserControl
{
public CarouselPageSelectionPage()
{
InitializeComponent();
Loaded += (_, _) => UpdateStatus();
}
private void OnGoTo0(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 0;
private void OnGoTo1(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 1;
private void OnGoTo2(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 2;
private void OnGoTo3(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 3;
private void OnFirst(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 0;
private void OnPrevious(object? sender, RoutedEventArgs e)
{
if (DemoCarousel.SelectedIndex > 0)
DemoCarousel.SelectedIndex--;
}
private void OnNext(object? sender, RoutedEventArgs e)
{
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
if (DemoCarousel.SelectedIndex < pageCount - 1)
DemoCarousel.SelectedIndex++;
}
private void OnLast(object? sender, RoutedEventArgs e)
{
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
if (pageCount > 0)
DemoCarousel.SelectedIndex = pageCount - 1;
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
{
UpdateStatus();
}
private void UpdateStatus()
{
if (StatusText == null)
return;
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
var header = (DemoCarousel.SelectedPage as ContentPage)?.Header?.ToString() ?? "—";
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount}: {header}";
}
}
}

65
samples/ControlCatalog/Pages/CarouselPage/CarouselPageTransitionsPage.xaml

@ -0,0 +1,65 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPageTransitionsPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Page Transition" FontWeight="SemiBold" FontSize="13" />
<ComboBox x:Name="TransitionCombo" SelectedIndex="0"
SelectionChanged="OnTransitionChanged"
HorizontalAlignment="Stretch">
<ComboBoxItem Content="None" />
<ComboBoxItem Content="CrossFade" />
<ComboBoxItem Content="Slide Horizontal" />
<ComboBoxItem Content="Slide Vertical" />
<ComboBoxItem Content="Card Stack" />
<ComboBoxItem Content="Wave Reveal" />
</ComboBox>
<Separator />
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" />
<StackPanel Spacing="6">
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" />
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" />
</StackPanel>
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" />
<TextBlock x:Name="StatusText" Text="Page 1 of 4 | Transition: None"
Opacity="0.7" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="6" ClipToBounds="True">
<CarouselPage x:Name="DemoCarousel"
SelectionChanged="OnSelectionChanged">
<ContentPage Header="Page 1" Background="#BBDEFB">
<TextBlock Text="Page 1" FontSize="32" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</ContentPage>
<ContentPage Header="Page 2" Background="#C8E6C9">
<TextBlock Text="Page 2" FontSize="32" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</ContentPage>
<ContentPage Header="Page 3" Background="#FFE0B2">
<TextBlock Text="Page 3" FontSize="32" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</ContentPage>
<ContentPage Header="Page 4" Background="#E1BEE7">
<TextBlock Text="Page 4" FontSize="32" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</ContentPage>
</CarouselPage>
</Border>
</DockPanel>
</UserControl>

69
samples/ControlCatalog/Pages/CarouselPage/CarouselPageTransitionsPage.xaml.cs

@ -0,0 +1,69 @@
using System;
using System.Collections;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Interactivity;
using ControlCatalog.Pages.Transitions;
namespace ControlCatalog.Pages
{
public partial class CarouselPageTransitionsPage : UserControl
{
public CarouselPageTransitionsPage()
{
InitializeComponent();
}
private void OnTransitionChanged(object? sender, SelectionChangedEventArgs e)
{
if (DemoCarousel == null)
return;
DemoCarousel.PageTransition = TransitionCombo?.SelectedIndex switch
{
0 => null,
1 => new CrossFade(TimeSpan.FromMilliseconds(300)),
2 => new PageSlide(TimeSpan.FromMilliseconds(300), PageSlide.SlideAxis.Horizontal),
3 => new PageSlide(TimeSpan.FromMilliseconds(300), PageSlide.SlideAxis.Vertical),
4 => new CardStackPageTransition(TimeSpan.FromMilliseconds(400)),
5 => new WaveRevealPageTransition(TimeSpan.FromMilliseconds(600)),
_ => null
};
UpdateStatus();
}
private void OnPrevious(object? sender, RoutedEventArgs e)
{
if (DemoCarousel.SelectedIndex > 0)
DemoCarousel.SelectedIndex--;
}
private void OnNext(object? sender, RoutedEventArgs e)
{
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
if (DemoCarousel.SelectedIndex < pageCount - 1)
DemoCarousel.SelectedIndex++;
}
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
{
UpdateStatus();
}
private void UpdateStatus()
{
if (StatusText == null)
return;
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
var modeName = DemoCarousel.PageTransition switch
{
null => "None",
CardStackPageTransition => "Card Stack",
WaveRevealPageTransition => "Wave Reveal",
{ } t => t.GetType().Name
};
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount} | Transition: {modeName}";
}
}
}

97
samples/ControlCatalog/Pages/CarouselPage/CarouselTransitionsPage.xaml

@ -0,0 +1,97 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselTransitionsPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
<Button x:Name="PreviousButton"
Content="Previous"
HorizontalAlignment="Stretch" />
<Button x:Name="NextButton"
Content="Next"
HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Transition" FontWeight="SemiBold" FontSize="13" />
<ComboBox x:Name="TransitionCombo"
HorizontalAlignment="Stretch"
SelectedIndex="1">
<ComboBoxItem>None</ComboBoxItem>
<ComboBoxItem>Page Slide</ComboBoxItem>
<ComboBoxItem>Cross Fade</ComboBoxItem>
<ComboBoxItem>Rotate 3D</ComboBoxItem>
<ComboBoxItem>Card Stack</ComboBoxItem>
<ComboBoxItem>Wave Reveal</ComboBoxItem>
<ComboBoxItem>Composite (Slide + Fade)</ComboBoxItem>
</ComboBox>
<TextBlock Text="Orientation" FontWeight="SemiBold" FontSize="13" />
<ComboBox x:Name="OrientationCombo"
HorizontalAlignment="Stretch"
SelectedIndex="0">
<ComboBoxItem>Horizontal</ComboBoxItem>
<ComboBoxItem>Vertical</ComboBoxItem>
</ComboBox>
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="StatusText"
Text="Transition: Page Slide"
Opacity="0.7"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Carousel x:Name="DemoCarousel" Height="300">
<Carousel.PageTransition>
<PageSlide Duration="0.25" Orientation="Horizontal" />
</Carousel.PageTransition>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 1: Delicate Arch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 2: Hirsch" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True">
<Grid>
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" />
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12">
<TextBlock Text="Item 3: Maple Leaf" Foreground="White"
HorizontalAlignment="Center" FontWeight="SemiBold" />
</Border>
</Grid>
</Border>
</Carousel>
</Border>
</DockPanel>
</UserControl>

66
samples/ControlCatalog/Pages/CarouselPage/CarouselTransitionsPage.xaml.cs

@ -0,0 +1,66 @@
using System;
using Avalonia.Animation;
using Avalonia.Controls;
using ControlCatalog.Pages.Transitions;
namespace ControlCatalog.Pages
{
public partial class CarouselTransitionsPage : UserControl
{
public CarouselTransitionsPage()
{
InitializeComponent();
PreviousButton.Click += (_, _) => DemoCarousel.Previous();
NextButton.Click += (_, _) => DemoCarousel.Next();
TransitionCombo.SelectionChanged += (_, _) => ApplyTransition();
OrientationCombo.SelectionChanged += (_, _) => ApplyTransition();
}
private void ApplyTransition()
{
var axis = OrientationCombo.SelectedIndex == 0 ?
PageSlide.SlideAxis.Horizontal :
PageSlide.SlideAxis.Vertical;
var label = axis == PageSlide.SlideAxis.Horizontal ? "Horizontal" : "Vertical";
switch (TransitionCombo.SelectedIndex)
{
case 0:
DemoCarousel.PageTransition = null;
StatusText.Text = "Transition: None";
break;
case 1:
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromSeconds(0.25), axis);
StatusText.Text = $"Transition: Page Slide ({label})";
break;
case 2:
DemoCarousel.PageTransition = new CrossFade(TimeSpan.FromSeconds(0.25));
StatusText.Text = "Transition: Cross Fade";
break;
case 3:
DemoCarousel.PageTransition = new Rotate3DTransition(TimeSpan.FromSeconds(0.5), axis);
StatusText.Text = $"Transition: Rotate 3D ({label})";
break;
case 4:
DemoCarousel.PageTransition = new CardStackPageTransition(TimeSpan.FromSeconds(0.5), axis);
StatusText.Text = $"Transition: Card Stack ({label})";
break;
case 5:
DemoCarousel.PageTransition = new WaveRevealPageTransition(TimeSpan.FromSeconds(0.8), axis);
StatusText.Text = $"Transition: Wave Reveal ({label})";
break;
case 6:
DemoCarousel.PageTransition = new CompositePageTransition
{
PageTransitions =
{
new PageSlide(TimeSpan.FromSeconds(0.25), axis),
new CrossFade(TimeSpan.FromSeconds(0.25)),
}
};
StatusText.Text = "Transition: Composite (Slide + Fade)";
break;
}
}
}
}

132
samples/ControlCatalog/Pages/CarouselPage/CarouselVerticalPage.xaml

@ -0,0 +1,132 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselVerticalPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="260">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
<Button x:Name="PreviousButton" Content="Up" HorizontalAlignment="Stretch" />
<Button x:Name="NextButton" Content="Down" HorizontalAlignment="Stretch" />
<Separator />
<TextBlock Text="Transition" FontWeight="SemiBold" FontSize="13" />
<ComboBox x:Name="TransitionCombo"
HorizontalAlignment="Stretch"
SelectedIndex="0">
<ComboBoxItem>PageSlide</ComboBoxItem>
<ComboBoxItem>CrossFade</ComboBoxItem>
<ComboBoxItem>None</ComboBoxItem>
</ComboBox>
<Separator />
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="13" />
<CheckBox x:Name="WrapCheck"
Content="Wrap Selection"
IsChecked="False"
IsCheckedChanged="OnWrapSelectionChanged" />
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
<TextBlock x:Name="StatusText"
Text="Item: 1 / 4"
Opacity="0.7"
TextWrapping="Wrap" />
<TextBlock Text="Use Up/Down arrow keys or buttons to navigate."
FontSize="11"
Opacity="0.5"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<Carousel x:Name="DemoCarousel"
Focusable="True"
IsSwipeEnabled="True">
<Carousel.PageTransition>
<PageSlide Duration="0.3" Orientation="Vertical" />
</Carousel.PageTransition>
<Border Margin="14,12" CornerRadius="12">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Color="#1A1A2E" Offset="0" />
<GradientStop Color="#3525CD" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10">
<TextBlock Text="01" FontSize="64" FontWeight="Bold"
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Neon Pulse" FontSize="18" FontWeight="SemiBold"
Foreground="#C3C0FF" HorizontalAlignment="Center" />
<TextBlock Text="Slide down to explore" FontSize="12"
Foreground="#80FFFFFF" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Margin="14,12" CornerRadius="12">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Color="#0C1A1F" Offset="0" />
<GradientStop Color="#0891B2" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10">
<TextBlock Text="02" FontSize="64" FontWeight="Bold"
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Ephemeral Blue" FontSize="18" FontWeight="SemiBold"
Foreground="#BAF0FA" HorizontalAlignment="Center" />
<TextBlock Text="Vertical PageSlide in action" FontSize="12"
Foreground="#80FFFFFF" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Margin="14,12" CornerRadius="12">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Color="#0A1F18" Offset="0" />
<GradientStop Color="#059669" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10">
<TextBlock Text="03" FontSize="64" FontWeight="Bold"
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Forest Forms" FontSize="18" FontWeight="SemiBold"
Foreground="#A7F3D0" HorizontalAlignment="Center" />
<TextBlock Text="Swipe up or down on touch screens" FontSize="12"
Foreground="#80FFFFFF" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<Border Margin="14,12" CornerRadius="12">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Color="#1F1208" Offset="0" />
<GradientStop Color="#D97706" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10">
<TextBlock Text="04" FontSize="64" FontWeight="Bold"
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" />
<TextBlock Text="Golden Hour" FontSize="18" FontWeight="SemiBold"
Foreground="#FDE68A" HorizontalAlignment="Center" />
<TextBlock Text="Switch transitions in the panel" FontSize="12"
Foreground="#80FFFFFF" HorizontalAlignment="Center" />
</StackPanel>
</Border>
</Carousel>
</Border>
</DockPanel>
</UserControl>

39
samples/ControlCatalog/Pages/CarouselPage/CarouselVerticalPage.xaml.cs

@ -0,0 +1,39 @@
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class CarouselVerticalPage : UserControl
{
public CarouselVerticalPage()
{
InitializeComponent();
PreviousButton.Click += (_, _) => DemoCarousel.Previous();
NextButton.Click += (_, _) => DemoCarousel.Next();
DemoCarousel.SelectionChanged += OnSelectionChanged;
TransitionCombo.SelectionChanged += OnTransitionChanged;
DemoCarousel.Loaded += (_, _) => DemoCarousel.Focus();
}
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {DemoCarousel.ItemCount}";
}
private void OnTransitionChanged(object? sender, SelectionChangedEventArgs e)
{
DemoCarousel.PageTransition = TransitionCombo.SelectedIndex switch
{
1 => new CrossFade(System.TimeSpan.FromSeconds(0.3)),
2 => null,
_ => new PageSlide(System.TimeSpan.FromSeconds(0.3), PageSlide.SlideAxis.Vertical),
};
}
private void OnWrapSelectionChanged(object? sender, RoutedEventArgs e)
{
DemoCarousel.WrapSelection = WrapCheck.IsChecked == true;
}
}
}

298
samples/ControlCatalog/Pages/CarouselPage/SanctuaryMainPage.xaml

@ -0,0 +1,298 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.SanctuaryMainPage">
<UserControl.Styles>
<Style Selector="Button.primary /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#f47b25" />
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" />
</Style>
<Style Selector="Button.primary:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#e0701f" />
</Style>
<Style Selector="Button.primary:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#c9611a" />
</Style>
<Style Selector="Button.glass /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#18FFFFFF" />
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" />
</Style>
<Style Selector="Button.glass:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#2AFFFFFF" />
</Style>
<Style Selector="Button.glass:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#10FFFFFF" />
</Style>
</UserControl.Styles>
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Sanctuary" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Main landing page with a full-screen hero card, Featured Escapes section, and a bottom TabbedPage navigation. Navigated to from the onboarding carousel." />
<Separator />
<TextBlock Text="Design" FontSize="13" FontWeight="SemiBold" />
<TextBlock FontSize="12" Text="Theme: Dark (#221710)" />
<TextBlock FontSize="12" Text="Primary: #f47b25 (warm orange)" />
<Separator />
<TextBlock Text="Tabs" FontSize="13" FontWeight="SemiBold" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Home — hero + Featured Escapes cards" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Explore — destination discovery" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Saved — bookmarked destinations" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Profile — account and settings" />
<Separator />
<TextBlock Text="Navigation" FontSize="13" FontWeight="SemiBold" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Reached via 'Get Started' on the Urban Adventures carousel page. Back stack is cleared on arrival." />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Grid RowDefinitions="Auto,*" Background="#221710">
<!-- Top Nav Bar -->
<Border Grid.Row="0" Background="#DD221710" Padding="16,10,16,10">
<Grid ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="8" VerticalAlignment="Center">
<Panel Width="30" Height="30">
<Ellipse Fill="#f47b25" />
<TextBlock Text="▲" Foreground="White" FontSize="13" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Panel>
<TextBlock Text="Sanctuary" FontSize="18" FontWeight="Bold"
Foreground="White" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="6" VerticalAlignment="Center">
<Border Width="48" Height="48" CornerRadius="24" Background="#18FFFFFF">
<TextBlock Text="⌕" FontSize="20" Foreground="#80FFFFFF"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<Border Width="48" Height="48" CornerRadius="24" Background="#33f47b25">
<TextBlock Text="◉" FontSize="19" Foreground="#f47b25"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</StackPanel>
</Grid>
</Border>
<!-- Tabbed content -->
<TabbedPage Grid.Row="1"
TabPlacement="Bottom"
SelectedIndex="0">
<TabbedPage.Resources>
<SolidColorBrush x:Key="TabbedPageTabStripBackground">#221710</SolidColorBrush>
<SolidColorBrush x:Key="TabbedPageTabItemHeaderForegroundSelected">#f47b25</SolidColorBrush>
<SolidColorBrush x:Key="TabbedPageTabItemHeaderForegroundUnselected">#50FFFFFF</SolidColorBrush>
<Thickness x:Key="TabbedPageTabItemHeaderPadding">8,10,8,4</Thickness>
</TabbedPage.Resources>
<!-- Home Tab -->
<ContentPage Header="Home"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z</StreamGeometry>
</ContentPage.Icon>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<StackPanel>
<!-- Hero Card -->
<Border Margin="12,12,12,8" CornerRadius="16" ClipToBounds="True" Height="380">
<Border.Background>
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_hero.jpg"
Stretch="UniformToFill" />
</Border.Background>
<Grid>
<Border ClipToBounds="True" Margin="-1">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="Transparent" />
<GradientStop Offset="0.45" Color="#55221710" />
<GradientStop Offset="1" Color="#EE221710" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom"
Margin="28,0,28,32" Spacing="14">
<StackPanel HorizontalAlignment="Center" Spacing="2">
<TextBlock Text="Find Your" FontSize="40" FontWeight="ExtraBold"
Foreground="White" TextAlignment="Center" />
<TextBlock Text="Sanctuary" FontSize="40" FontWeight="ExtraBold"
Foreground="#f47b25" TextAlignment="Center" />
</StackPanel>
<TextBlock Text="Embark on a curated journey through the world's most serene and breathtaking natural wonders. Escape the noise and rediscover peace."
FontSize="13" Foreground="#CAffffff"
TextAlignment="Center" TextWrapping="Wrap" MaxWidth="280" />
<StackPanel Spacing="10" HorizontalAlignment="Center">
<Button Classes="primary"
Foreground="#221710" FontWeight="Bold" FontSize="14"
CornerRadius="24" Padding="28,14"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center">
<TextBlock Text="Explore the Collection" Foreground="#221710" FontWeight="Bold" />
</Button>
<Button Classes="glass"
Foreground="White" FontWeight="Bold" FontSize="14"
CornerRadius="24" Padding="28,14"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center">
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Center">
<TextBlock Text="⊕" Foreground="White" VerticalAlignment="Center" />
<TextBlock Text="View Map" Foreground="White" FontWeight="Bold" VerticalAlignment="Center" />
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</Grid>
</Border>
<!-- Featured Escapes Header -->
<Grid Margin="16,8,16,12" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" Spacing="3">
<TextBlock Text="Featured Escapes" FontSize="20" FontWeight="Bold" Foreground="White" />
<TextBlock Text="Hand-picked destinations for your next retreat"
FontSize="12" Foreground="#80FFFFFF" />
</StackPanel>
<TextBlock Grid.Column="1" Text="See All" FontSize="12" FontWeight="Bold"
Foreground="#f47b25" VerticalAlignment="Bottom" />
</Grid>
<!-- Card 1: Deep Forest -->
<Border Margin="16,0,16,12" CornerRadius="16" ClipToBounds="True" Height="240">
<Border.Background>
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_deep_forest.jpg"
Stretch="UniformToFill" />
</Border.Background>
<Grid>
<Border ClipToBounds="True" Margin="-1">
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Offset="0" Color="#66000000" />
<GradientStop Offset="0.5" Color="Transparent" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel VerticalAlignment="Bottom" Margin="16,0,16,16" Spacing="4">
<Border CornerRadius="12" Background="#33f47b25" Padding="8,4" HorizontalAlignment="Left">
<TextBlock Text="FOREST" FontSize="10" FontWeight="Bold" Foreground="#f47b25" />
</Border>
<TextBlock Text="Deep Forest" FontSize="22" FontWeight="Bold" Foreground="White" />
<TextBlock Text="Quiet trails in Oregon, USA" FontSize="12" Foreground="#CCffffff" />
</StackPanel>
</Grid>
</Border>
<!-- Card 2: Arctic Silence -->
<Border Margin="16,0,16,12" CornerRadius="16" ClipToBounds="True" Height="240">
<Border.Background>
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_arctic_silence.jpg"
Stretch="UniformToFill" />
</Border.Background>
<Grid>
<Border ClipToBounds="True" Margin="-1">
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Offset="0" Color="#66000000" />
<GradientStop Offset="0.5" Color="Transparent" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel VerticalAlignment="Bottom" Margin="16,0,16,16" Spacing="4">
<Border CornerRadius="12" Background="#33f47b25" Padding="8,4" HorizontalAlignment="Left">
<TextBlock Text="ALPINE" FontSize="10" FontWeight="Bold" Foreground="#f47b25" />
</Border>
<TextBlock Text="Arctic Silence" FontSize="22" FontWeight="Bold" Foreground="White" />
<TextBlock Text="Remote retreats in Svalbard" FontSize="12" Foreground="#CCffffff" />
</StackPanel>
</Grid>
</Border>
<!-- Card 3: Desert Sands -->
<Border Margin="16,0,16,20" CornerRadius="16" ClipToBounds="True" Height="240">
<Border.Background>
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_desert_sands.jpg"
Stretch="UniformToFill" />
</Border.Background>
<Grid>
<Border ClipToBounds="True" Margin="-1">
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Offset="0" Color="#66000000" />
<GradientStop Offset="0.5" Color="Transparent" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel VerticalAlignment="Bottom" Margin="16,0,16,16" Spacing="4">
<Border CornerRadius="12" Background="#33f47b25" Padding="8,4" HorizontalAlignment="Left">
<TextBlock Text="DESERT" FontSize="10" FontWeight="Bold" Foreground="#f47b25" />
</Border>
<TextBlock Text="Desert Sands" FontSize="22" FontWeight="Bold" Foreground="White" />
<TextBlock Text="Star gazing in Wadi Rum" FontSize="12" Foreground="#CCffffff" />
</StackPanel>
</Grid>
</Border>
</StackPanel>
</ScrollViewer>
</ContentPage>
<!-- Explore Tab -->
<ContentPage Header="Explore"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z</StreamGeometry>
</ContentPage.Icon>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="12" Margin="32">
<TextBlock Text="✦" FontSize="48" Foreground="#33FFFFFF" HorizontalAlignment="Center" />
<TextBlock Text="Explore" FontSize="20" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
<TextBlock Text="Discover new destinations around the world."
FontSize="13" Foreground="#80FFFFFF"
TextAlignment="Center" TextWrapping="Wrap" />
</StackPanel>
</ContentPage>
<!-- Saved Tab -->
<ContentPage Header="Saved"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z</StreamGeometry>
</ContentPage.Icon>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="12" Margin="32">
<TextBlock Text="♡" FontSize="48" Foreground="#33FFFFFF" HorizontalAlignment="Center" />
<TextBlock Text="Saved" FontSize="20" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
<TextBlock Text="Your saved destinations will appear here."
FontSize="13" Foreground="#80FFFFFF"
TextAlignment="Center" TextWrapping="Wrap" />
</StackPanel>
</ContentPage>
<!-- Profile Tab -->
<ContentPage Header="Profile"
Background="#221710">
<ContentPage.Icon>
<StreamGeometry>M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z</StreamGeometry>
</ContentPage.Icon>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="12" Margin="32">
<TextBlock Text="◉" FontSize="48" Foreground="#33FFFFFF" HorizontalAlignment="Center" />
<TextBlock Text="Profile" FontSize="20" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
<TextBlock Text="Your profile and settings will appear here."
FontSize="13" Foreground="#80FFFFFF"
TextAlignment="Center" TextWrapping="Wrap" />
</StackPanel>
</ContentPage>
</TabbedPage>
</Grid>
</DockPanel>
</UserControl>

11
samples/ControlCatalog/Pages/CarouselPage/SanctuaryMainPage.xaml.cs

@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace ControlCatalog.Pages;
public partial class SanctuaryMainPage : UserControl
{
public SanctuaryMainPage()
{
InitializeComponent();
}
}

335
samples/ControlCatalog/Pages/CarouselPage/SanctuaryShowcasePage.xaml

@ -0,0 +1,335 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.SanctuaryShowcasePage">
<UserControl.Styles>
<!-- Orange primary button -->
<Style Selector="Button.primary /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#f47b25" />
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" />
</Style>
<Style Selector="Button.primary:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#e0701f" />
</Style>
<Style Selector="Button.primary:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#c9611a" />
</Style>
<!-- Glass button (semi-transparent white) -->
<Style Selector="Button.glass /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#18FFFFFF" />
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" />
</Style>
<Style Selector="Button.glass:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#2AFFFFFF" />
</Style>
<Style Selector="Button.glass:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#10FFFFFF" />
</Style>
</UserControl.Styles>
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Sanctuary" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="A travel discovery app with 3 full-screen immersive pages. Uses PipsPager with custom pill-shaped indicators. Swipe, use arrow keys, tap the CTA buttons, or click the pip indicators to navigate." />
<Separator />
<TextBlock Text="Design" FontSize="13" FontWeight="SemiBold" />
<TextBlock FontSize="12" Text="Theme: Dark (#221710)" />
<TextBlock FontSize="12" Text="Primary: #f47b25 (warm orange)" />
<Separator />
<TextBlock Text="Pages" FontSize="13" FontWeight="SemiBold" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="1. Explore the Unknown — mountain backdrop" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="2. Hidden Sanctuaries — forest scene" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="3. Urban Adventures — neon city" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" CornerRadius="8" ClipToBounds="True" Margin="12">
<Grid>
<CarouselPage x:Name="DemoCarousel" IsGestureEnabled="True">
<!-- Page 1: Explore the Unknown -->
<ContentPage HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ContentPage.Background>
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/mountain_bg.jpg"
Stretch="UniformToFill" />
</ContentPage.Background>
<Grid>
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="Transparent" />
<GradientStop Offset="0.35" Color="#55221710" />
<GradientStop Offset="1" Color="#EE221710" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Grid RowDefinitions="*,Auto">
<StackPanel Grid.Row="1" Margin="28,0,28,44" Spacing="0"
HorizontalAlignment="Center">
<TextBlock Text="Explore the Unknown"
FontSize="36" FontWeight="Bold" Foreground="White"
TextAlignment="Center" TextWrapping="Wrap"
MaxWidth="300" Margin="0,0,0,14" />
<TextBlock Text="Embark on an unforgettable adventure through pristine wilderness and discover the hidden wonders of the world's most majestic peaks."
FontSize="14" Foreground="#CAffffff"
TextAlignment="Center" TextWrapping="Wrap"
MaxWidth="300" Margin="0,0,0,24" />
<Button Classes="primary"
Foreground="White" FontWeight="Bold" FontSize="16"
CornerRadius="24" Padding="24,16"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Click="OnPage1CTA" Margin="0,0,0,48">
<StackPanel Orientation="Horizontal" Spacing="10" HorizontalAlignment="Center">
<TextBlock Text="Start Journey" Foreground="White"
FontWeight="Bold" VerticalAlignment="Center" />
<TextBlock Text="→" Foreground="White" VerticalAlignment="Center" />
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Grid>
</ContentPage>
<!-- Page 2: Hidden Sanctuaries -->
<ContentPage HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ContentPage.Background>
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/forest_bg.jpg"
Stretch="UniformToFill" />
</ContentPage.Background>
<Grid>
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#88221710" />
<GradientStop Offset="0.3" Color="Transparent" />
<GradientStop Offset="0.75" Color="#55221710" />
<GradientStop Offset="1" Color="#CC221710" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Grid RowDefinitions="Auto,*,Auto">
<!-- Logo bar -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Spacing="8"
Margin="20,22,20,0">
<Panel Width="28" Height="28">
<Ellipse Fill="#f47b25" />
<TextBlock Text="▲" Foreground="White" FontSize="12" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Panel>
<TextBlock Text="SANCTUARY" Foreground="White" FontWeight="Bold"
FontSize="15" VerticalAlignment="Center" />
</StackPanel>
<!-- Center content -->
<StackPanel Grid.Row="1" Margin="24,0,24,0" Spacing="18"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Border CornerRadius="20" BorderBrush="#50f47b25" BorderThickness="1"
Background="#1Af47b25" HorizontalAlignment="Center" Padding="14,6">
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock Text="◎" Foreground="#f47b25" FontSize="11" VerticalAlignment="Center" />
<TextBlock Text="VOLUME II: SECLUSION" Foreground="#f47b25"
FontSize="11" FontWeight="Bold" />
</StackPanel>
</Border>
<StackPanel Spacing="0" HorizontalAlignment="Center">
<TextBlock Text="Hidden" Foreground="White"
FontSize="54" FontWeight="Bold" TextAlignment="Center" />
<TextBlock Text="Sanctuaries" Foreground="White"
FontSize="54" FontStyle="Italic" FontWeight="Light"
TextAlignment="Center" />
</StackPanel>
<TextBlock Text="Find your peace in the world's most secluded natural wonders. From misty forest groves to still mountain lakes, discover the quiet beauty of nature's best-kept secrets."
Foreground="#CCffffff" FontSize="14"
TextAlignment="Center" TextWrapping="Wrap" MaxWidth="310" />
<StackPanel Spacing="10" HorizontalAlignment="Center">
<Button Classes="primary"
Foreground="#221710" FontWeight="Bold" FontSize="15"
CornerRadius="24" Padding="32,16"
HorizontalContentAlignment="Center" MinWidth="220"
Click="OnPage2CTA">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="Discover More" Foreground="#221710"
FontWeight="Bold" VerticalAlignment="Center" />
<TextBlock Text="→" Foreground="#221710" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button Classes="glass"
Foreground="White" FontWeight="Bold" FontSize="15"
CornerRadius="24" Padding="32,16"
HorizontalContentAlignment="Center" MinWidth="220"
Click="OnPage2CTA">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="▷" Foreground="White" VerticalAlignment="Center" />
<TextBlock Text="Experience" Foreground="White"
FontWeight="Bold" VerticalAlignment="Center" />
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
<!-- Footer: location + social -->
<StackPanel Grid.Row="2" Spacing="14" Margin="0,0,0,44">
<Grid ColumnDefinitions="*,Auto" Margin="20,0,20,0">
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="5"
VerticalAlignment="Center">
<TextBlock Text="⊙" Foreground="#80FFFFFF" FontSize="11"
VerticalAlignment="Center" />
<TextBlock Text="NORDIC HIGHLANDS" Foreground="#80FFFFFF"
FontSize="10" FontWeight="SemiBold" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="14">
<TextBlock Text="Instagram" Foreground="#80FFFFFF"
FontSize="10" FontWeight="SemiBold" />
<TextBlock Text="Pinterest" Foreground="#80FFFFFF"
FontSize="10" FontWeight="SemiBold" />
</StackPanel>
</Grid>
</StackPanel>
</Grid>
</Grid>
</ContentPage>
<!-- Page 3: Urban Adventures -->
<ContentPage HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ContentPage.Background>
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/city_bg.jpg"
Stretch="UniformToFill" />
</ContentPage.Background>
<Grid>
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="Transparent" />
<GradientStop Offset="0.35" Color="#55221710" />
<GradientStop Offset="0.6" Color="#99221710" />
<GradientStop Offset="1" Color="#EE221710" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Grid RowDefinitions="*,Auto">
<StackPanel Grid.Row="1" Margin="28,0,28,44" Spacing="0"
HorizontalAlignment="Center">
<TextBlock Text="Urban Adventures"
FontSize="44" FontWeight="Bold" Foreground="White"
TextAlignment="Center" TextWrapping="Wrap"
MaxWidth="320" Margin="0,0,0,14" />
<Border Height="5" Width="88" CornerRadius="3"
Background="#f47b25" HorizontalAlignment="Center"
Margin="0,0,0,18" />
<TextBlock Text="Experience the electric pulse of the city that never sleeps. Explore hidden gems and neon-lit wonders around every corner."
FontSize="14" Foreground="#CAffffff"
TextAlignment="Center" TextWrapping="Wrap"
MaxWidth="300" Margin="0,0,0,24" />
<Button Classes="primary"
Foreground="White" FontWeight="Bold" FontSize="16"
CornerRadius="24" Padding="24,16"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Click="OnPage3CTA" Margin="0,0,0,48">
<TextBlock Text="Get Started" Foreground="White" FontWeight="Bold" />
</Button>
</StackPanel>
</Grid>
</Grid>
</ContentPage>
</CarouselPage>
<PipsPager HorizontalAlignment="Center"
VerticalAlignment="Bottom" Margin="0,0,0,20"
NumberOfPages="3"
SelectedPageIndex="{Binding #DemoCarousel.SelectedIndex}"
IsPreviousButtonVisible="False"
IsNextButtonVisible="False">
<PipsPager.Styles>
<Style Selector="PipsPager /template/ ListBox ListBoxItem">
<Setter Property="Width" Value="38" />
<Setter Property="Height" Value="24" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="2,0" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Grid Background="Transparent">
<Border Name="Pip"
Width="8" Height="8" CornerRadius="4"
HorizontalAlignment="Center" VerticalAlignment="Center"
Background="#4DFFFFFF">
<Border.Transitions>
<Transitions>
<DoubleTransition Property="Width" Duration="0:0:0.25" Easing="CubicEaseOut" />
<DoubleTransition Property="Height" Duration="0:0:0.25" Easing="CubicEaseOut" />
<CornerRadiusTransition Property="CornerRadius" Duration="0:0:0.25" Easing="CubicEaseOut" />
<BrushTransition Property="Background" Duration="0:0:0.25" />
</Transitions>
</Border.Transitions>
</Border>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pointerover /template/ Border#Pip">
<Setter Property="Width" Value="10" />
<Setter Property="Height" Value="10" />
<Setter Property="CornerRadius" Value="5" />
<Setter Property="Background" Value="#80FFFFFF" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected /template/ Border#Pip">
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="8" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Background" Value="#f47b25" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected:pointerover /template/ Border#Pip">
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="8" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Background" Value="#e0701f" />
</Style>
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pressed /template/ Border#Pip">
<Setter Property="Width" Value="8" />
<Setter Property="Height" Value="8" />
<Setter Property="Background" Value="#f47b25" />
</Style>
</PipsPager.Styles>
</PipsPager>
</Grid>
</Border>
</DockPanel>
</UserControl>

70
samples/ControlCatalog/Pages/CarouselPage/SanctuaryShowcasePage.xaml.cs

@ -0,0 +1,70 @@
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.VisualTree;
namespace ControlCatalog.Pages;
public partial class SanctuaryShowcasePage : UserControl
{
public SanctuaryShowcasePage()
{
InitializeComponent();
}
private void OnPage1CTA(object? sender, RoutedEventArgs e)
{
DemoCarousel.SelectedIndex = 1;
}
private void OnPage2CTA(object? sender, RoutedEventArgs e)
{
DemoCarousel.SelectedIndex = 2;
}
private async void OnPage3CTA(object? sender, RoutedEventArgs e)
{
var nav = this.FindAncestorOfType<NavigationPage>();
if (nav == null)
return;
var carouselWrapper = nav.NavigationStack.LastOrDefault();
var headerGrid = new Grid { ColumnDefinitions = new ColumnDefinitions("*, Auto") };
headerGrid.Children.Add(new TextBlock
{
Text = "Sanctuary",
VerticalAlignment = VerticalAlignment.Center
});
var closeIcon = Geometry.Parse(
"M4.397 4.397a1 1 0 0 1 1.414 0L12 10.585l6.19-6.188a1 1 0 0 1 1.414 1.414L13.413 12l6.19 6.189a1 1 0 0 1-1.414 1.414L12 13.413l-6.189 6.19a1 1 0 0 1-1.414-1.414L10.585 12 4.397 5.811a1 1 0 0 1 0-1.414z");
var closeBtn = new Button
{
Content = new PathIcon { Data = closeIcon },
Background = Brushes.Transparent,
BorderThickness = new Thickness(0),
Padding = new Thickness(8, 4),
VerticalAlignment = VerticalAlignment.Center
};
Grid.SetColumn(closeBtn, 1);
headerGrid.Children.Add(closeBtn);
closeBtn.Click += async (_, _) => await nav.PopAsync(null);
var mainPage = new ContentPage
{
Header = headerGrid,
Content = new SanctuaryMainPage()
};
NavigationPage.SetHasBackButton(mainPage, false);
await nav.PushAsync(mainPage);
if (carouselWrapper != null)
{
nav.RemovePage(carouselWrapper);
}
}
}

5
samples/ControlCatalog/Pages/ClipboardPage.xaml.cs

@ -34,7 +34,10 @@ namespace ControlCatalog.Pages
{
InitializeComponent();
_clipboardLastDataObjectChecker =
new DispatcherTimer(TimeSpan.FromSeconds(0.5), default, CheckLastDataObject);
new DispatcherTimer(TimeSpan.FromSeconds(0.5), default, CheckLastDataObject)
{
IsEnabled = false
};
using var asset = AssetLoader.Open(new Uri("avares://ControlCatalog/Assets/image1.jpg"));
_defaultImage = new Bitmap(asset);

95
samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml

@ -0,0 +1,95 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CommandBarEventsPage">
<UserControl.Resources>
<StreamGeometry x:Key="AddIcon">M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z</StreamGeometry>
<StreamGeometry x:Key="SaveIcon">M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z</StreamGeometry>
<StreamGeometry x:Key="ShareIcon">M18,16.08C17.24,16.08 16.56,16.38 16.04,16.85L8.91,12.7C8.96,12.47 9,12.24 9,12C9,11.76 8.96,11.53 8.91,11.3L15.96,7.19C16.5,7.69 17.21,8 18,8A3,3 0 0,0 21,5A3,3 0 0,0 18,2A3,3 0 0,0 15,5C15,5.24 15.04,5.47 15.09,5.7L8.04,9.81C7.5,9.31 6.79,9 6,9A3,3 0 0,0 3,12A3,3 0 0,0 6,15C6.79,15 7.5,14.69 8.04,14.19L15.16,18.34C15.11,18.55 15.08,18.77 15.08,19C15.08,20.61 16.39,21.91 18,21.91C19.61,21.91 20.92,20.61 20.92,19C20.92,17.39 19.61,16.08 18,16.08Z</StreamGeometry>
<StreamGeometry x:Key="ExportIcon">M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20M16,11V18.1L13.9,16L11.1,18.8L8.3,16L11.1,13.2L9,11.1L16,11Z</StreamGeometry>
<StreamGeometry x:Key="DeleteIcon">M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z</StreamGeometry>
</UserControl.Resources>
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="280">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Actions" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<CheckBox x:Name="IsOpenCheck"
Content="IsOpen"
IsCheckedChanged="OnIsOpenChanged" />
<Button Content="+ Add Primary"
HorizontalAlignment="Stretch"
Click="OnAddPrimary" />
<Button Content="- Remove Primary"
HorizontalAlignment="Stretch"
Click="OnRemovePrimary" />
<Button Content="+ Add Secondary"
HorizontalAlignment="Stretch"
Click="OnAddSecondary" />
<Button Content="- Remove Secondary"
HorizontalAlignment="Stretch"
Click="OnRemoveSecondary" />
<Button Content="Clear Log"
HorizontalAlignment="Stretch"
Click="OnClearLog" />
<Separator />
<TextBlock Text="State" FontWeight="SemiBold" />
<TextBlock x:Name="StateText"
FontSize="12"
Opacity="0.7"
TextWrapping="Wrap" />
<Separator />
<TextBlock Text="About" FontWeight="SemiBold" />
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap"
Text="Opening/Opened fire when the overflow opens. Closing/Closed fire when it closes. The log also records item clicks and command execution while the state panel reflects IsOpen, HasSecondaryCommands, and IsOverflowButtonVisible in real time." />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<ScrollViewer>
<StackPanel Spacing="12" Margin="12,12,12,0">
<TextBlock Classes="h2">Observe CommandBar overflow events, item invocation, and state changes while opening, closing, and editing the primary and secondary command sets.</TextBlock>
<CommandBar x:Name="DemoBar"
OverflowButtonVisibility="Auto">
<CommandBar.PrimaryCommands>
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton>
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<AppBarButton Label="Export"><AppBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></AppBarButton.Icon></AppBarButton>
<AppBarButton Label="Delete"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton>
</CommandBar.SecondaryCommands>
</CommandBar>
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
Padding="10">
<StackPanel Spacing="6">
<TextBlock Text="Event Log" FontWeight="SemiBold" />
<TextBlock x:Name="EventLogText"
FontFamily="Consolas, Menlo, monospace"
FontSize="12"
TextWrapping="Wrap"
MinHeight="140"
Opacity="0.8"
Text="Ready" />
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</DockPanel>
</UserControl>

220
samples/ControlCatalog/Pages/CommandBar/CommandBarEventsPage.xaml.cs

@ -0,0 +1,220 @@
using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;
using MiniMvvm;
namespace ControlCatalog.Pages
{
public partial class CommandBarEventsPage : UserControl
{
private readonly List<string> _log = new();
private int _primaryCount = 3;
private int _secondaryCount = 2;
public CommandBarEventsPage()
{
InitializeComponent();
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
private void OnLoaded(object? sender, RoutedEventArgs e)
{
DemoBar.Opening += OnOpening;
DemoBar.Opened += OnOpened;
DemoBar.Closing += OnClosing;
DemoBar.Closed += OnClosed;
DemoBar.PropertyChanged += OnBarPropertyChanged;
AttachItemHandlers(DemoBar.PrimaryCommands);
AttachItemHandlers(DemoBar.SecondaryCommands);
AppendLog("Ready");
RefreshState();
}
private void OnUnloaded(object? sender, RoutedEventArgs e)
{
DemoBar.Opening -= OnOpening;
DemoBar.Opened -= OnOpened;
DemoBar.Closing -= OnClosing;
DemoBar.Closed -= OnClosed;
DemoBar.PropertyChanged -= OnBarPropertyChanged;
DetachItemHandlers(DemoBar.PrimaryCommands);
DetachItemHandlers(DemoBar.SecondaryCommands);
}
private void OnIsOpenChanged(object? sender, RoutedEventArgs e)
{
DemoBar.IsOpen = IsOpenCheck.IsChecked == true;
RefreshState();
}
private void OnAddPrimary(object? sender, RoutedEventArgs e)
{
_primaryCount++;
var button = CreateButton($"Primary {_primaryCount}");
DemoBar.PrimaryCommands.Add(button);
AppendLog($"Primary +, {DemoBar.PrimaryCommands.Count}");
RefreshState();
}
private void OnRemovePrimary(object? sender, RoutedEventArgs e)
{
RemoveLastCommand(DemoBar.PrimaryCommands, "Primary");
}
private void OnAddSecondary(object? sender, RoutedEventArgs e)
{
_secondaryCount++;
var button = CreateButton($"Secondary {_secondaryCount}");
DemoBar.SecondaryCommands.Add(button);
AppendLog($"Secondary +, {DemoBar.SecondaryCommands.Count}");
RefreshState();
}
private void OnRemoveSecondary(object? sender, RoutedEventArgs e)
{
RemoveLastCommand(DemoBar.SecondaryCommands, "Secondary");
}
private void OnClearLog(object? sender, RoutedEventArgs e)
{
_log.Clear();
EventLogText.Text = "Log cleared";
}
private void OnOpening(object? sender, RoutedEventArgs e)
{
AppendLog("Opening");
RefreshState();
}
private void OnOpened(object? sender, RoutedEventArgs e)
{
AppendLog("Opened");
RefreshState();
}
private void OnClosing(object? sender, RoutedEventArgs e)
{
AppendLog("Closing");
RefreshState();
}
private void OnClosed(object? sender, RoutedEventArgs e)
{
AppendLog("Closed");
RefreshState();
}
private void OnBarPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == CommandBar.IsOpenProperty
|| e.Property == CommandBar.HasSecondaryCommandsProperty
|| e.Property == CommandBar.IsOverflowButtonVisibleProperty)
{
RefreshState();
}
}
private void RefreshState()
{
StateText.Text =
$"IsOpen: {DemoBar.IsOpen}\n" +
$"HasSecondaryCommands: {DemoBar.HasSecondaryCommands}\n" +
$"IsOverflowButtonVisible: {DemoBar.IsOverflowButtonVisible}\n" +
$"Primary: {DemoBar.PrimaryCommands.Count}\n" +
$"Secondary: {DemoBar.SecondaryCommands.Count}\n" +
$"OverflowItems: {DemoBar.OverflowItems.Count}";
IsOpenCheck.IsChecked = DemoBar.IsOpen;
}
private void OnCommandItemClick(object? sender, RoutedEventArgs e)
{
if (sender is AppBarButton button)
AppendLog($"Click, {button.Label}, {DescribePlacement(button)}");
}
private AppBarButton CreateButton(string label)
{
var button = new AppBarButton
{
Label = label,
Icon = new PathIcon
{
Data = StreamGeometry.Parse("M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z")
}
};
AttachItemHandler(button);
return button;
}
private void AttachItemHandlers(IEnumerable<ICommandBarElement> items)
{
foreach (var item in items)
AttachItemHandler(item);
}
private void DetachItemHandlers(IEnumerable<ICommandBarElement> items)
{
foreach (var item in items)
{
if (item is AppBarButton button)
button.Click -= OnCommandItemClick;
}
}
private void AttachItemHandler(ICommandBarElement item)
{
if (item is not AppBarButton button)
return;
button.Click -= OnCommandItemClick;
button.Click += OnCommandItemClick;
button.Command = MiniCommand.Create(() => AppendLog($"Command, {button.Label}, {DescribePlacement(button)}"));
}
private void RemoveLastCommand(IList<ICommandBarElement> items, string bucketName)
{
if (items.Count == 0)
return;
var item = items[^1];
var label = item is AppBarButton button ? button.Label ?? "(unnamed)" : item.GetType().Name;
if (item is AppBarButton appBarButton)
appBarButton.Click -= OnCommandItemClick;
items.RemoveAt(items.Count - 1);
AppendLog($"{bucketName} -, {label}, {items.Count}");
RefreshState();
}
private static string DescribePlacement(AppBarButton button)
{
return button.IsInOverflow ? "overflow" : "primary";
}
private void AppendLog(string message)
{
_log.Add(message);
if (_log.Count > 12)
_log.RemoveAt(0);
EventLogText.Text = string.Join("\n", _log.Select((entry, index) => $"{index + 1,2}. {entry}"));
}
}
}

1
samples/ControlCatalog/Pages/CommandBarPage.xaml.cs

@ -22,6 +22,7 @@ namespace ControlCatalog.Pages
// Features
("Features", "Overflow Menu", "Secondary commands appear in an overflow popup. Configure visibility and sticky behavior.", () => new CommandBarOverflowPage()),
("Features", "Dynamic Overflow", "IsDynamicOverflowEnabled moves primary commands to overflow as space shrinks.", () => new CommandBarDynamicOverflowPage()),
("Features", "Events & State", "Observe Opening, Opened, Closing, and Closed while tracking IsOpen, HasSecondaryCommands, and IsOverflowButtonVisible.", () => new CommandBarEventsPage()),
};
public CommandBarPage()

32
samples/ControlCatalog/Pages/ContentPage/ContentPageCommandBarPage.xaml

@ -34,12 +34,32 @@
<Separator />
<TextBlock Text="About" FontWeight="SemiBold" />
<TextBlock Text="• NavigationPage.SetTopCommandBar(page, bar): places a CommandBar inside the navigation bar area at the top."
FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
<TextBlock Text="• NavigationPage.SetBottomCommandBar(page, bar): places a CommandBar below the page content at the bottom."
FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
<TextBlock Text="• Each ContentPage has its own CommandBar. It is replaced when navigating between pages."
FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
<StackPanel Spacing="6">
<Grid ColumnDefinitions="Auto,*">
<TextBlock Text="•" FontSize="12" Opacity="0.7" Margin="0,0,6,0" />
<TextBlock Grid.Column="1"
Text="NavigationPage.SetTopCommandBar(page, bar): places a CommandBar inside the navigation bar area at the top."
FontSize="12"
Opacity="0.7"
TextWrapping="Wrap" />
</Grid>
<Grid ColumnDefinitions="Auto,*">
<TextBlock Text="•" FontSize="12" Opacity="0.7" Margin="0,0,6,0" />
<TextBlock Grid.Column="1"
Text="NavigationPage.SetBottomCommandBar(page, bar): places a CommandBar below the page content at the bottom."
FontSize="12"
Opacity="0.7"
TextWrapping="Wrap" />
</Grid>
<Grid ColumnDefinitions="Auto,*">
<TextBlock Text="•" FontSize="12" Opacity="0.7" Margin="0,0,6,0" />
<TextBlock Grid.Column="1"
Text="Each ContentPage has its own CommandBar. It is replaced when navigating between pages."
FontSize="12"
Opacity="0.7"
TextWrapping="Wrap" />
</Grid>
</StackPanel>
</StackPanel>
</ScrollViewer>

14
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -228,13 +228,8 @@ namespace ControlCatalog.Pages
try
{
// Sync disposal of StreamWriter is not supported on WASM
#if NET6_0_OR_GREATER
await using var stream = await file.OpenWriteAsync();
await using var writer = new System.IO.StreamWriter(stream);
#else
using var stream = await file.OpenWriteAsync();
using var writer = new System.IO.StreamWriter(stream);
#endif
await writer.WriteLineAsync(openedFileContent.Text);
SetFolder(await file.GetParentAsync());
@ -265,13 +260,8 @@ namespace ControlCatalog.Pages
if (result.File is { } file)
{
// Sync disposal of StreamWriter is not supported on WASM
#if NET6_0_OR_GREATER
await using var stream = await file.OpenWriteAsync();
await using var writer = new System.IO.StreamWriter(stream);
#else
using var stream = await file.OpenWriteAsync();
using var writer = new System.IO.StreamWriter(stream);
#endif
if (result.SelectedFileType == FilePickerFileTypes.Xml)
{
await writer.WriteLineAsync("<sample>Test</sample>");
@ -431,11 +421,7 @@ namespace ControlCatalog.Pages
internal static async Task<string> ReadTextFromFile(IStorageFile file, int length)
{
#if NET6_0_OR_GREATER
await using var stream = await file.OpenReadAsync();
#else
using var stream = await file.OpenReadAsync();
#endif
using var reader = new System.IO.StreamReader(stream);
// 4GB file test, shouldn't load more than 10000 chars into a memory.

3
samples/ControlCatalog/Pages/DrawerDemoPage.xaml.cs

@ -19,6 +19,9 @@ namespace ControlCatalog.Pages
("Features", "Compact Rail",
"CompactOverlay and CompactInline layout modes: a narrow icon rail is always visible and expands on open. Adjust rail width and open pane width.",
() => new DrawerPageCompactPage()),
("Features", "Breakpoint",
"DrawerBreakpointLength: below the threshold the drawer switches to Overlay mode automatically. Resize the window or adjust the slider to see the layout switch in real time.",
() => new DrawerPageBreakpointPage()),
("Features", "Events",
"Opened, Closing, and Closed drawer events plus NavigatedTo and NavigatedFrom page lifecycle events. Enable 'Cancel next close' to prevent the drawer from closing.",
() => new DrawerPageEventsPage()),

113
samples/ControlCatalog/Pages/DrawerPage/DrawerPageBreakpointPage.xaml

@ -0,0 +1,113 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.DrawerPageBreakpointPage">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="240">
<StackPanel Margin="12" Spacing="8">
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock Text="DrawerBreakpointLength" FontSize="13" FontWeight="SemiBold" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="When set, the drawer automatically switches layout based on the available size (width for Left/Right, height for Top/Bottom)." />
<Border Background="{DynamicResource SystemControlBackgroundBaseLowBrush}"
CornerRadius="4" Padding="8">
<StackPanel Spacing="4">
<Grid ColumnDefinitions="18,*">
<PathIcon Grid.Column="0" Width="12" Height="12" Opacity="0.7" VerticalAlignment="Top" Margin="0,1,0,0"
Data="M19,11H7.83L12.42,6.41L11,5L4,12L11,19L12.41,17.59L7.83,13H19V11Z" />
<TextBlock Grid.Column="1" FontSize="11" TextWrapping="Wrap"
Text="Below breakpoint → Overlay (hamburger button, drawer closes)" />
</Grid>
<Grid ColumnDefinitions="18,*">
<PathIcon Grid.Column="0" Width="12" Height="12" Opacity="0.7" VerticalAlignment="Top" Margin="0,1,0,0"
Data="M5,13H16.17L11.58,17.59L13,19L20,12L13,5L11.59,6.41L16.17,11H5V13Z" />
<TextBlock Grid.Column="1" FontSize="11" TextWrapping="Wrap"
Text="Above breakpoint → configured layout, drawer opens automatically" />
</Grid>
</StackPanel>
</Border>
<TextBlock Text="Breakpoint value" FontSize="12" Opacity="0.7" />
<StackPanel Orientation="Horizontal" Spacing="8">
<Slider x:Name="BreakpointSlider" Minimum="100" Maximum="900" Value="500"
Width="150" ValueChanged="OnBreakpointChanged" />
<TextBlock x:Name="BreakpointText" Text="500" VerticalAlignment="Center" />
</StackPanel>
<Separator />
<TextBlock Text="Layout above breakpoint" FontSize="13" FontWeight="SemiBold" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="The DrawerLayoutBehavior used when width exceeds the breakpoint." />
<ComboBox x:Name="LayoutCombo" SelectedIndex="0"
SelectionChanged="OnLayoutChanged" HorizontalAlignment="Stretch">
<ComboBoxItem Content="Split" />
<ComboBoxItem Content="CompactInline" />
<ComboBoxItem Content="CompactOverlay" />
</ComboBox>
<Separator />
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" />
<TextBlock x:Name="WidthText" Text="Width: —" Opacity="0.7" />
<TextBlock x:Name="ModeText" Text="Mode: Overlay" Opacity="0.7" TextWrapping="Wrap" />
<TextBlock TextWrapping="Wrap" FontSize="11" Opacity="0.6"
Text="Resize the window to see the layout switch automatically." />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<DrawerPage x:Name="DemoDrawer"
DrawerLayoutBehavior="Split"
DrawerBreakpointLength="500"
DrawerLength="200">
<DrawerPage.Drawer>
<StackPanel Margin="8" Spacing="4">
<Button HorizontalAlignment="Stretch" Background="Transparent"
Click="OnMenuItemClick" Tag="Home">
<StackPanel Orientation="Horizontal" Spacing="8">
<PathIcon Width="16" Height="16"
Data="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z" />
<TextBlock Text="Home" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button HorizontalAlignment="Stretch" Background="Transparent"
Click="OnMenuItemClick" Tag="Profile">
<StackPanel Orientation="Horizontal" Spacing="8">
<PathIcon Width="16" Height="16"
Data="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" />
<TextBlock Text="Profile" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button HorizontalAlignment="Stretch" Background="Transparent"
Click="OnMenuItemClick" Tag="Settings">
<StackPanel Orientation="Horizontal" Spacing="8">
<PathIcon Width="16" Height="16"
Data="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.04 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.68 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.04 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" />
<TextBlock Text="Settings" VerticalAlignment="Center" />
</StackPanel>
</Button>
</StackPanel>
</DrawerPage.Drawer>
<DrawerPage.Content>
<ContentPage x:Name="DetailPage" Header="Home">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8">
<TextBlock x:Name="DetailTitleText" Text="Home" FontSize="24" FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="Select an item from the drawer." FontSize="13" Opacity="0.7"
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="260" />
</StackPanel>
</ContentPage>
</DrawerPage.Content>
</DrawerPage>
</Border>
</DockPanel>
</UserControl>

84
samples/ControlCatalog/Pages/DrawerPage/DrawerPageBreakpointPage.xaml.cs

@ -0,0 +1,84 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class DrawerPageBreakpointPage : UserControl
{
private bool _isLoaded;
public DrawerPageBreakpointPage()
{
InitializeComponent();
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
_isLoaded = true;
DemoDrawer.PropertyChanged += OnDrawerPropertyChanged;
UpdateStatus();
}
protected override void OnUnloaded(RoutedEventArgs e)
{
base.OnUnloaded(e);
DemoDrawer.PropertyChanged -= OnDrawerPropertyChanged;
}
private void OnDrawerPropertyChanged(object? sender, Avalonia.AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == DrawerPage.BoundsProperty)
UpdateStatus();
}
private void OnBreakpointChanged(object? sender, RangeBaseValueChangedEventArgs e)
{
if (!_isLoaded)
return;
var value = (int)e.NewValue;
DemoDrawer.DrawerBreakpointLength = value;
BreakpointText.Text = value.ToString();
UpdateStatus();
}
private void OnLayoutChanged(object? sender, SelectionChangedEventArgs e)
{
if (!_isLoaded)
return;
DemoDrawer.DrawerLayoutBehavior = LayoutCombo.SelectedIndex switch
{
0 => DrawerLayoutBehavior.Split,
1 => DrawerLayoutBehavior.CompactInline,
2 => DrawerLayoutBehavior.CompactOverlay,
_ => DrawerLayoutBehavior.Split
};
UpdateStatus();
}
private void OnMenuItemClick(object? sender, RoutedEventArgs e)
{
if (!_isLoaded || sender is not Button button)
return;
var item = button.Tag?.ToString() ?? "Home";
DetailTitleText.Text = item;
DetailPage.Header = item;
if (DemoDrawer.DrawerLayoutBehavior != DrawerLayoutBehavior.Split)
DemoDrawer.IsOpen = false;
}
private void UpdateStatus()
{
var isVertical = DemoDrawer.DrawerPlacement == DrawerPlacement.Top ||
DemoDrawer.DrawerPlacement == DrawerPlacement.Bottom;
var length = isVertical ? DemoDrawer.Bounds.Height : DemoDrawer.Bounds.Width;
var breakpoint = DemoDrawer.DrawerBreakpointLength;
WidthText.Text = $"{(isVertical ? "Height" : "Width")}: {(int)length} px";
var isOverlay = breakpoint > 0 && length > 0 && length < breakpoint;
ModeText.Text = isOverlay ?
"Mode: Overlay (below breakpoint)" :
$"Mode: {DemoDrawer.DrawerLayoutBehavior} (above breakpoint)";
}
}
}

5
samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml

@ -118,6 +118,11 @@
Header="Customization"
DrawerLength="260"
DrawerHeaderBackground="{DynamicResource SystemControlHighlightAccentBrush}">
<DrawerPage.DrawerIconTemplate>
<DataTemplate DataType="Geometry">
<PathIcon Data="{Binding}" />
</DataTemplate>
</DrawerPage.DrawerIconTemplate>
<DrawerPage.DrawerHeader>
<Border x:Name="DrawerHeaderBorder" Padding="16">
<StackPanel Spacing="4">

13
samples/ControlCatalog/Pages/DrawerPage/DrawerPageCustomizationPage.xaml.cs

@ -1,5 +1,7 @@
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input.GestureRecognizers;
using Avalonia.Interactivity;
using Avalonia.Media;
@ -22,6 +24,7 @@ namespace ControlCatalog.Pages
public DrawerPageCustomizationPage()
{
InitializeComponent();
EnableMouseSwipeGesture(DemoDrawer);
}
protected override void OnLoaded(RoutedEventArgs e)
@ -188,5 +191,15 @@ namespace ControlCatalog.Pages
if (DemoDrawer.DrawerBehavior != DrawerBehavior.Locked)
DemoDrawer.IsOpen = false;
}
private static void EnableMouseSwipeGesture(Control control)
{
var recognizer = control.GestureRecognizers
.OfType<SwipeGestureRecognizer>()
.FirstOrDefault();
if (recognizer is not null)
recognizer.IsMouseEnabled = true;
}
}
}

13
samples/ControlCatalog/Pages/DrawerPage/DrawerPageFirstLookPage.xaml.cs

@ -1,4 +1,6 @@
using System.Linq;
using Avalonia.Controls;
using Avalonia.Input.GestureRecognizers;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
@ -8,6 +10,7 @@ namespace ControlCatalog.Pages
public DrawerPageFirstLookPage()
{
InitializeComponent();
EnableMouseSwipeGesture(DemoDrawer);
}
protected override void OnLoaded(RoutedEventArgs e)
@ -61,5 +64,15 @@ namespace ControlCatalog.Pages
{
StatusText.Text = $"Drawer: {(DemoDrawer.IsOpen ? "Open" : "Closed")}";
}
private static void EnableMouseSwipeGesture(Control control)
{
var recognizer = control.GestureRecognizers
.OfType<SwipeGestureRecognizer>()
.FirstOrDefault();
if (recognizer is not null)
recognizer.IsMouseEnabled = true;
}
}
}

8
samples/ControlCatalog/Pages/DrawerPage/EcoTrackerAppPage.xaml

@ -52,9 +52,13 @@
</DrawerPage.Resources>
<DrawerPage.DrawerIcon>
<PathIcon Width="22" Height="22"
Data="M12 3C9 6 6 9 6 13C6 17.4 8.7 21 12 22C15.3 21 18 17.4 18 13C18 9 15 6 12 3Z" />
<StreamGeometry>M12 3C9 6 6 9 6 13C6 17.4 8.7 21 12 22C15.3 21 18 17.4 18 13C18 9 15 6 12 3Z</StreamGeometry>
</DrawerPage.DrawerIcon>
<DrawerPage.DrawerIconTemplate>
<DataTemplate DataType="Geometry">
<PathIcon Width="22" Height="22" Data="{Binding}" />
</DataTemplate>
</DrawerPage.DrawerIconTemplate>
<DrawerPage.DrawerHeader>
<StackPanel Background="{StaticResource EcoDrawerBg}" Margin="0,0,0,8">

3
samples/ControlCatalog/Pages/NavigationDemoPage.xaml.cs

@ -28,6 +28,9 @@ namespace ControlCatalog.Pages
// Data
("Data", "Pass Data", "Pass data during navigation via constructor arguments or DataContext.",
() => new NavigationPagePassDataPage()),
("Data", "MVVM Navigation",
"Keep navigation decisions in view models by routing NavigationPage push and pop operations through a small INavigationService.",
() => new NavigationPageMvvmPage()),
// Features
("Features", "Attached Methods",

51
samples/ControlCatalog/Pages/NavigationPage/LAvenirAppPage.xaml.cs

@ -59,6 +59,26 @@ public partial class LAvenirAppPage : UserControl
_infoPanel.IsVisible = Bounds.Width >= 650;
}
void ApplyRootNavigationBarAppearance()
{
if (_navPage == null)
return;
_navPage.Background = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarForeground"] = new SolidColorBrush(TextDark);
}
void ApplyDetailNavigationBarAppearance()
{
if (_navPage == null)
return;
_navPage.Background = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarForeground"] = Brushes.White;
}
TabbedPage BuildMenuTabbedPage()
{
var tp = new TabbedPage
@ -92,6 +112,7 @@ public partial class LAvenirAppPage : UserControl
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Center,
};
ApplyRootNavigationBarAppearance();
NavigationPage.SetTopCommandBar(tp, new Button
{
@ -119,7 +140,7 @@ public partial class LAvenirAppPage : UserControl
Content = menuView,
Background = new SolidColorBrush(BgLight),
Header = "Menu",
Icon = "M11 9H9V2H7v7H5V2H3v7c0 2.12 1.66 3.84 3.75 3.97V22h2.5v-9.03C11.34 12.84 13 11.12 13 9V2h-2v7zm5-3v8h2.5v8H21V2c-2.76 0-5 2.24-5 4z",
Icon = Geometry.Parse("M11 9H9V2H7v7H5V2H3v7c0 2.12 1.66 3.84 3.75 3.97V22h2.5v-9.03C11.34 12.84 13 11.12 13 9V2h-2v7zm5-3v8h2.5v8H21V2c-2.76 0-5 2.24-5 4z"),
};
var reservationsPage = new ContentPage
@ -127,7 +148,7 @@ public partial class LAvenirAppPage : UserControl
Content = new LAvenirReservationsView(),
Background = new SolidColorBrush(BgLight),
Header = "Reservations",
Icon = "M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM9 10H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2z",
Icon = Geometry.Parse("M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM9 10H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2z"),
};
var profilePage = new ContentPage
@ -135,7 +156,7 @@ public partial class LAvenirAppPage : UserControl
Content = new LAvenirProfileView(),
Background = new SolidColorBrush(BgLight),
Header = "Profile",
Icon = "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z",
Icon = Geometry.Parse("M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"),
};
tp.Pages = new ObservableCollection<Page> { menuPage, reservationsPage, profilePage };
@ -144,7 +165,8 @@ public partial class LAvenirAppPage : UserControl
async void PushDishDetail(string name, string price, string description, string imageFile)
{
if (_navPage == null) return;
if (_navPage == null)
return;
var detail = new ContentPage
{
@ -153,22 +175,19 @@ public partial class LAvenirAppPage : UserControl
Header = name,
};
NavigationPage.SetBottomCommandBar(detail, BuildFloatingBar(price));
_navPage.Background = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarForeground"] = Brushes.White;
detail.NavigatedFrom += (_, _) =>
detail.Navigating += args =>
{
if (_navPage != null)
{
_navPage.Background = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarForeground"] = new SolidColorBrush(TextDark);
}
if (args.NavigationType == NavigationType.Pop)
ApplyRootNavigationBarAppearance();
return Task.CompletedTask;
};
ApplyDetailNavigationBarAppearance();
await _navPage.PushAsync(detail);
if (!ReferenceEquals(_navPage.CurrentPage, detail))
ApplyRootNavigationBarAppearance();
}
Border BuildFloatingBar(string price)

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageAppearancePage.xaml.cs

@ -8,6 +8,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageAppearancePage : UserControl
{
private bool _initialized;
private int _pageCount;
private int _backButtonStyle;
@ -19,6 +20,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Appearance", "Change bar properties using the options panel.", 0), null);
}

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageAttachedMethodsPage.xaml.cs

@ -8,6 +8,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageAttachedMethodsPage : UserControl
{
private bool _initialized;
private int _pageCount;
public NavigationPageAttachedMethodsPage()
@ -18,6 +19,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
await DemoNav.PushAsync(new ContentPage
{
Header = "Root Page",

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageBackButtonPage.xaml.cs

@ -8,6 +8,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageBackButtonPage : UserControl
{
private bool _initialized;
private int _pushCount;
public NavigationPageBackButtonPage()
@ -18,6 +19,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
DemoNav.Pushed += (s, ev) => AddLog($"Pushed: \"{ev.Page?.Header}\"");
DemoNav.Popped += (s, ev) => AddLog($"Popped: \"{ev.Page?.Header}\"");

7
samples/ControlCatalog/Pages/NavigationPage/NavigationPageEventsPage.xaml

@ -51,6 +51,13 @@
</ScrollViewer>
</Border>
<Separator />
<!-- IsNavigating indicator -->
<TextBlock Text="Status" FontSize="13" FontWeight="SemiBold" />
<TextBlock Text="{Binding IsNavigating, ElementName=DemoNav, StringFormat='IsNavigating: {0}'}"
FontSize="12" />
<Separator />
<TextBlock Text="NavigationPage exposes events for push, pop, insert, remove, and modal operations. Pages also fire NavigatedTo and NavigatedFrom on each navigation."
TextWrapping="Wrap" FontSize="12" Opacity="0.7" />

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageEventsPage.xaml.cs

@ -7,6 +7,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageEventsPage : UserControl
{
private bool _initialized;
private int _pageCount;
public NavigationPageEventsPage()
@ -17,6 +18,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
DemoNav.Pushed += (s, ev) => AddLog($"Pushed → {ev.Page?.Header}");
DemoNav.Popped += (s, ev) => AddLog($"Popped ← {ev.Page?.Header}");
DemoNav.PoppedToRoot += (s, ev) => AddLog("PoppedToRoot");

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageFirstLookPage.xaml.cs

@ -6,6 +6,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageFirstLookPage : UserControl
{
private bool _initialized;
private int _pageCount;
public NavigationPageFirstLookPage()
@ -16,6 +17,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Home", "Welcome!\nUse the buttons to push and pop pages.", 0), null);
UpdateStatus();
}

19
samples/ControlCatalog/Pages/NavigationPage/NavigationPageGesturePage.xaml.cs

@ -1,18 +1,27 @@
using System.Linq;
using Avalonia.Controls;
using Avalonia.Input.GestureRecognizers;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class NavigationPageGesturePage : UserControl
{
private bool _initialized;
public NavigationPageGesturePage()
{
InitializeComponent();
EnableMouseSwipeGesture(DemoNav);
Loaded += OnLoaded;
}
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Page 1", "← Drag from the left edge to go back", 0), null);
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Page 2", "← Drag from the left edge to go back", 1), null);
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Page 3", "← Drag from the left edge to go back", 2), null);
@ -43,5 +52,15 @@ namespace ControlCatalog.Pages
{
StatusText.Text = $"Depth: {DemoNav.StackDepth}";
}
private static void EnableMouseSwipeGesture(Control control)
{
var recognizer = control.GestureRecognizers
.OfType<SwipeGestureRecognizer>()
.FirstOrDefault();
if (recognizer is not null)
recognizer.IsMouseEnabled = true;
}
}
}

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageInteractiveHeaderPage.xaml.cs

@ -37,6 +37,7 @@ namespace ControlCatalog.Pages
];
private readonly ObservableCollection<ContactItem> _filteredItems = new(AllContacts);
private bool _initialized;
private string _searchText = "";
public NavigationPageInteractiveHeaderPage()
@ -47,6 +48,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
var headerGrid = new Grid
{
ColumnDefinitions = new ColumnDefinitions("*, Auto"),

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageModalPage.xaml.cs

@ -7,6 +7,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageModalPage : UserControl
{
private bool _initialized;
private int _modalCount;
public NavigationPageModalPage()
@ -17,6 +18,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Home", "Use Push Modal to show a modal on top.", 0), null);
}

8
samples/ControlCatalog/Pages/NavigationPage/NavigationPageModalTransitionsPage.xaml.cs

@ -20,6 +20,7 @@ namespace ControlCatalog.Pages
];
private int _modalCount;
private bool _initialized;
public NavigationPageModalTransitionsPage()
{
@ -29,6 +30,13 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
{
UpdateTransition();
return;
}
_initialized = true;
await DemoNav.PushAsync(new ContentPage
{
Header = "Modal Transitions",

95
samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmNavigation.cs

@ -0,0 +1,95 @@
using System;
using System.Threading.Tasks;
using Avalonia.Controls;
using MiniMvvm;
namespace ControlCatalog.Pages
{
internal interface ISampleNavigationService
{
event EventHandler<NavigationStateChangedEventArgs>? StateChanged;
Task NavigateToAsync(ViewModelBase viewModel);
Task GoBackAsync();
Task PopToRootAsync();
}
internal interface ISamplePageFactory
{
ContentPage CreatePage(ViewModelBase viewModel);
}
internal sealed class NavigationStateChangedEventArgs : EventArgs
{
public NavigationStateChangedEventArgs(string currentPageHeader, int navigationDepth, string lastAction)
{
CurrentPageHeader = currentPageHeader;
NavigationDepth = navigationDepth;
LastAction = lastAction;
}
public string CurrentPageHeader { get; }
public int NavigationDepth { get; }
public string LastAction { get; }
}
internal sealed class SampleNavigationService : ISampleNavigationService
{
private readonly NavigationPage _navigationPage;
private readonly ISamplePageFactory _pageFactory;
public SampleNavigationService(NavigationPage navigationPage, ISamplePageFactory pageFactory)
{
_navigationPage = navigationPage;
_pageFactory = pageFactory;
_navigationPage.Pushed += (_, e) => PublishState($"Pushed {e.Page?.Header}");
_navigationPage.Popped += (_, e) => PublishState($"Popped {e.Page?.Header}");
_navigationPage.PoppedToRoot += (_, _) => PublishState("Popped to root");
}
public event EventHandler<NavigationStateChangedEventArgs>? StateChanged;
public async Task NavigateToAsync(ViewModelBase viewModel)
{
var page = _pageFactory.CreatePage(viewModel);
await _navigationPage.PushAsync(page);
}
public async Task GoBackAsync()
{
if (_navigationPage.NavigationStack.Count <= 1)
{
PublishState("Already at the root page");
return;
}
await _navigationPage.PopAsync();
}
public async Task PopToRootAsync()
{
if (_navigationPage.NavigationStack.Count <= 1)
{
PublishState("Already at the root page");
return;
}
await _navigationPage.PopToRootAsync();
}
private void PublishState(string lastAction)
{
var header = _navigationPage.CurrentPage?.Header?.ToString() ?? "None";
StateChanged?.Invoke(this, new NavigationStateChangedEventArgs(
header,
_navigationPage.NavigationStack.Count,
lastAction));
}
}
}

86
samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmPage.xaml

@ -0,0 +1,86 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:pages="using:ControlCatalog.Pages"
x:Class="ControlCatalog.Pages.NavigationPageMvvmPage"
x:DataType="pages:NavigationPageMvvmShellViewModel">
<DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="300">
<StackPanel Margin="12" Spacing="12">
<TextBlock Text="MVVM Pattern"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap"
FontSize="12"
Opacity="0.75"
Text="This sample keeps NavigationPage in the view, sends commands from view models, routes push or pop operations through ISampleNavigationService, and resolves pages in a separate SamplePageFactory." />
<Separator />
<TextBlock Text="Selected Project"
FontSize="13"
FontWeight="SemiBold" />
<ListBox ItemsSource="{Binding Projects}"
SelectedItem="{Binding SelectedProject, Mode=TwoWay}"
MaxHeight="180">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="pages:ProjectCardViewModel">
<StackPanel Margin="0,2" Spacing="2">
<TextBlock Text="{Binding Name}"
FontWeight="SemiBold" />
<TextBlock Text="{Binding Owner}"
FontSize="11"
Opacity="0.65" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Open Selected Project"
Command="{Binding OpenSelectedProjectCommand}" />
<Button Content="Back"
Command="{Binding GoBackCommand}" />
<Button Content="Pop To Root"
Command="{Binding PopToRootCommand}" />
<Separator />
<TextBlock Text="Navigation State"
FontSize="13"
FontWeight="SemiBold" />
<TextBlock Text="{Binding CurrentPageHeader, StringFormat=Current page: {0}}"
Opacity="0.75" />
<TextBlock Text="{Binding NavigationDepth, StringFormat=Stack depth: {0}}"
Opacity="0.75" />
<TextBlock Text="{Binding LastAction, StringFormat=Last action: {0}}"
Opacity="0.75"
TextWrapping="Wrap" />
<Separator />
<TextBlock Text="Selected Details"
FontSize="13"
FontWeight="SemiBold" />
<TextBlock Text="{Binding SelectedProject.Status, StringFormat=Status: {0}}"
Opacity="0.75" />
<TextBlock Text="{Binding SelectedProject.NextMilestone, StringFormat=Next milestone: {0}}"
Opacity="0.75"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<Border DockPanel.Dock="Right"
Width="1"
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Border Margin="12"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
ClipToBounds="True">
<NavigationPage x:Name="DemoNav" />
</Border>
</DockPanel>
</UserControl>

32
samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmPage.xaml.cs

@ -0,0 +1,32 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace ControlCatalog.Pages
{
public partial class NavigationPageMvvmPage : UserControl
{
private readonly NavigationPageMvvmShellViewModel _viewModel;
private bool _initialized;
public NavigationPageMvvmPage()
{
InitializeComponent();
ISamplePageFactory pageFactory = new SamplePageFactory();
ISampleNavigationService navigationService = new SampleNavigationService(DemoNav, pageFactory);
_viewModel = new NavigationPageMvvmShellViewModel(navigationService);
DataContext = _viewModel;
Loaded += OnLoaded;
}
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
await _viewModel.InitializeAsync();
}
}
}

252
samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmPageFactory.cs

@ -0,0 +1,252 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Layout;
using Avalonia.Media;
using MiniMvvm;
namespace ControlCatalog.Pages
{
internal sealed class SamplePageFactory : ISamplePageFactory
{
public ContentPage CreatePage(ViewModelBase viewModel) =>
viewModel switch
{
WorkspaceViewModel workspace => CreateWorkspacePage(workspace),
ProjectDetailViewModel detail => CreateProjectDetailPage(detail),
ProjectActivityViewModel activity => CreateProjectActivityPage(activity),
_ => throw new InvalidOperationException($"Unsupported view model: {viewModel.GetType().Name}")
};
private static ContentPage CreateWorkspacePage(WorkspaceViewModel viewModel)
{
var stack = new StackPanel
{
Margin = new Thickness(20),
Spacing = 14,
};
stack.Children.Add(new TextBlock
{
Text = viewModel.Title,
FontSize = 24,
FontWeight = FontWeight.Bold,
});
stack.Children.Add(new TextBlock
{
Text = viewModel.Description,
FontSize = 13,
Opacity = 0.75,
TextWrapping = TextWrapping.Wrap,
});
stack.Children.Add(new ItemsControl
{
ItemsSource = viewModel.Projects,
ItemTemplate = new FuncDataTemplate<ProjectCardViewModel>((item, _) =>
{
if (item == null)
return new TextBlock();
var accentBrush = new SolidColorBrush(item.AccentColor);
var statusBadge = new Border
{
Background = accentBrush,
CornerRadius = new CornerRadius(999),
Padding = new Thickness(10, 4),
Child = new TextBlock
{
Text = item.Status,
Foreground = Brushes.White,
FontSize = 11,
FontWeight = FontWeight.SemiBold,
}
};
DockPanel.SetDock(statusBadge, Dock.Right);
var header = new DockPanel();
header.Children.Add(statusBadge);
header.Children.Add(new TextBlock
{
Text = item.Name,
FontSize = 17,
FontWeight = FontWeight.SemiBold,
});
return new Border
{
Background = new SolidColorBrush(Color.FromArgb(20, item.AccentColor.R, item.AccentColor.G, item.AccentColor.B)),
BorderBrush = accentBrush,
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(8),
Padding = new Thickness(14),
Margin = new Thickness(0, 0, 0, 8),
Child = new StackPanel
{
Spacing = 8,
Children =
{
header,
new TextBlock
{
Text = item.Summary,
FontSize = 13,
Opacity = 0.72,
TextWrapping = TextWrapping.Wrap,
},
new TextBlock
{
Text = $"Owner: {item.Owner} • Next: {item.NextMilestone}",
FontSize = 12,
Opacity = 0.6,
TextWrapping = TextWrapping.Wrap,
},
new Button
{
Content = "Open Project",
HorizontalAlignment = HorizontalAlignment.Left,
Command = item.OpenCommand,
}
}
}
};
})
});
var page = new ContentPage
{
Header = "Workspace",
Content = new ScrollViewer { Content = stack },
HorizontalContentAlignment = HorizontalAlignment.Stretch,
VerticalContentAlignment = VerticalAlignment.Stretch,
};
NavigationPage.SetHasBackButton(page, false);
return page;
}
private static ContentPage CreateProjectDetailPage(ProjectDetailViewModel viewModel)
{
var accentBrush = new SolidColorBrush(viewModel.AccentColor);
var panel = new StackPanel
{
Margin = new Thickness(24, 20),
Spacing = 12,
};
panel.Children.Add(new Border
{
Background = accentBrush,
CornerRadius = new CornerRadius(999),
Padding = new Thickness(12, 5),
HorizontalAlignment = HorizontalAlignment.Left,
Child = new TextBlock
{
Text = viewModel.Status,
Foreground = Brushes.White,
FontSize = 11,
FontWeight = FontWeight.SemiBold,
}
});
panel.Children.Add(new TextBlock
{
Text = viewModel.Name,
FontSize = 26,
FontWeight = FontWeight.Bold,
});
panel.Children.Add(new TextBlock
{
Text = viewModel.Summary,
FontSize = 14,
Opacity = 0.78,
TextWrapping = TextWrapping.Wrap,
});
panel.Children.Add(new TextBlock
{
Text = $"Owner: {viewModel.Owner}",
FontSize = 13,
Opacity = 0.68,
});
panel.Children.Add(new TextBlock
{
Text = $"Next milestone: {viewModel.NextMilestone}",
FontSize = 13,
Opacity = 0.68,
TextWrapping = TextWrapping.Wrap,
});
panel.Children.Add(new Separator { Margin = new Thickness(0, 4) });
panel.Children.Add(new TextBlock
{
Text = "This page is resolved by SamplePageFactory from a ProjectDetailViewModel. The view model only requests navigation through ISampleNavigationService.",
FontSize = 12,
Opacity = 0.7,
TextWrapping = TextWrapping.Wrap,
});
panel.Children.Add(new Button
{
Content = "Open Activity",
HorizontalAlignment = HorizontalAlignment.Left,
Command = viewModel.OpenActivityCommand,
});
return new ContentPage
{
Header = viewModel.Name,
Background = new SolidColorBrush(Color.FromArgb(18, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
Content = new ScrollViewer { Content = panel },
HorizontalContentAlignment = HorizontalAlignment.Stretch,
VerticalContentAlignment = VerticalAlignment.Stretch,
};
}
private static ContentPage CreateProjectActivityPage(ProjectActivityViewModel viewModel)
{
var panel = new StackPanel
{
Margin = new Thickness(24, 20),
Spacing = 10,
};
panel.Children.Add(new TextBlock
{
Text = "Activity Timeline",
FontSize = 24,
FontWeight = FontWeight.Bold,
});
panel.Children.Add(new TextBlock
{
Text = $"Recent updates for {viewModel.Name}. This page was opened from a command on the detail view model.",
FontSize = 13,
Opacity = 0.74,
TextWrapping = TextWrapping.Wrap,
});
foreach (var item in viewModel.Items)
{
panel.Children.Add(new Border
{
Background = new SolidColorBrush(Color.FromArgb(14, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
BorderBrush = new SolidColorBrush(Color.FromArgb(80, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(6),
Padding = new Thickness(12, 10),
Child = new TextBlock
{
Text = item,
FontSize = 13,
TextWrapping = TextWrapping.Wrap,
}
});
}
return new ContentPage
{
Header = "Activity",
Content = new ScrollViewer { Content = panel },
HorizontalContentAlignment = HorizontalAlignment.Stretch,
VerticalContentAlignment = VerticalAlignment.Stretch,
};
}
}
}

238
samples/ControlCatalog/Pages/NavigationPage/NavigationPageMvvmViewModels.cs

@ -0,0 +1,238 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia.Media;
using MiniMvvm;
namespace ControlCatalog.Pages
{
public sealed class NavigationPageMvvmShellViewModel : ViewModelBase
{
private readonly ISampleNavigationService _navigationService;
private string _currentPageHeader = "Not initialized";
private string _lastAction = "Waiting for first load";
private int _navigationDepth;
private ProjectCardViewModel? _selectedProject;
internal NavigationPageMvvmShellViewModel(ISampleNavigationService navigationService)
{
_navigationService = navigationService;
_navigationService.StateChanged += OnStateChanged;
Workspace = new WorkspaceViewModel(CreateProjects(navigationService));
SelectedProject = Workspace.Projects[0];
OpenSelectedProjectCommand = MiniCommand.CreateFromTask(OpenSelectedProjectAsync);
GoBackCommand = MiniCommand.CreateFromTask(_navigationService.GoBackAsync);
PopToRootCommand = MiniCommand.CreateFromTask(_navigationService.PopToRootAsync);
}
internal WorkspaceViewModel Workspace { get; }
public IReadOnlyList<ProjectCardViewModel> Projects => Workspace.Projects;
public MiniCommand OpenSelectedProjectCommand { get; }
public MiniCommand GoBackCommand { get; }
public MiniCommand PopToRootCommand { get; }
public string CurrentPageHeader
{
get => _currentPageHeader;
set => this.RaiseAndSetIfChanged(ref _currentPageHeader, value);
}
public int NavigationDepth
{
get => _navigationDepth;
set => this.RaiseAndSetIfChanged(ref _navigationDepth, value);
}
public string LastAction
{
get => _lastAction;
set => this.RaiseAndSetIfChanged(ref _lastAction, value);
}
public ProjectCardViewModel? SelectedProject
{
get => _selectedProject;
set => this.RaiseAndSetIfChanged(ref _selectedProject, value);
}
public Task InitializeAsync() => _navigationService.NavigateToAsync(Workspace);
private async Task OpenSelectedProjectAsync()
{
if (SelectedProject == null)
return;
await SelectedProject.OpenCommandAsync();
}
private void OnStateChanged(object? sender, NavigationStateChangedEventArgs e)
{
CurrentPageHeader = e.CurrentPageHeader;
NavigationDepth = e.NavigationDepth;
LastAction = e.LastAction;
}
private static IReadOnlyList<ProjectCardViewModel> CreateProjects(ISampleNavigationService navigationService) =>
new[]
{
new ProjectCardViewModel(
"Release Radar",
"Marta Collins",
"Ready for QA",
"Coordinate the 11.0 release checklist and lock down the final regression window.",
"Freeze build on Friday",
Color.Parse("#0063B1"),
navigationService,
new[]
{
"Release notes draft updated with accessibility fixes.",
"Package validation finished for desktop artifacts.",
"Remaining task, confirm browser smoke test coverage."
}),
new ProjectCardViewModel(
"Support Console",
"Jae Kim",
"Active Sprint",
"Consolidate customer incidents into a triage board and route them to platform owners.",
"Triage review in 2 hours",
Color.Parse("#0F7B0F"),
navigationService,
new[]
{
"Five customer reports grouped under input routing.",
"Hotfix candidate approved for preview branch.",
"Awaiting macOS verification on native embed scenarios."
}),
new ProjectCardViewModel(
"Docs Refresh",
"Anika Patel",
"Needs Review",
"Refresh navigation samples and walkthrough docs so the gallery matches the current API.",
"Sample review tomorrow",
Color.Parse("#8E562E"),
navigationService,
new[]
{
"NavigationPage sample matrix reviewed with design.",
"MVVM walkthrough draft linked from the docs backlog.",
"Outstanding task, capture one more screenshot for drawer navigation."
}),
};
}
internal sealed class WorkspaceViewModel : ViewModelBase
{
public WorkspaceViewModel(IReadOnlyList<ProjectCardViewModel> projects)
{
Projects = projects;
}
public string Title => "Team Workspace";
public string Description =>
"Each card is a project view model with its own command. The command asks ISampleNavigationService to navigate with the next view model, and SamplePageFactory resolves the matching ContentPage.";
public IReadOnlyList<ProjectCardViewModel> Projects { get; }
}
public sealed class ProjectCardViewModel : ViewModelBase
{
private readonly ISampleNavigationService _navigationService;
internal ProjectCardViewModel(
string name,
string owner,
string status,
string summary,
string nextMilestone,
Color accentColor,
ISampleNavigationService navigationService,
IReadOnlyList<string> activityItems)
{
Name = name;
Owner = owner;
Status = status;
Summary = summary;
NextMilestone = nextMilestone;
AccentColor = accentColor;
ActivityItems = activityItems;
_navigationService = navigationService;
OpenCommand = MiniCommand.CreateFromTask(OpenCommandAsync);
}
public string Name { get; }
public string Owner { get; }
public string Status { get; }
public string Summary { get; }
public string NextMilestone { get; }
public Color AccentColor { get; }
public IReadOnlyList<string> ActivityItems { get; }
public MiniCommand OpenCommand { get; }
public Task OpenCommandAsync()
{
return _navigationService.NavigateToAsync(new ProjectDetailViewModel(this, _navigationService));
}
}
internal sealed class ProjectDetailViewModel : ViewModelBase
{
private readonly ProjectCardViewModel _project;
private readonly ISampleNavigationService _navigationService;
public ProjectDetailViewModel(ProjectCardViewModel project, ISampleNavigationService navigationService)
{
_project = project;
_navigationService = navigationService;
OpenActivityCommand = MiniCommand.CreateFromTask(OpenActivityAsync);
}
public string Name => _project.Name;
public string Owner => _project.Owner;
public string Status => _project.Status;
public string Summary => _project.Summary;
public string NextMilestone => _project.NextMilestone;
public Color AccentColor => _project.AccentColor;
public MiniCommand OpenActivityCommand { get; }
private Task OpenActivityAsync()
{
return _navigationService.NavigateToAsync(new ProjectActivityViewModel(_project));
}
}
internal sealed class ProjectActivityViewModel : ViewModelBase
{
public ProjectActivityViewModel(ProjectCardViewModel project)
{
Name = project.Name;
AccentColor = project.AccentColor;
Items = project.ActivityItems;
}
public string Name { get; }
public Color AccentColor { get; }
public IReadOnlyList<string> Items { get; }
}
}

6
samples/ControlCatalog/Pages/NavigationPage/NavigationPagePassDataPage.xaml.cs

@ -19,6 +19,7 @@ namespace ControlCatalog.Pages
new("Emma Brown", "UX Researcher", "Germany", Color.Parse("#F44336")),
};
private bool _initialized;
private bool _isLoaded;
public NavigationPagePassDataPage()
@ -31,6 +32,11 @@ namespace ControlCatalog.Pages
{
_isLoaded = true;
if (_initialized)
return;
_initialized = true;
DemoNav.Pushed += (s, ev) => AppendNavigationLog($"Pushed → {ev.Page?.Header}");
DemoNav.Popped += (s, ev) => AppendNavigationLog($"Popped ← {ev.Page?.Header}");

24
samples/ControlCatalog/Pages/NavigationPage/NavigationPageScrollAwarePage.xaml.cs

@ -21,8 +21,10 @@ namespace ControlCatalog.Pages
}
private IDisposable? _scrollSubscription;
private ScrollViewer? _scrollViewer;
private double _lastScrollY;
private double _currentTranslateY;
private bool _initialized;
public NavigationPageScrollAwarePage()
{
@ -33,12 +35,21 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
var scrollViewer = new ScrollViewer { Content = BuildLongContent() };
if (_initialized)
{
if (_scrollViewer != null)
Dispatcher.UIThread.Post(() => AttachScrollWatcher(_scrollViewer), DispatcherPriority.Loaded);
return;
}
_initialized = true;
_scrollViewer = new ScrollViewer { Content = BuildLongContent() };
var rootPage = new ContentPage
{
Header = "Scroll to Hide Bar",
Content = scrollViewer,
Content = _scrollViewer,
HorizontalContentAlignment = HorizontalAlignment.Stretch,
VerticalContentAlignment = VerticalAlignment.Stretch,
};
@ -46,13 +57,18 @@ namespace ControlCatalog.Pages
NavigationPage.SetBarLayoutBehavior(rootPage, BarLayoutBehavior.Overlay);
await DemoNav.PushAsync(rootPage, null);
Dispatcher.UIThread.Post(() => AttachScrollWatcher(scrollViewer), DispatcherPriority.Loaded);
Dispatcher.UIThread.Post(() => AttachScrollWatcher(_scrollViewer), DispatcherPriority.Loaded);
}
private void OnUnloaded(object? sender, RoutedEventArgs e) => DetachScrollWatcher();
private void AttachScrollWatcher(ScrollViewer sv)
private void AttachScrollWatcher(ScrollViewer? sv)
{
if (sv == null)
return;
DetachScrollWatcher();
var navBar = DemoNav.GetVisualDescendants().OfType<Border>()
.FirstOrDefault(b => b.Name == "PART_NavigationBar");
if (navBar == null)

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageStackPage.xaml.cs

@ -9,6 +9,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageStackPage : UserControl
{
private bool _initialized;
private int _pageCount;
public NavigationPageStackPage()
@ -19,6 +20,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
DemoNav.Pushed += (s, ev) => RefreshStack();
DemoNav.Popped += (s, ev) => RefreshStack();
DemoNav.PoppedToRoot += (s, ev) => RefreshStack();

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageTitlePage.xaml.cs

@ -8,6 +8,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageTitlePage : UserControl
{
private bool _initialized;
private int _pageCount;
public NavigationPageTitlePage()
@ -18,6 +19,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Home", "Choose a header type and tap 'Push'.", 0), null);
StatusText.Text = "Current: Home";
}

5
samples/ControlCatalog/Pages/NavigationPage/NavigationPageToolbarPage.xaml.cs

@ -7,6 +7,7 @@ namespace ControlCatalog.Pages
{
public partial class NavigationPageToolbarPage : UserControl
{
private bool _initialized;
private int _pageCount;
private int _itemCount;
private ContentPage? _rootPage;
@ -20,6 +21,10 @@ namespace ControlCatalog.Pages
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
if (_initialized)
return;
_initialized = true;
_rootPage = NavigationDemoHelper.MakePage("CommandBar Demo",
"Use the panel to add CommandBar items.\nTop items appear inside the navigation bar.\nBottom items appear as a separate bar.", 0);
ApplyPosition();

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

Loading…
Cancel
Save