-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Refactor styling #3636
Refactor styling #3636
Conversation
We already have some specific internal methods for routing certain methods via an untyped property to a typed property, but adding support for the visitor pattern allows us to support arbitrary use-cases.
- Don't use Rx in the styling system. Instead introduces `IStyleActivator` which is like an `IObservable<bool>`-lite in order to cut down on allocations. - #nullable enable on touched files
Match selectors from left-to-right, as before we were checking things like property equality (and creating a `PropertyEqualsActivator`) before checking that the control is of the correct type. Also hopefully makes the selector matching logic more readable.
We need to make sure to set up the bindings as soon as the setter is instanced, even if it's not activated immediately.
Animations are still using an `IObservable<bool>` to trigger them as I didn't feel confident refactoring them as part of this PR.
I'm not sure what should happen here when the style deactivates and is re-activated. Should the one-time binding trigger again? Or should it only trigger on first activation? Wait and see what the use-case for this is (if any).
@@ -224,44 +147,12 @@ void ISetResourceParent.SetParent(IResourceNode parent) | |||
|
|||
if (parent == null) | |||
{ | |||
Detach(); | |||
//Detach(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, and I forgot to mention it in the description. This PR actually removes support for removing styles (well, you can still remove them but they won't get unapplied to controls). This is because I wanted to implement adding styles too and intended to do it in another PR. Not sure if this is a blocker for this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it have any observable difference if we don’t support it for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someone is removing styles from a Styles
collection, yes. However the fact that adding styles to these doesn't currently work in my mind makes it unlikely that anyone is relying on this. I plan to submit a PR to implement adding/removing styles in the next day or so anyway.
What happens to said disposable if something else sets a different value? |
The new value will take effect until that itself is disposed. It might be worth giving some background here: this change is enabled by #3255:
The future PR is this PR. What that #3255 didn't do though was provide a way to remove the priority value when a style was detached, which is what I added here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Style remove not working for a while should be fine (I think that might break our theme switcher).
And you still have merge conflicts to resolve.
Ok, implemented support for adding/removing styles, will open a PR shortly. In the meantime, will merge this. |
What does the pull request do?
Previously @MarchingCube and myself had identified that our styling system was one of the performance bottlenecks in our code, mainly due to its extensive use of Rx and Disposables and the allocations they make.
This PR refactors the styling system with an eye to reducing memory allocations:
AvaloniaObject.SetValue
return anIDisposable
for values that can be undone (i.e. non LocalValue values)Setter
on a control, create a typed object to produce value/binding so that untyped binding adapters can be avoidedSetter
on a control, don't create a binding if the parent style doesn't have an activator, instead useSetValue
now that it returns anIDisposable
IObservable<bool>
for style activators. While usingIObservable<>
itself does not necessarily have a large allocation overhead, the particularly limited use of it in this case meant that we can save a few allocations by using our own interface:IStyleActivator
. In particular, to AND or OR a series of observables, one needs to allocate an object for each input observable in order to identify which of the inputs have changed.IStyleActivator.Subscribe
on the other hand receives anint tag
which is passed on eachOnNext
invocation to identify the input.#nullable enable
the files that were touchedWhat is the current behavior?
Some benchmarks on
master
:Running ControlCatalog.NetCore on
master
and opening all the tabs:542.38 MB total
165.05 MB .NET total
126.87 MB .NET used
2.35M objects
What is the updated/expected behavior with this PR?
Running ControlCatalog.NetCore on this branch and opening all the tabs:
518.25 MB total
138.43 MB .NET total
108.39 MB .NET used
1.93M objects
Checklist
Breaking changes
Some of the low-level style APIs have changed a little, but these shouldn't be being used from user code.
This PR removes support for removing styles (well, you can still remove them but they won't get unapplied to controls). This is because I want to implement adding styles too and intend to do it in another PR.