question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Convert Most `DirectProperty` Occurrences to `StyledProperty`

See original GitHub issue

Is your feature request related to a problem? Please describe.

This one is going to cause some controversy. However, I believe it’s time to significantly narrow the use-case of DirectProperty(ies) which are unable to be set by styles in most cases.

Some additional points for discussion:

  • Using DirectProperty in styles will cause exceptions and crashes (I’ve seen this come up a few times recently). This is VERY unintuitive to use as developers and we have to carefully check each property type. Of course tooling and compiler errors will improve, but I think it’s more of a fundamental problem.
  • It is somewhat confusing in Avalonia which property type to use and when. I think this should be documented clearly after this issue is closed (more on that below).
  • DirectProperty is pretty neat but not something we had to worry about in WPF where all properties are fully supported in styles (except for special read-only ones).
  • DirectProperty is still useful in some cases (read-only properties and lists) and must not go away
  • There are good reasons to set some properties that are currently direct within styles. Since it isn’t supported there are some ugly hacks required.
  • At the very minimum all direct property usage should be audited for 11.0 and converted to styled properties as required.

With the significant optimization done to the property value store over the past few years, I don’t expect a significant performance impact moving most properties over. I could be wrong though.

Describe the solution you’d like

Almost all current DirectProperty occurrences should be converted to StyledProperty so they can be used fully within styles. My original comment was:

direct properties should be reserved only for “data”… which includes content, read-only collections

@tomenscape had some good points and narrowed the scope again:

I would go even further than robloo’s suggestion: in light of these changes, DirectProperty should be restricted to read-only properties. This is the only safe way to proceed. Even “data” values can reasonably set in a style, if you have multiple distinct values that you want to switch between depending on UI state.

This means ALL direct properties such as TextBlock.Text, Expander.IsExpanded and SplitPane.IsPaneOpen (which are UI state information) would be converted to styled properties.

Describe alternatives you’ve considered

There are two alternatives:

  1. Extend the styling system to allow settings DirectProperty as if it was a StyledProperty. No idea how to do this.
  2. No changes…

Additional context

Some recent discussions include:

@tomenscape Feel free to duplicate your past comments here. It will put everything in one spot for the future.


Current status is tracked below. Note that animations and certain drawing primitives are currently out-of-scope. There is a strong chance of performance regressions in these areas and the use-cases of changing such properties in styles is not yet clear. Therefore, the focus is primarily controls:

  • AutoCompleteBox
  • ~Border~
    • No DirectProperty usage
  • Button
    • The only DirectProperty IsPressed is a read-only property so remains unchanged
  • ~ButtonSpinner~
    • No DirectProperty usage
  • CalendarDatePicker
  • Calendar
  • ~Canvas~
    • No DirectProperty usage
  • ~Carousel~
    • No DirectProperty usage
  • ~CheckBox~
    • No DirectProperty usage (derives directly from ToggleButton which was completed separately)
  • ColorPicker / ColorView (and primitives)
    • Verified to be correct
  • ComboBox
  • ~ContentControl~
    • No DirectProperty usage
  • ContentPresenter
  • ~DataGrid~
  • DatePicker
  • ~DatePickerPresenter~
    • No DirectProperty usage
  • ~Decorator~
    • No DirectProperty usage
  • ~DockPanel~
    • No DirectProperty usage
  • ~DropDownButton~
    • No DirectProperty usage (currently derives directly from Button)
  • Expander
  • Flyout
  • ~Grid~
    • No DirectProperty usage
  • ~GridSplitter~
    • No DirectProperty usage
  • ~Image~
    • No DirectProperty usage
  • ~ItemsControl~
    • Has two direct properties (Items, ItemCount) but they are already handled after the Items/ItemsSource rewrite
    • Items has an Obsolete setter (it is intended to be read-only)
    • ItemCount is read-only and correct as a DirectProperty
  • ItemsPresenter
  • ~ItemsRepeater~
  • Label
  • [Partial] ListBox
  • ~Menu~
    • No DirectProperty usage
  • MenuBase
  • ~MenuItem~
    • No DirectProperty usage
  • MenuFlyout
  • ~ContextMenu~
    • No DirectProperty usage
  • NativeMenu
  • NativeMenuItem
  • NumericUpDown
  • ~Panel~
    • No DirectProperty usage
  • Popup
  • ProgressBar
    • The only direct property Percentage is correct as a direct property. This is a read-only calculated value.
    • ProgressBarTemplateProperties has many DirectProperty members but these can likely be ignored for now (animation is out of scope).
    • Other properties were fixed with RangeBase
  • RadioButton
  • RangeBase
  • ~Rectangle~
    • No DirectProperty usage
  • ~RelativePanel~
    • No DirectProperty usage
  • ~RepeatButton~
    • No DirectProperty usage
  • ScrollBar
    • Has a single read-only DirectProperty IsExpanded that is likely already correct
  • ScrollContentPresenter
  • ScrollViewer
  • [Partial] SelectingItemsControl
  • ~Separator~
    • No DirectProperty usage
  • ~Slider~
    • No DirectProperty usage (inherited from RangeBase)
  • ~Spinner~
    • No DirectProperty usage
  • ~SplitButton~
    • No DirectProperty usage
  • SplitView
  • ~StackPanel~
    • No DirectProperty usage
  • ~TabControl~
    • No DirectProperty usage
  • ~TabItem~
    • No DirectProperty usage
  • ~TabStrip~
    • No DirectProperty usage
  • TemplatedControl
  • TextBlock
    • This must be done specially as its own PR and with benchmarking if possible. There is concern about performance regressions.
    • Completed in #10617
  • TextBox
  • TimePicker
  • ~TimePickerPresenter~
    • No DirectProperty usage
  • ToggleButton
  • ~ToggleSplitButton~
    • No DirectProperty usage
  • ~ToggleSwitch~
    • No DirectProperty usage
  • ~ToolTip~
    • No DirectProperty usage
  • ~Track~
    • No DirectProperty usage
  • [Partial] TreeView
  • TreeViewItem
  • ~Viewbox~
    • No DirectProperty usage
  • ~WrapPanel~
    • No DirectProperty usage
  • Window
  • ~PathIcon~
    • No DirectProperty usage

