Skip to content

Conversation

@grokys
Copy link
Member

@grokys grokys commented Jun 26, 2018

There are lots of cases of styled properties that have only a local value. Currently we are creating a PriorityValue for each set property on an AvaloniaObject, even if it is to store just a single local value.

This PR changes that: when a property has just a single local value it will be stored directly without creating a PriorityValue. When the property is bound to, or when a non-LocalValue is assigned to it, then a PriorityValue will be created as before.

This PR refactors the value dictionary into a ValueStore class to make this manageable. The overhead of this is non-zero, but in the figures below only represents about 0.5mb. I think this is an acceptable overhead for the sake of maintenance (yes, I did try a version where the code to manage this was placed directly in AvaloniaObject).

Memory Usage

Memory usage was measured via the VS2017 diagnostic tools by running ControlCatalog in Release mode, opening all pages and then taking a memory snapshot:

Note that this PR depends on #1695:

On #1695:

Objects Heap Size (KB)
1,086,578 63,557

This PR:

Objects Heap Size (KB)
966,731 56,749

Depends on #1695

grokys added 4 commits June 26, 2018 02:30
Instead of using a `PriorityValue`, when a property is assigned a simple `LocalValue` just store the value directly in the value store.
@grokys grokys requested a review from a team June 26, 2018 22:14
@wieslawsoltes
Copy link
Collaborator

@grokys I get this error:

Could not convert object '!HideChrome' (of type System.String) to {clr-namespace:Avalonia;assembly=Avalonia.Base}AvaloniaProperty: Could not find AvaloniaProperty 'MetroWindow.!HideChrome'.
   at Portable.Xaml.XamlObjectWriterInternal.GetCorrectlyTypedValue(XamlMember xm, XamlType xt, Object value) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 694
   at Portable.Xaml.XamlObjectWriterInternal.PopulateObject(Boolean considerPositionalParameters, IList`1 contents) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 562
   at Portable.Xaml.XamlObjectWriterInternal.OnWriteEndMember() in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 519
   at Portable.Xaml.XamlWriterInternalBase.WriteEndMember() in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlWriterInternalBase.cs:line 270
   at Portable.Xaml.XamlServices.Transform(XamlReader xamlReader, XamlWriter xamlWriter, Boolean closeWriter) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlServices.cs:line 128
   at Avalonia.Markup.Xaml.AvaloniaXamlLoader.LoadFromReader(XamlReader reader, AvaloniaXamlContext context, IAmbientProvider parentAmbientProvider) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\AvaloniaXamlLoader.cs:line 208
   at Avalonia.Markup.Xaml.Templates.TemplateContent.Load() in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\Templates\TemplateContent.cs:line 35
   at Avalonia.Controls.Primitives.TemplatedControl.ApplyTemplate() in C:\projects\Avalonia\src\Avalonia.Controls\Primitives\TemplatedControl.cs:line 259
   at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize) in C:\projects\Avalonia\src\Avalonia.Layout\Layoutable.cs:line 474
   at Avalonia.Layout.Layoutable.Measure(Size availableSize) in C:\projects\Avalonia\src\Avalonia.Layout\Layoutable.cs:line 318
   at Avalonia.Layout.LayoutManager.Measure(ILayoutable control) in C:\projects\Avalonia\src\Avalonia.Layout\LayoutManager.cs:line 178
   at Avalonia.Layout.LayoutManager.ExecuteInitialLayoutPass(ILayoutRoot root) in C:\projects\Avalonia\src\Avalonia.Layout\LayoutManager.cs:line 118
   at Avalonia.Controls.Window.Show() in C:\projects\Avalonia\src\Avalonia.Controls\Window.cs:line 366
   at Core2D.Avalonia.App.Start(IServiceProvider serviceProvider, AboutInfo aboutInfo) in C:\DOWNLOADS\GitHub\Core2D\src\Core2D.Avalonia\App.xaml.cs:line 146
Could not find AvaloniaProperty 'MetroWindow.!HideChrome'.
   at Avalonia.Markup.Xaml.Converters.AvaloniaPropertyTypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\Converters\AvaloniaPropertyTypeConverter.cs:line 44
   at Portable.Xaml.XamlObjectWriterInternal.GetCorrectlyTypedValue(XamlMember xm, XamlType xt, Object value) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 687

Code:
https://github.com/wieslawsoltes/Dock/blob/a1ca42c5b4519b33f343421f657aa787c41b9cd0/src/Dock.Avalonia/Controls/MetroWindow.xaml.cs#L40

https://github.com/wieslawsoltes/Dock/blob/a1ca42c5b4519b33f343421f657aa787c41b9cd0/src/Dock.Avalonia/Controls/MetroWindow.xaml#L18

@wieslawsoltes
Copy link
Collaborator

wieslawsoltes commented Jun 27, 2018

It also throws when property is really missing, which I think is good 👍

Could not convert object 'TitleBarContent' (of type System.String) to {clr-namespace:Avalonia;assembly=Avalonia.Base}AvaloniaProperty: Could not find AvaloniaProperty 'MetroWindow.TitleBarContent'.
   at Portable.Xaml.XamlObjectWriterInternal.GetCorrectlyTypedValue(XamlMember xm, XamlType xt, Object value) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 694
   at Portable.Xaml.XamlObjectWriterInternal.PopulateObject(Boolean considerPositionalParameters, IList`1 contents) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 562
   at Portable.Xaml.XamlObjectWriterInternal.OnWriteEndMember() in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 519
   at Portable.Xaml.XamlWriterInternalBase.WriteEndMember() in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlWriterInternalBase.cs:line 270
   at Portable.Xaml.XamlServices.Transform(XamlReader xamlReader, XamlWriter xamlWriter, Boolean closeWriter) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlServices.cs:line 128
   at Avalonia.Markup.Xaml.AvaloniaXamlLoader.LoadFromReader(XamlReader reader, AvaloniaXamlContext context, IAmbientProvider parentAmbientProvider) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\AvaloniaXamlLoader.cs:line 208
   at Avalonia.Markup.Xaml.Templates.TemplateContent.Load() in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\Templates\TemplateContent.cs:line 35
   at Avalonia.Controls.Primitives.TemplatedControl.ApplyTemplate() in C:\projects\Avalonia\src\Avalonia.Controls\Primitives\TemplatedControl.cs:line 259
   at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize) in C:\projects\Avalonia\src\Avalonia.Layout\Layoutable.cs:line 474
   at Avalonia.Layout.Layoutable.Measure(Size availableSize) in C:\projects\Avalonia\src\Avalonia.Layout\Layoutable.cs:line 318
   at Avalonia.Layout.LayoutManager.Measure(ILayoutable control) in C:\projects\Avalonia\src\Avalonia.Layout\LayoutManager.cs:line 178
   at Avalonia.Layout.LayoutManager.ExecuteInitialLayoutPass(ILayoutRoot root) in C:\projects\Avalonia\src\Avalonia.Layout\LayoutManager.cs:line 118
   at Avalonia.Controls.Window.Show() in C:\projects\Avalonia\src\Avalonia.Controls\Window.cs:line 366
   at Core2D.Avalonia.App.Start(IServiceProvider serviceProvider, AboutInfo aboutInfo) in C:\DOWNLOADS\GitHub\Core2D\src\Core2D.Avalonia\App.xaml.cs:line 146
