Skip to content
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

Add Expander Events #9555

Merged
merged 7 commits into from
Nov 30, 2022
Merged

Add Expander Events #9555

merged 7 commits into from
Nov 30, 2022

Conversation

robloo
Copy link
Contributor

@robloo robloo commented Nov 28, 2022

What does the pull request do?

Adds four new Expander events:

  1. Expanded : Based on WPF's implementation
  2. Collapsed : Based on WPF's implementation
  3. Expanding : Based on WinUI
  4. Collapsing : New for Avalonia

Additionally, Expanding and Collapsing events can be externally cancelled (marked as handled) to keep the expander in a certain state.

What is the current behavior?

There are no expander events, the IsExpanded property must be observed directly to determine expanded/collapsed state.

What is the updated/expected behavior with this PR?

Four events added as described above.

How was the solution implemented (if it's not obvious)?

Additional Resources

Checklist

Breaking changes

None, except the protected method protected virtual async void OnIsExpandedChanged(AvaloniaPropertyChangedEventArgs e) has been removed. The new OnCollapsed(...), OnCollapsing(...), OnExpanded(...), OnExpanding(...) methods may be used instead.

Obsoletions / Deprecations

None

Fixed issues

Closes #9458

@robloo robloo marked this pull request as ready for review November 28, 2022 05:17
@avaloniaui-team
Copy link
Contributor

You can test this PR using the following package version. 11.0.999-cibuild0026604-beta. (feed url: https://nuget.avaloniaui.net/repository/avalonia-all/index.json) [PRBUILDID]

@avaloniaui-team
Copy link
Contributor

You can test this PR using the following package version. 11.0.999-cibuild0026647-beta. (feed url: https://nuget.avaloniaui.net/repository/avalonia-all/index.json) [PRBUILDID]

@avaloniaui-team
Copy link
Contributor

You can test this PR using the following package version. 11.0.999-cibuild0026664-beta. (feed url: https://nuget.avaloniaui.net/repository/avalonia-all/index.json) [PRBUILDID]

Comment on lines +166 to +171
RaisePropertyChanged(
IsExpandedProperty,
oldValue: value,
newValue: _isExpanded,
BindingPriority.LocalValue,
isEffectiveValue: true);
Copy link
Member

Choose a reason for hiding this comment

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

This is kind of code I generally would prefer to avoid, as this API changes the property value without actually setting the value in conventional way.
Although, it also seems to the most convenient way to do these events for the users who would use this control.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tend to agree with you. I made sure to document reasoning well in case there are different suggestions. However, while it looks bad in general, I can't think of any downsides. It should be perfectly harmless. It's just one of those bad special cases.

That said, I did think of a way around this. It requires removing the toggle button entirely from the control template. State would then be managed entirely within the Expander itself -- which is probably a fundamentally better design to begin with. I think WPF was also being lazy and didn't want to duplicate a lot of code, as well.

Im not sure how much code duplication would be required to remove the toggle button from the default template. Pointer press and click would have to be entirely managed by the Expander. Keyboard navigation as well. It would probably be similar to what we did for SplitButton.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll leave this open and we can always come back and change things in the future. It shouldn't be a bad breaking change except for those writing their own control themes (rare).

Copy link
Member

Choose a reason for hiding this comment

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

It probably will be less customizable without the toggle button

Copy link
Member

@maxkatz6 maxkatz6 left a comment

Choose a reason for hiding this comment

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

Works well.
Thank you for continuing improving our controls!

@robloo
Copy link
Contributor Author

robloo commented Nov 30, 2022

Thank you for continuing improving our controls!

No problem, these type of changes are driven by my own needs though :) It's a pain point in porting that is tricky to work around in some cases. It's less code just to add to the framework.

@maxkatz6 maxkatz6 merged commit 1d7e5a2 into AvaloniaUI:master Nov 30, 2022
@avaloniaui-team
Copy link
Contributor

You can test this PR using the following package version. 11.0.999-cibuild0026682-beta. (feed url: https://nuget.avaloniaui.net/repository/avalonia-all/index.json) [PRBUILDID]

@robloo robloo deleted the expander-events branch November 30, 2022 01:04
@grokys
Copy link
Member

grokys commented Jan 16, 2023

Expanding/Collapsing may be cancelled by setting Handled = true in external event handlers

(I've seen this discussed but can't find where now, apologies if I'm going over old ground...)

I'm not sure that reusing Handed is the best solution here. Handed is used to prevent propagation up the tree and to me feels distinct from canceling an operation.

EDIT: Ok, found it: #9979 (comment) - yeah I think adding a separate event args class would be a good idea.

@grokys
Copy link
Member

grokys commented Jan 17, 2023

Also given that canceling the expansion is causing problems (#9979) are we sure we want to add that feature? I may be looking at the wrong version but it looks like WinUI doesn't have a way to cancel.

@robloo
Copy link
Contributor Author

robloo commented Jan 17, 2023

@grokys I have usages for cancelling the expansion. Specifically, in an accordion-layout not allowing to close the currently opened expander unless another one is expanded first. Other Expander implementations from 3rd party control libraries have supported cancellation in the past as well. I see no fundamental reason we shouldn't have this from an API standpoint -- cancelling is fairly common like this in other cases/controls as well.

There are no technical limitations that can't be worked-around either. This and the other PR does work well -- you can try it out in control catalog now -- it just has to force a binding update due to a more general problem (discussed #9979 (comment)).

Edit: To summarize I wouldn't say "Canceling the expansion is causing problems". It works just fine already and only needs to work around a fundamental problem with properties. But the work-around is harmless itself.

@grokys
Copy link
Member

grokys commented Jan 17, 2023

Specifically, in an accordion-layout not allowing to close the currently opened expander unless another one is expanded first.

Wouldn't it be simpler to just disable the toggle button for the currently expanded expander in that case?

Other Expander implementations from 3rd party control libraries have supported cancellation in the past as well. Cancelling is fairly common like this in other cases/controls as well.

Hmm ok, if you can point me to some examples of this, maybe we can try to work out how they manage this desync between controls.

@robloo
Copy link
Contributor Author

robloo commented Jan 17, 2023

Wouldn't it be simpler to just disable the toggle button for the currently expanded expander in that case?

It would fundamentally change how the API works. You would have to switch to and add an "AllowExpandCollapse"-type property instead. It is more common (look at Flyout for example) to allow canceling an Opening/Closing type event in XAML frameworks. Microsoft may not have done this a lot but I would argue that's because they never evolved their controls enough before they cancelled the projects. Every subsequent XAML framework has also had less-and-less features so comparing to WinUI/UWP is not always the best either (sorry I'm getting sidetracked).

if you can point me to some examples of this

maybe we can try to work out how they manage this desync between controls.

Well, I think we know the problem here fairly well:

  1. Expander is fundamentally not designed correctly as a control. With most other controls "state" information is stored ONLY in a property of the control itself NOT in (or shared with) a template part like a toggle button IsChecked property. However, even WPF used this "hack" to significantly simplify the control design and implementation. First mentioned here: Add Expander Events #9555 (comment)
  2. WPF and other XAML frameworks have never (as I understand it) properly handled the case where the receiver of a value reverts the change. This is discussed at length here: Switch Expander.IsExpanded to a StyledProperty #9979 (comment) (for future readers)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Expander Events
4 participants