Issue Analytics

  • State:closed
  • Created 8 months ago
  • Reactions:6
  • Comments:49 (49 by maintainers)

github_iconTop GitHub Comments

2reactions
TomEdwardsEnscapecommented, Apr 29, 2023

Another option is a “property update batch” object which defers notifications for property changes made during its lifetime until disposed. This can be initiated from a control’s OnPropertyChanged, since it is executed first.

2reactions
TomEdwardsEnscapecommented, Jan 10, 2023

Thanks for making this issue @robloo. I was looking at the new ValueStore last night and I agree that there doesn’t seem to be much of a performance difference between setting a StyledProperty with local priority and setting a DirectProperty. It seems that the only remaining benefit of DirectProperty is providing support for read-only properties.

You have described the issue well, so I don’t need to replicate most of what I said. I’ll just add these details about the use case at my company:

We are using ControlTheme everywhere, and those themes often contains activatable styles. Our use case is actually low-level controls (e.g. Button) which appear within the templates of high-level controls, and the selectors are something like ^[Foo=bar] /template/ #SomeButton.

I understand the problems that come with setting direct properties from this context, but since we never wanted to remove these values, only to switch between multiple different options, that has never been a problem for us.

I would implement this change by first removing DirectProperty.Setter and AvaloniaObject.SetDirectValueUnchecked, and then fixing all the compile errors that arise. The fix for each error would be switching to StyledProperty or removing the setter and making the property read-only. AvaloniaObject.SetAndRaise (which is a protected method) would remain for use within private/protected C# property setters.

Separately: Changing Expander.IsExpanded is problematic now because I added cancellation which requires a direct property to intercept before the property is set. We would need an OnPropertyChanging callback with cancellation to get around this now.

Once the property is changed to StyledProperty, a coercion method could be executed before the value is written.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Defining Properties
Styled properties ensure that your property will work correctly with Avalonia's styling system. You register a styled property by calling AvaloniaProperty.
Read more >
Multiplatform Avalonia .NET Framework Programming ...
This article explains the most important and basic concepts of Avalonia WPF-like multiplatform UI package.
Read more >
005. Avalonia UI - Templated Controls - YouTube
Your browser can't play this video. Learn more.
Read more >
Hottest 'avalonia' Answers
This code runs DoSomethingForVeryLongTime on the UI thread, not a background thread. It issues the call asynchronously but the actual call still runs...
Read more >
MuPDFCore - Giorgio Bianchini
A string containing all the text in the document. Characters are converted from the UTF-8 representation used in the document to equivalent UTF-16...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found