├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── .vscode
├── launch.json
├── settings.json
└── tasks.json
├── CODE_OF_CONDUCT.md
├── Directory.Build.props
├── Directory.Build.targets
├── HotAvalonia.sln
├── LICENSE.md
├── README.md
├── global.json
├── media
├── examples
│ ├── hot_reload_app.gif
│ ├── hot_reload_resources.gif
│ ├── hot_reload_styles.gif
│ ├── hot_reload_user_control.gif
│ ├── hot_reload_view.gif
│ └── hot_reload_window.gif
└── icon.png
├── samples
├── Directory.Build.targets
├── HotReloadDemo.Android
│ ├── HotReloadDemo.Android.csproj
│ ├── MainActivity.cs
│ ├── Properties
│ │ └── AndroidManifest.xml
│ └── Resources
│ │ ├── drawable-night-v31
│ │ └── avalonia_anim.xml
│ │ ├── drawable-v31
│ │ └── avalonia_anim.xml
│ │ ├── drawable
│ │ └── splash_screen.xml
│ │ ├── values-night
│ │ └── colors.xml
│ │ ├── values-v31
│ │ └── styles.xml
│ │ └── values
│ │ ├── colors.xml
│ │ └── styles.xml
├── HotReloadDemo.Desktop
│ ├── HotReloadDemo.Desktop.csproj
│ ├── Program.cs
│ └── app.manifest
└── HotReloadDemo
│ ├── App.axaml
│ ├── App.axaml.cs
│ ├── Assets
│ └── icon.ico
│ ├── Controls
│ ├── ToDoItemControl.axaml
│ └── ToDoItemControl.axaml.cs
│ ├── Converters
│ └── TitleCaseConverter.cs
│ ├── HotReloadDemo.csproj
│ ├── Models
│ └── ToDoItem.cs
│ ├── Resources
│ └── AppResources.axaml
│ ├── Services
│ ├── FakeToDoItemProvider.cs
│ └── IToDoItemProvider.cs
│ ├── Styles
│ └── AppStyles.axaml
│ ├── ViewLocator.cs
│ ├── ViewModels
│ ├── AddItemViewModel.cs
│ ├── MainViewModel.cs
│ ├── ToDoListViewModel.cs
│ └── ViewModelBase.cs
│ └── Views
│ ├── AddItemView.axaml
│ ├── AddItemView.axaml.cs
│ ├── MainView.axaml
│ ├── MainView.axaml.cs
│ ├── MainWindow.axaml
│ ├── MainWindow.axaml.cs
│ ├── ToDoListView.axaml
│ └── ToDoListView.axaml.cs
└── src
├── HotAvalonia.Core
├── Assets
│ ├── AssetInfo.cs
│ ├── DynamicAsset.cs
│ ├── DynamicAssetLoader.cs
│ └── DynamicAssetTypeConverter.cs
├── AvaloniaAssetManager.cs
├── AvaloniaControlManager.cs
├── AvaloniaHotReload.cs
├── AvaloniaHotReloadContext.cs
├── AvaloniaProjectLocator.cs
├── BannedSymbols.txt
├── Collections
│ ├── MemoryCache.cs
│ └── WeakSet.cs
├── Compat
│ └── System
│ │ ├── BitConverter.cs
│ │ └── IO
│ │ └── StreamCompatExtensions.cs
├── DependencyInjection
│ └── AvaloniaServiceProvider.cs
├── Helpers
│ ├── AssemblyHelper.cs
│ ├── ILGeneratorHelper.cs
│ ├── LoggingHelper.cs
│ ├── MethodHelper.cs
│ ├── OpCodeHelper.cs
│ ├── StopwatchHelper.cs
│ ├── TypeHelper.cs
│ └── UriHelper.cs
├── HotAvalonia.Core.csproj
├── HotReloadFeatures.cs
├── IHotReloadContext.cs
├── IO
│ ├── CachingFileSystem.cs
│ ├── EmptyFileSystem.cs
│ ├── EmptyFileSystemWatcher.cs
│ ├── FileObserver.cs
│ ├── FileSystem.cs
│ ├── FileSystemState.cs
│ ├── FileWatcher.cs
│ ├── IFileSystem.cs
│ ├── IFileSystemWatcher.cs
│ ├── LocalFileSystem.cs
│ ├── LocalFileSystemWatcher.cs
│ ├── RemoteFileSystem.Shared.cs
│ ├── RemoteFileSystem.cs
│ ├── RemoteFileSystemException.cs
│ ├── RemoteFileSystemWatcher.Shared.cs
│ └── RemoteFileSystemWatcher.cs
├── Net
│ └── SslTcpClient.cs
├── README.md
├── Reflection
│ ├── DynamicAssembly.cs
│ ├── Inject
│ │ ├── CallbackInjector.cs
│ │ ├── CallbackParameterType.cs
│ │ ├── CallbackResultAttribute.cs
│ │ ├── CallerAttribute.cs
│ │ ├── CallerMemberAttribute.cs
│ │ ├── IInjection.cs
│ │ ├── InjectionType.cs
│ │ └── MethodInjector.cs
│ └── MethodBodyReader.cs
└── Xaml
│ ├── CompileXamlFunc.cs
│ ├── CompiledXamlDocument.cs
│ ├── DynamicSreAssembly.cs
│ ├── NamedControlReference.cs
│ ├── XamlCompiler.cs
│ ├── XamlDocument.cs
│ ├── XamlPatcher.cs
│ └── XamlScanner.cs
├── HotAvalonia.Extensions
├── AvaloniaHotReloadExtensions.cs
├── AvaloniaHotReloadExtensions.fs
├── AvaloniaHotReloadExtensions.vb
├── HotAvalonia.Extensions.csproj
├── HotAvalonia.Extensions.props
└── README.md
├── HotAvalonia.Fody
├── Cecil
│ ├── CecilField.cs
│ ├── CecilMethod.cs
│ ├── CecilProperty.cs
│ ├── CecilType.cs
│ ├── ITypeResolver.cs
│ ├── TypeName.cs
│ └── WeakType.cs
├── FeatureWeaver.cs
├── FileSystemCredentialsWeaver.cs
├── Helpers
│ ├── MethodReferenceHelper.cs
│ ├── ModuleReferenceHelper.cs
│ ├── StringHelper.cs
│ └── TypeReferenceHelper.cs
├── HotAvalonia.Fody.csproj
├── HotAvalonia.Fody.props
├── MSBuild
│ ├── MSBuildFile.cs
│ ├── MSBuildProject.cs
│ └── MSBuildSolution.cs
├── ModuleWeaver.cs
├── PopulateOverrideWeaver.cs
├── README.md
├── ReferencesWeaver.cs
├── Reflection
│ └── BindingFlag.cs
├── UnreferencedTypes.cs
└── UseHotReloadWeaver.cs
├── HotAvalonia.Remote
├── HotAvalonia.Remote.csproj
├── IO
│ ├── RemoteFileSystem.cs
│ ├── RemoteFileSystemClient.cs
│ └── RemoteFileSystemWatcher.cs
├── Net
│ └── SslTcpListener.cs
├── Program.cs
└── README.md
└── HotAvalonia
├── FileSystemServerConfig.cs
├── GenerateFileSystemServerConfigTask.cs
├── GetFileSystemClientConfigTask.cs
├── Helpers
└── NetworkHelper.cs
├── HotAvalonia.csproj
├── HotAvalonia.props
├── HotAvalonia.targets
├── MSBuildTask.cs
└── StartFileSystemServerTask.cs
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - development
8 | pull_request:
9 | workflow_dispatch:
10 |
11 | env:
12 | DOTNET_CLI_TELEMETRY_OPTOUT: true
13 | DOTNET_NOLOGO: true
14 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
15 | DOTNET_GENERATE_ASPNET_CERTIFICATE: false
16 | DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: true
17 | NUGET_XMLDOC_MODE: skip
18 | BUILD_OUTPUT: ${{ github.workspace }}/dist
19 |
20 | jobs:
21 | build:
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@v4
25 |
26 | - name: Setup .NET SDK
27 | uses: actions/setup-dotnet@v4
28 |
29 | - name: Build (Debug)
30 | run: dotnet build -tl -c Debug
31 |
32 | - name: Build (Release)
33 | run: dotnet build -tl -c Release
34 |
35 | - name: Run tests
36 | run: dotnet test -tl -c Release --no-build
37 |
38 | - name: Create NuGet packages
39 | run: dotnet pack -tl -c Release --no-build -o "${{ env.BUILD_OUTPUT }}"
40 |
41 | - name: Upload build artifacts
42 | uses: actions/upload-artifact@v4
43 | with:
44 | name: build
45 | if-no-files-found: error
46 | path: ${{ env.BUILD_OUTPUT }}/*.nupkg
47 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: release
2 |
3 | on:
4 | release:
5 | types:
6 | - published
7 |
8 | env:
9 | DOTNET_CLI_TELEMETRY_OPTOUT: true
10 | DOTNET_NOLOGO: true
11 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
12 | DOTNET_GENERATE_ASPNET_CERTIFICATE: false
13 | DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: true
14 | NUGET_XMLDOC_MODE: skip
15 | BUILD_OUTPUT: ${{ github.workspace }}/dist
16 |
17 | jobs:
18 | build:
19 | runs-on: ubuntu-latest
20 | permissions:
21 | contents: write
22 | steps:
23 | - uses: actions/checkout@v4
24 |
25 | - name: Setup .NET SDK
26 | uses: actions/setup-dotnet@v4
27 |
28 | - name: Build (Debug)
29 | run: dotnet build -tl -c Debug
30 |
31 | - name: Build (Release)
32 | run: dotnet build -tl -c Release
33 |
34 | - name: Run tests
35 | run: dotnet test -tl -c Release --no-build
36 |
37 | - name: Create NuGet packages
38 | run: dotnet pack -tl -c Release --no-build -o "${{ env.BUILD_OUTPUT }}"
39 |
40 | - name: Upload NuGets to GitHub
41 | uses: Kira-NT/mc-publish@v3.3
42 | with:
43 | files: ${{ env.BUILD_OUTPUT }}/*.nupkg
44 | github-token: ${{ secrets.GITHUB_TOKEN }}
45 |
46 | - name: Upload NuGets to NuGet.org
47 | run: dotnet nuget push "${{ env.BUILD_OUTPUT }}/*.nupkg" --api-key "${{ secrets.NUGET_TOKEN }}" --source "https://api.nuget.org/v3/index.json" --skip-duplicate
48 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": ".NET Launch (Demo)",
6 | "type": "coreclr",
7 | "request": "launch",
8 | "preLaunchTask": "build",
9 | "program": "${workspaceFolder}/samples/HotReloadDemo.Desktop/bin/Debug/net9.0/HotReloadDemo.Desktop.dll",
10 | "env": {
11 | "HOTAVALONIA_STATICRESOURCEPATCHER": "true",
12 | "HOTAVALONIA_MERGERESOURCEINCLUDEPATCHER": "true",
13 | "HOTAVALONIA_SKIP_INITIAL_PATCHING": "false",
14 | "HOTAVALONIA_DISABLE_INJECTIONS": "false",
15 | "HOTAVALONIA_LOG_LEVEL_OVERRIDE": "error",
16 | },
17 | "args": [],
18 | "cwd": "${workspaceFolder}/samples/HotReloadDemo.Desktop",
19 | "console": "internalConsole",
20 | "stopAtEntry": false,
21 | "logging": {
22 | "moduleLoad": false,
23 | }
24 | },
25 | {
26 | "name": ".NET Launch (Android Demo)",
27 | "type": "coreclr",
28 | "request": "launch",
29 | "preLaunchTask": "build",
30 | "program": "dotnet",
31 | "args": [
32 | "build",
33 | "${workspaceFolder}/samples/HotReloadDemo.Android",
34 | "/property:Configuration=Debug",
35 | "/property:GenerateFullPaths=true",
36 | "/consoleloggerparameters:NoSummary",
37 | "/property:AndroidSdkDirectory=${input:androidSdkDir}",
38 | "/property:JavaSdkDirectory=${input:javaSdkDir}",
39 | "/t:Run",
40 | ],
41 | "cwd": "${workspaceFolder}",
42 | "console": "integratedTerminal",
43 | },
44 | {
45 | "name": ".NET Attach",
46 | "type": "coreclr",
47 | "request": "attach",
48 | },
49 | ],
50 | "inputs": [
51 | {
52 | "id": "androidSdkDir",
53 | "type": "promptString",
54 | "description": "Enter Android SDK Directory",
55 | "default": "${env:HOME}/.android",
56 | },
57 | {
58 | "id": "javaSdkDir",
59 | "type": "promptString",
60 | "description": "Enter Java SDK Directory",
61 | "default": "${env:HOME}/.android/java",
62 | },
63 | ],
64 | }
65 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dotnet.defaultSolution": "HotAvalonia.sln",
3 | }
4 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/HotAvalonia.sln",
11 | "/property:Configuration=Debug",
12 | "/property:GenerateFullPaths=true",
13 | "/consoleloggerparameters:NoSummary",
14 | "-tl",
15 | ],
16 | "problemMatcher": "$msCompile",
17 | },
18 | {
19 | "label": "prepare-android-environment",
20 | "dependsOrder": "sequence",
21 | "dependsOn": [
22 | "workload-install-android",
23 | "install-android-sdk",
24 | ],
25 | },
26 | {
27 | "label": "workload-install-android",
28 | "type": "process",
29 | "command": "dotnet",
30 | "args": [
31 | "workload",
32 | "install",
33 | "android",
34 | ],
35 | "problemMatcher": "$msCompile",
36 | },
37 | {
38 | "label": "install-android-sdk",
39 | "type": "process",
40 | "command": "dotnet",
41 | "args": [
42 | "build",
43 | "${workspaceFolder}/samples/HotReloadDemo.Android",
44 | "/property:AndroidSdkDirectory=${input:androidSdkDir}",
45 | "/property:JavaSdkDirectory=${input:javaSdkDir}",
46 | "/property:AcceptAndroidSdkLicenses=True",
47 | "/t:InstallAndroidDependencies",
48 | ],
49 | "problemMatcher": "$msCompile",
50 | },
51 | {
52 | "label": "start-android-emulator",
53 | "type": "shell",
54 | "command": "${input:androidSdkDir}/emulator/emulator -avd ${input:androidEmulatorName} -partition-size 512",
55 | "windows": {
56 | "command": "${input:androidSdkDir}/emulator/emulator.exe -avd ${input:androidEmulatorName} -partition-size 512",
57 | },
58 | "problemMatcher": [],
59 | "isBackground": true,
60 | "presentation": {
61 | "echo": false,
62 | "reveal": "never",
63 | "focus": false,
64 | "panel": "shared",
65 | "showReuseMessage": false,
66 | "clear": true,
67 | }
68 | }
69 | ],
70 | "inputs": [
71 | {
72 | "id": "androidSdkDir",
73 | "type": "promptString",
74 | "description": "Enter Android SDK Directory",
75 | "default": "${env:HOME}/.android",
76 | },
77 | {
78 | "id": "javaSdkDir",
79 | "type": "promptString",
80 | "description": "Enter Java SDK Directory",
81 | "default": "${env:HOME}/.android/java",
82 | },
83 | {
84 | "id": "androidEmulatorName",
85 | "type": "promptString",
86 | "description": "Enter the name of your Android emulator",
87 | "default": "Pixel",
88 | },
89 | ],
90 | }
91 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, caste, color, religion, or sexual
10 | identity and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the overall
26 | community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or advances of
31 | any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email address,
35 | without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | [kira.canary@proton.me](mailto:kira.canary@proton.me).
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series of
86 | actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or permanent
93 | ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within the
113 | community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.1, available at
119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120 |
121 | Community Impact Guidelines were inspired by
122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123 |
124 | For answers to common questions about this code of conduct, see the FAQ at
125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126 | [https://www.contributor-covenant.org/translations][translations].
127 |
128 | [homepage]: https://www.contributor-covenant.org
129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130 | [Mozilla CoC]: https://github.com/mozilla/diversity
131 | [FAQ]: https://www.contributor-covenant.org/faq
132 | [translations]: https://www.contributor-covenant.org/translations
133 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 | enable
6 | true
7 | preview
8 | true
9 | false
10 | $(DefineConstants)$(FeatureFlags.Replace("#",";"))
11 |
12 |
13 |
14 | 3.0.0
15 | Kira-NT
16 | 2023
17 | true
18 | avalonia avaloniaui hot-reload dynamic hot reload xaml axaml ui development tools net netstandard
19 |
20 |
21 |
22 | 11.0.0
23 | 6.9.2
24 |
25 |
26 |
27 | false
28 | $(Author)
29 | $(Author)
30 | Copyright © $(ReleaseYear)-$([System.DateTime]::Now.Year) $(Authors)
31 | Copyright © $(ReleaseYear) $(Authors)
32 | $([System.IO.Path]::GetFileNameWithoutExtension('$([System.IO.Directory]::GetFiles(`$(MSBuildThisFileDirectory)`, `*.sln`)[0])'))
33 | https://github.com/$(Author)/$(ProjectName)
34 | git
35 | $(RepositoryUrl)
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(DefineConstants);NATIVE_AOT
5 |
6 |
7 |
8 | $(Version)-build.$(GITHUB_RUN_NUMBER)
9 |
10 |
11 |
12 | README.md
13 | LICENSE.md
14 | icon.png
15 | false
16 | true
17 | true
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/HotAvalonia.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio Version 17
3 | VisualStudioVersion = 17.0.31903.59
4 | MinimumVisualStudioVersion = 10.0.40219.1
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotAvalonia", "src/HotAvalonia/HotAvalonia.csproj", "{8434892B-7F24-441A-9623-D1E387F0C992}"
6 | EndProject
7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotAvalonia.Core", "src/HotAvalonia.Core/HotAvalonia.Core.csproj", "{4DC5A913-2573-47FE-8434-0F7D030B2116}"
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotAvalonia.Extensions", "src/HotAvalonia.Extensions/HotAvalonia.Extensions.csproj", "{B196D2B3-DCDE-48A2-B783-590E19B396C4}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotAvalonia.Fody", "src/HotAvalonia.Fody/HotAvalonia.Fody.csproj", "{4D3AC651-616F-4FCC-9285-45A824A95F94}"
12 | EndProject
13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotAvalonia.Remote", "src/HotAvalonia.Remote/HotAvalonia.Remote.csproj", "{F5BF4495-B20F-4828-893D-464B08C3ACF0}"
14 | EndProject
15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotReloadDemo", "samples/HotReloadDemo/HotReloadDemo.csproj", "{692200A4-8EDB-493C-A2D2-B10CDE68DA0B}"
16 | EndProject
17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotReloadDemo.Desktop", "samples/HotReloadDemo.Desktop/HotReloadDemo.Desktop.csproj", "{347F6CC8-192B-4BF2-AC25-BB9A3B045F95}"
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Debug|Any CPU = Debug|Any CPU
22 | Release|Any CPU = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(SolutionProperties) = preSolution
25 | HideSolutionNode = FALSE
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {8434892B-7F24-441A-9623-D1E387F0C992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {8434892B-7F24-441A-9623-D1E387F0C992}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {8434892B-7F24-441A-9623-D1E387F0C992}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {8434892B-7F24-441A-9623-D1E387F0C992}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {4DC5A913-2573-47FE-8434-0F7D030B2116}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {4DC5A913-2573-47FE-8434-0F7D030B2116}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {4DC5A913-2573-47FE-8434-0F7D030B2116}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {4DC5A913-2573-47FE-8434-0F7D030B2116}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {B196D2B3-DCDE-48A2-B783-590E19B396C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {B196D2B3-DCDE-48A2-B783-590E19B396C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {B196D2B3-DCDE-48A2-B783-590E19B396C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {B196D2B3-DCDE-48A2-B783-590E19B396C4}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {4D3AC651-616F-4FCC-9285-45A824A95F94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {4D3AC651-616F-4FCC-9285-45A824A95F94}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {4D3AC651-616F-4FCC-9285-45A824A95F94}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {4D3AC651-616F-4FCC-9285-45A824A95F94}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {F5BF4495-B20F-4828-893D-464B08C3ACF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {F5BF4495-B20F-4828-893D-464B08C3ACF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {F5BF4495-B20F-4828-893D-464B08C3ACF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {F5BF4495-B20F-4828-893D-464B08C3ACF0}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {692200A4-8EDB-493C-A2D2-B10CDE68DA0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {692200A4-8EDB-493C-A2D2-B10CDE68DA0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {692200A4-8EDB-493C-A2D2-B10CDE68DA0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {692200A4-8EDB-493C-A2D2-B10CDE68DA0B}.Release|Any CPU.Build.0 = Release|Any CPU
52 | {347F6CC8-192B-4BF2-AC25-BB9A3B045F95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53 | {347F6CC8-192B-4BF2-AC25-BB9A3B045F95}.Debug|Any CPU.Build.0 = Debug|Any CPU
54 | {347F6CC8-192B-4BF2-AC25-BB9A3B045F95}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {347F6CC8-192B-4BF2-AC25-BB9A3B045F95}.Release|Any CPU.Build.0 = Release|Any CPU
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023-2025 Kira NT
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.100",
4 | "rollForward": "latestMinor",
5 | "allowPrerelease": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/media/examples/hot_reload_app.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/media/examples/hot_reload_app.gif
--------------------------------------------------------------------------------
/media/examples/hot_reload_resources.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/media/examples/hot_reload_resources.gif
--------------------------------------------------------------------------------
/media/examples/hot_reload_styles.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/media/examples/hot_reload_styles.gif
--------------------------------------------------------------------------------
/media/examples/hot_reload_user_control.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/media/examples/hot_reload_user_control.gif
--------------------------------------------------------------------------------
/media/examples/hot_reload_view.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/media/examples/hot_reload_view.gif
--------------------------------------------------------------------------------
/media/examples/hot_reload_window.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/media/examples/hot_reload_window.gif
--------------------------------------------------------------------------------
/media/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/media/icon.png
--------------------------------------------------------------------------------
/samples/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
13 | <_HotAvaloniaHarfsFile>$(MSBuildThisFileDirectory)../src/HotAvalonia.Remote/bin/$(Configuration)/net7.0/HotAvalonia.Remote.dll
14 | <_HotAvaloniaAssemblyFile>$(MSBuildThisFileDirectory)../src/HotAvalonia/bin/$(Configuration)/netstandard2.0/HotAvalonia.dll
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/HotReloadDemo.Android.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0-android
6 | 21
7 | apk
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/MainActivity.cs:
--------------------------------------------------------------------------------
1 | using Android.Content.PM;
2 | using Avalonia;
3 | using Avalonia.Android;
4 |
5 | namespace HotReloadDemo.Android;
6 |
7 | [Activity(
8 | Label = "HotReloadDemo.Android",
9 | Theme = "@style/HotReloadDemoTheme.NoActionBar",
10 | Icon = "@drawable/icon",
11 | MainLauncher = true,
12 | ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
13 | public class MainActivity : AvaloniaMainActivity
14 | {
15 | protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
16 | => base.CustomizeAppBuilder(builder)
17 | .LogToTrace()
18 | .WithInterFont();
19 | }
20 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Resources/drawable-night-v31/avalonia_anim.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
15 |
16 |
20 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
42 |
43 |
44 |
45 |
46 |
53 |
54 |
55 |
56 |
57 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Resources/drawable-v31/avalonia_anim.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
15 |
16 |
21 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
59 |
60 |
61 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Resources/drawable/splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Resources/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #212121
4 |
5 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Resources/values-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
15 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
5 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Android/Resources/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Desktop/HotReloadDemo.Desktop.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net9.0
6 | app.manifest
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Desktop/Program.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.ReactiveUI;
3 |
4 | namespace HotReloadDemo.Desktop;
5 |
6 | static class Program
7 | {
8 | [STAThread]
9 | public static void Main(string[] args) => BuildAvaloniaApp()
10 | .StartWithClassicDesktopLifetime(args);
11 |
12 | public static AppBuilder BuildAvaloniaApp()
13 | => AppBuilder.Configure()
14 | .UsePlatformDetect()
15 | .WithInterFont()
16 | .LogToTrace()
17 | .UseReactiveUI();
18 | }
19 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo.Desktop/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/App.axaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 | using HotReloadDemo.ViewModels;
5 | using HotReloadDemo.Views;
6 |
7 | namespace HotReloadDemo;
8 |
9 | public partial class App : Application
10 | {
11 | public override void Initialize() => AvaloniaXamlLoader.Load(this);
12 |
13 | public override void OnFrameworkInitializationCompleted()
14 | {
15 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
16 | {
17 | desktop.MainWindow = new MainWindow
18 | {
19 | DataContext = new MainViewModel(),
20 | };
21 | }
22 | else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
23 | {
24 | singleViewPlatform.MainView = new MainView
25 | {
26 | DataContext = new MainViewModel(),
27 | };
28 | }
29 |
30 | base.OnFrameworkInitializationCompleted();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Assets/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kira-NT/HotAvalonia/9e4983a3faa6b0e29af106522dc3bfe9e62c51bb/samples/HotReloadDemo/Assets/icon.ico
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Controls/ToDoItemControl.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Controls/ToDoItemControl.axaml.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using Avalonia.Controls;
3 | using Avalonia.Interactivity;
4 | using HotAvalonia;
5 |
6 | namespace HotReloadDemo.Controls;
7 |
8 | internal sealed partial class ToDoItemControl : UserControl
9 | {
10 | public ToDoItemControl()
11 | {
12 | InitializeComponent();
13 | Initialize();
14 | }
15 |
16 | [AvaloniaHotReload]
17 | private void Initialize()
18 | {
19 | // Let's pretend that we did something very important here.
20 | int hashCode = GetHashCode();
21 | Debug.WriteLine("Initializing {0}#{1}...", this, hashCode);
22 | }
23 |
24 | private void CheckBox_Click(object? sender, RoutedEventArgs e)
25 | {
26 | int hashCode = GetHashCode();
27 | Debug.WriteLine("Clicked {0}#{1}", this, hashCode);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Converters/TitleCaseConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data;
3 | using Avalonia.Data.Converters;
4 |
5 | namespace HotReloadDemo.Converters;
6 |
7 | ///
8 | /// Represents a converter that converts the first character of a string to its uppercase equivalent.
9 | ///
10 | public sealed class TitleCaseConverter : IValueConverter
11 | {
12 | ///
13 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
14 | {
15 | if (value is not string text || !targetType.IsAssignableFrom(typeof(string)))
16 | return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
17 |
18 | return string.IsNullOrEmpty(text) ? text : (char.ToUpper(text[0]) + text.Substring(1));
19 | }
20 |
21 | ///
22 | object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
23 | => throw new NotSupportedException();
24 | }
25 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/HotReloadDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Models/ToDoItem.cs:
--------------------------------------------------------------------------------
1 | namespace HotReloadDemo.Models;
2 |
3 | public class ToDoItem
4 | {
5 | public string Description { get; set; } = string.Empty;
6 |
7 | public bool IsChecked { get; set; }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Resources/AppResources.axaml:
--------------------------------------------------------------------------------
1 |
4 |
5 | Enter your todo item
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Services/FakeToDoItemProvider.cs:
--------------------------------------------------------------------------------
1 | using HotReloadDemo.Models;
2 |
3 | namespace HotReloadDemo.Services;
4 |
5 | public sealed class FakeToDoItemProvider : IToDoItemProvider
6 | {
7 | public IEnumerable GetItems() => new[]
8 | {
9 | new ToDoItem { Description = "walk the dog" },
10 | new ToDoItem { Description = "buy some milk" },
11 | new ToDoItem { Description = "learn Avalonia", IsChecked = true },
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Services/IToDoItemProvider.cs:
--------------------------------------------------------------------------------
1 | using HotReloadDemo.Models;
2 |
3 | namespace HotReloadDemo.Services;
4 |
5 | public interface IToDoItemProvider
6 | {
7 | IEnumerable GetItems();
8 | }
9 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Styles/AppStyles.axaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/ViewLocator.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Controls.Templates;
3 | using HotReloadDemo.ViewModels;
4 |
5 | namespace HotReloadDemo;
6 |
7 | public class ViewLocator : IDataTemplate
8 | {
9 | public Control? Build(object? data)
10 | {
11 | string? name = data?.GetType().FullName?.Replace("ViewModel", "View");
12 | Type? type = name is null ? null : Type.GetType(name);
13 |
14 | if (type is not null)
15 | return (Control?)Activator.CreateInstance(type);
16 |
17 | return new TextBlock { Text = "Not Found: " + name };
18 | }
19 |
20 | public bool Match(object? data) => data is ViewModelBase;
21 | }
22 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/ViewModels/AddItemViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive;
2 | using HotReloadDemo.Models;
3 | using ReactiveUI;
4 |
5 | namespace HotReloadDemo.ViewModels;
6 |
7 | public class AddItemViewModel : ViewModelBase
8 | {
9 | private string _description = string.Empty;
10 |
11 | public AddItemViewModel()
12 | {
13 | IObservable isValidObservable = this.WhenAnyValue(
14 | x => x.Description,
15 | x => !string.IsNullOrWhiteSpace(x));
16 |
17 | OkCommand = ReactiveCommand.Create(() => new ToDoItem { Description = Description }, isValidObservable);
18 | CancelCommand = ReactiveCommand.Create(() => { });
19 | }
20 |
21 | public string Description
22 | {
23 | get => _description;
24 | set => this.RaiseAndSetIfChanged(ref _description, value);
25 | }
26 |
27 | public ReactiveCommand OkCommand { get; }
28 |
29 | public ReactiveCommand CancelCommand { get; }
30 | }
31 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/ViewModels/MainViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive;
2 | using System.Reactive.Linq;
3 | using HotReloadDemo.Models;
4 | using HotReloadDemo.Services;
5 | using ReactiveUI;
6 |
7 | namespace HotReloadDemo.ViewModels;
8 |
9 | public class MainViewModel : ViewModelBase
10 | {
11 | private object _content;
12 |
13 | public MainViewModel()
14 | : this(new FakeToDoItemProvider())
15 | {
16 | }
17 |
18 | public MainViewModel(IToDoItemProvider provider)
19 | {
20 | ToDoList = new(provider.GetItems());
21 | _content = ToDoList;
22 | }
23 |
24 | public ToDoListViewModel ToDoList { get; }
25 |
26 | public object Content
27 | {
28 | get => _content;
29 | private set => this.RaiseAndSetIfChanged(ref _content, value);
30 | }
31 |
32 | public void AddItem()
33 | {
34 | AddItemViewModel addItemViewModel = new();
35 |
36 | Observable.Merge(
37 | addItemViewModel.OkCommand,
38 | addItemViewModel.CancelCommand.Select(_ => default(ToDoItem)))
39 | .Take(1)
40 | .Subscribe(Observer.Create(newItem =>
41 | {
42 | if (newItem is not null)
43 | ToDoList.ToDoItems.Add(newItem);
44 |
45 | Content = ToDoList;
46 | }));
47 |
48 | Content = addItemViewModel;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/ViewModels/ToDoListViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using HotReloadDemo.Models;
3 |
4 | namespace HotReloadDemo.ViewModels;
5 |
6 | public class ToDoListViewModel : ViewModelBase
7 | {
8 | public ObservableCollection ToDoItems { get; }
9 |
10 | public ToDoListViewModel(IEnumerable items)
11 | {
12 | ArgumentNullException.ThrowIfNull(items);
13 |
14 | ToDoItems = new(items);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/ViewModels/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 |
3 | namespace HotReloadDemo.ViewModels;
4 |
5 | public class ViewModelBase : ReactiveObject
6 | {
7 | }
8 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/AddItemView.axaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
20 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/AddItemView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 |
3 | namespace HotReloadDemo.Views;
4 |
5 | public partial class AddItemView : UserControl
6 | {
7 | public AddItemView() => InitializeComponent();
8 | }
9 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/MainView.axaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/MainView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 |
3 | namespace HotReloadDemo.Views;
4 |
5 | public partial class MainView : UserControl
6 | {
7 | public MainView() => InitializeComponent();
8 | }
9 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/MainWindow.axaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 |
3 | namespace HotReloadDemo.Views;
4 |
5 | public partial class MainWindow : Window
6 | {
7 | public MainWindow() => InitializeComponent();
8 | }
9 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/ToDoListView.axaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/samples/HotReloadDemo/Views/ToDoListView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 |
3 | namespace HotReloadDemo.Views;
4 |
5 | public partial class ToDoListView : UserControl
6 | {
7 | public ToDoListView() => InitializeComponent();
8 | }
9 |
--------------------------------------------------------------------------------
/src/HotAvalonia.Core/Assets/AssetInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace HotAvalonia.Assets;
4 |
5 | ///
6 | /// Represents metadata about an Avalonia asset.
7 | ///
8 | internal class AssetInfo
9 | {
10 | ///
11 | /// Gets the URI of the asset.
12 | ///
13 | public Uri Uri { get; }
14 |
15 | ///
16 | /// Gets the assembly associated with the asset.
17 | ///
18 | public Assembly Assembly { get; }
19 |
20 | ///
21 | /// Gets the URI of the project root containing the asset.
22 | ///
23 | public Uri Project { get; }
24 |
25 | ///
26 | /// Gets the path of the asset.
27 | ///
28 | public string Path { get; }
29 |
30 | ///
31 | /// Initializes a new instance of the class.
32 | ///
33 | /// The URI of the asset.
34 | /// The assembly associated with the asset.
35 | /// The URI of the project root containing the asset.
36 | /// The path of the asset.
37 | public AssetInfo(Uri uri, Assembly assembly, Uri project, string path)
38 | {
39 | Uri = uri;
40 | Assembly = assembly;
41 | Project = project;
42 | Path = path;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/HotAvalonia.Core/AvaloniaControlManager.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Threading;
2 | using HotAvalonia.Collections;
3 | using HotAvalonia.Helpers;
4 | using HotAvalonia.Reflection.Inject;
5 | using HotAvalonia.Xaml;
6 |
7 | namespace HotAvalonia;
8 |
9 | ///
10 | /// Manages the lifecycle and state of Avalonia controls.
11 | ///
12 | internal sealed class AvaloniaControlManager : IDisposable
13 | {
14 | ///
15 | /// The document associated with controls managed by this instance.
16 | ///
17 | private readonly CompiledXamlDocument _document;
18 |
19 | ///
20 | /// The set of weak references to the controls managed by this instance.
21 | ///
22 | private readonly WeakSet