Could not find AvaloniaProperty 'MetroWindow.TitleBarContent'.
   at Avalonia.Markup.Xaml.Converters.AvaloniaPropertyTypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\Converters\AvaloniaPropertyTypeConverter.cs:line 44
   at Portable.Xaml.XamlObjectWriterInternal.GetCorrectlyTypedValue(XamlMember xm, XamlType xt, Object value) in C:\projects\Avalonia\src\Markup\Avalonia.Markup.Xaml\PortableXaml\portable.xaml.github\src\Portable.Xaml\Portable.Xaml\XamlObjectWriter.cs:line 687

The TitleBarContent is really missing.

@wieslawsoltes
Copy link
Collaborator

@grokys Other than the issue I have reported with property PR looks good.

Copy link
Collaborator

@wieslawsoltes wieslawsoltes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with Core2D and all works now (fixes Core2D issues by refactoring property definitions and adding missing properties).

@jkoritzinsky
Copy link
Contributor

@wieslawsoltes The error you're getting on that TemplateBinding is a change by design in #1695. You should change that binding to be a regular binding with a RelativeSourceMode of TemplatedParent and a priority of TemplatedParent.

@jkoritzinsky jkoritzinsky merged commit 5d8b084 into master Jul 3, 2018
@jkoritzinsky jkoritzinsky deleted the valuestore branch July 3, 2018 19:47
@grokys grokys mentioned this pull request Jul 20, 2018
@grokys grokys added this to the 0.7.0 milestone Apr 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants