-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hot Reload doesn't work when the root element is named #5
Comments
Our world would be a much better place if all bug reports were this thorough and thoughtful. Thanks a lot for all the effort you put into this issue. The MRE is also hugely appreciated :) I'm gonna ignore the fact that VS and Rider behave differently in this situation for a bit, in hope that when the problem is gone, this detail will no longer be relevant. I always knew that there were some problems with named components (e.g., if you rely on auto-generated fields for those, their values are not being updated whenever the control is repopulated, because Avalonia puts this logic in a completely irrelevant to the process place, so I need to re-implement this functionality on my side), but it never occurred to me, for some reason, that I should at least test if they at least somewhat work :D So, the issue stems from public string? Name
{
get => _name;
set
{
if (_stylesApplied)
throw new InvalidOperationException("Cannot set Name : styled element already styled.");
_name = value;
}
} Should be pretty easy to hack our way around this. Give me a moment! |
Wow, that was fast. Auto-generated fields for named Controls? Do you mean the Avalonia XAML name reference generator? If so, then yes. It's most of the reason why I name controls in the first place though it does help automation, too. I probably wouldn't try hot reloading adding/modifying a name for a control that existed at startup though. Edit: Oh, I never use the root control name in code-behind...since that's |
I mean AvaloniaUI/Avalonia.NameGenerator, so yeah. There are a few issues with that project, at least for a tool like HotAvalonia:
Anyways, as of be3e5b8, source-generated fields are now also refreshed whenever their parent control is re-populated. I would greatly appreciate if you could check if everything related to named controls works fine now on your end, as you mentioned that there are some additional quirks with Visual Studio, and I do not have a Windows machine on me to test that. If everything is okay, I will push v1.1.1 asap :) |
I see. Before I narrowed down this issue, I assumed controls were being recreated, the visual tree was being manipulated, and some state synchronization was happening between old and new. I've looked through the HotAvalonia code base, but I don't really understand the specifics in how it works. In particular, the scenarios where method injection and the various populate override methods are used. Whether things like the IL gen is wholly necessary or just there for perf. I'm interested in seeing how much of this can be applied to other state synchronization scenarios; layout (de)serialization and snapshot testing. We could get Anyways, I have tested this on VS / Windows by pulling my repro into the solution. Everything seems to work well, so this should be resolved. Thanks! |
A bit late for this issue, but I submitted an Avalonia PR for the Name Generator attributes. It should be making its way in sooner-than-later, but it will still have some min version dependence. |
Well, you're not wrong! At the end of the day, these are required components for any hot reload system :D Everything you mentioned does happen. However, some tasks are performed implicitly, while others are handled in a rather unusual manner. The "proper way" to implement such a thing would be to keep a snapshot of the current logical tree and its relationship with the source XAML it's been built from, then track down changes in the source files, create a diff, and submit updates to affected nodes of the tree, yada yada. A number of people have tried to bring hot reload to Avalonia this exact way; all of them had some success with their prototypes, and all of them halted their attempts in the end because such an undertaking is quite a commitment to say the least. HotAvalonia doesn't do that. In fact, I believe there's not a single line of code in this repo that tries to parse XAML or address it in any other way than a simple string. HotAvalonia tracks changes on a per-file basis. So, whenever you change a source XAML file, controls associated with it are going to be completely rebuilt from ground zero. This approach has its downsides, sure, but also a huge benefit that makes it viable:
Arguably the most important component here is HotAvalonia's responsibility is to discover all controls within the running assembly, identify the XAML files they were built from, and then listen for change events on those files, just to throw
As you could probably tell from the first paragraph, in this project, and this project only, I'm not really obsessed with optimizations. So, method injection and IL generation associated with it are pretty important for HotAvalonia to work. Whenever we compile a new populate method for some control, it's easy for us to repopulate it - just call that generated method. However, Avalonia knows nothing about these shenanigans, so as soon as you create a new instance of the same control, it will revert to its "defaults" (i.e., its state at the moment of project compilation). To prevent that, HotAvalonia hijacks calls to all population methods within the assembly, so it can redirect those to freshly compiled alternatives that reflect the current state of your source files. You could also notice that there's a fallback mechanism employed when method hijacking is not possible (well, at least its primitive version I implemented here). There's an interesting atavism within the code produced by Avalonia for user controls (i.e., controls for which Initially, I hoped to implement method hijacking with
Great job! Also, nice catch with the Even though I cannot solely rely on these attributes, since I want to support Avalonia 11+, I will make a quick commit that will help to disambiguate some things in the future, in cases where the attributes are present. Thus, your contribution is still very much helpful! Once again, nicely done! :)
That's great! I'm going to trigger the CI in a moment, so you can expect the updated package to be indexed by NuGet in a few hours :) |
My goodness, I need to stop writing these giant walls of text |
Thanks for the fix and the wall of text. It was quite useful for me. |
@Kir-Antipov YOU ARE AMAZING, I have been having the same issue as steve without knowing the issue until now. Thank you for fixing it. |
@leowest77, thanks a lot for the kind words! And thanks to @stevemonaco for reporting the issue in the first place :D |
When an
x:Name
is assigned to a root element (Window
orUserControl
), hot reloading doesn't work. I assume that some synchronization is happening and Avalonia doesn't like it when theName
is set again.Repro (with XAML comments): https://github.com/stevemonaco/HotAvaloniaNameRepro
There are some behavioral differences in Rider and VS and I tested in both. Namely, the Window Title (and bindings to the Title) can be hot reloaded in Rider, but not in VS. Child state modifications never seem to work when the root element is named in either IDE.
I've been able to break hot reloading in a (real) project I made in Rider simply by adding an
x:Name
to theWindow
. Conversely, I've been able to fix another (real) project maintained in VS simply by removing aWindow
x:Name
.HotAvalonia version: 1.1.0
Avalonia versions: 11.0.10 and 11.1.0-beta2
.NET 8
VS: 17.9.3
Rider: 2024.1
Avalonia source where exception is thrown
Stack Trace:
The text was updated successfully, but these errors were encountered: