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

🚧 SizerBase class for GridSplitter + new ContentSizer and PropertySizer components #4083

Conversation

michael-hawker
Copy link
Member

@michael-hawker michael-hawker commented Jun 21, 2021

Fixes #2976 #2017 #3949

The end goal of this PR is to have a base component which both ContentSizer and GridSplitter inherit from. It will also simplify the GridSplitter component to not have a sub-component for controlling the mouse-cursor behavior and instead use our mouse cursor extensions. This should resolve #2017. This also allows us to properly implement GridSplitter cursor behavior for WinUI 3 as it should be owned by the component itself and we can just use ProtectedCursor instead of our cursor extensions.

The end goal is that GridSplitter will be functionally equivalent to the one within the toolkit, though technically from a component/style standpoint this is a breaking change for 8.0. Updating should be straight-forward unless using some properties we've removed/changed around style/cursors which have been moved to the XAML template.

Overview of new SizerBase class

This PR introduces a new base class SizerBase (name to be finalized) which centralizes the logic for 'splitter/sizer/gripper' type controls like GridSplitter. The base class handles the following:

  • Shared XAML Template
    • Simplified Cursor handling using our Mouse extension (also one line change for WinUI 3 when we port for ProtectedCursor)
    • 🆕 Created OrientationToObjectConverter to handle character change based on Orientation
    • Set automation name via XAML (to be tested still)
  • Mouse Interaction (🆕 fixed long-standing bug GridSplitter is not always fixed to cursor when moving #3949 from v1.1 of original GridSplitter; manipulation done cumulatively vs. delta now.)
  • Keyboard Interaction
  • Accessibility
  • Common Properties/Behaviors
    • DragIncrement/KeyboardIncrement (🆕 brought forward from WPF GridSplitter, now on base class)
    • RightToLeft flow handling (🆕 fixed for keyboard, unknown bug)
    • Orientation
  • Abstract methods for manipulation:
    • OnLoaded
    • OnDragStarting
    • OnDragHorizontal
    • OnDragVertical
  • Shared VSM (🆕 now supports IsEnabled states and aligns to Thumb states)

The subclasses like GridSplitter then only need to implement the abstract methods provided OnLoaded, OnDragStarting, OnDragHorizontal, and OnDragVertical to apply the requested movement amount to the element being manipulated, e.g. a Grid. This makes the sub-class controls very simple and flexible and easier to follow logic-wise.

New Controls: ContentSizer and PropertySizer

On top of this new refined base class, we introduce two new controls:

  • The ContentSizer control is a more flexible/generic version of our GridSplitter control. It provides a bar which can then control the size of any Target element. This can be used to make more complex UIs and things like collapsible trays with the Expander control. It's actually the component I use to remember the Sidebar position within XAML Studio.
  • The PropertySizer control is even more generalize and a little more niche, but allows the manipulation of any double property via a TwoWay binding to that property (either another UI Element or even a ViewModel). This makes it super simple for example to manipulate a NavigationView's OpenPaneLength property to create a customized sidebar experience for NavigationView with no further modifications, this is the sample provided in our sample app. This addresses Allow app users to resize NavigationView's Pane microsoft/microsoft-ui-xaml#190.

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Refactoring (no functional changes, no api changes)
  • Build or CI related changes (ui testing)

What is the current behavior?

Grid Splitter is a complex component made of a separate piece which controls mouse cursor behavior. It is also restricted for use within a Grid.

What is the new behavior?

Grid Splitter is now based off a new base class which provides the look-and-feel and mouse behavior with our mouse extensions API. A new ContentSizer and PropertySizer also inherit from this base to provide a more generalized solution for other types of UI scenarios.

Note: The underlying logic for how GridSplitter works with a Grid has been left unchanged in this PR (for the most part - outside of updating it to use Cumulative values vs. deltas basically). If we want to adopt the WPF logic specifically, I suggest we do that afterwards as a separate PR, though note the bug note below as well. We can open an issue later.

PR Checklist

Please check if your PR fulfills the following requirements:

  • Tested code with current supported SDKs
  • Pull Request has been submitted to the documentation repository instructions. Link:
  • Sample in sample app has been added / updated (for bug fixes / features)
  • New major technical changes in the toolkit have or will be added to the Wiki e.g. build changes, source generators, testing infrastructure, sample creation changes, etc...
  • Tests for the changes have been added (for bug fixes / features) (if applicable)
  • Header has been added to all new source files (run build/UpdateHeaders.bat)
  • Contains NO breaking changes

List of Work to be Done

  • Migrate ContentSizer into Toolkit
  • Add infrastructure to support GridSplitter tests within the UI Test integration harness
  • Investigate TargetControl loading issues? - Haven't noticed with latest incarnations of components with shared base class.
  • Need to be more specific about Direction/Sizing for ContentSizer (i.e. it only works Left/Top currently, not Right/Bottom)
    • Investigate if can auto-detect alignment from TargetControl and/or
    • Have property for movement direction
  • Setup proper gripper character based on direction
  • Setup common base class (SizerBar, SplitterBar, SlidingBar, HandleBar?) so can be used for GridSplitter
  • Refactor ContentSizer on common base class
  • Refactor GridSplitter on common base class
    • Remove extra GripperHoverWrapper and use MouseExtensions (like ContentSizer)
    • Once working with existing code, investigate if we want to migrate WPF logic in another PR
      • Extra Bug from WPF: if grid splitter is to the right on the right-most column it can't re-size it...
  • Need to test Narrator/AutomationProperty & Test AutomationPeer
  • Update Design projects for VS Metadata for Designer
  • Check if Cursor property can be provided as a custom one without interference
  • Add new UI Tests for new controls
  • Modernize template style: rounded corners? accent color? etc...
  • Do we need an easier way to customize content/template (style is pretty simple)?
  • Docs
  • Do we want to name things as GripperBarBase, ContentGripperBar, and PropertyGripperBar instead? (GridSplitter is a polyfill so remains the same.) Or some other naming scheme?

Any suggestions on the name for the common base component?

@michael-hawker michael-hawker added this to the 7.1 milestone Jun 21, 2021
@ghost
Copy link

ghost commented Jun 21, 2021

Thanks michael-hawker for opening a Pull Request! The reviewers will test the PR and highlight if there is any conflict or changes required. If the PR is approved we will proceed to merge the pull request 🙌

@ghost ghost requested review from azchohfi, Kyaa-dost and Rosuavio June 21, 2021 23:01
@ghost ghost added bug 🐛 An unexpected issue that highlights incorrect behavior controls 🎛️ feature request 📬 A request for new changes to improve functionality labels Jun 21, 2021
@michael-hawker
Copy link
Member Author

Ugh forgot to add headers, will fix in a min

@michael-hawker
Copy link
Member Author

michael-hawker commented Mar 5, 2022

Filed #4500, looks like there's an underlying issue with our CI at the moment. I built this locally with no issues before pushing up.

@michael-hawker michael-hawker changed the title 🚧 ContentSizer/GridSplitter Work 🚧 SizerBase class for GridSplitter + new ContentSizer and PropertySizer components Mar 5, 2022
@michael-hawker michael-hawker mentioned this pull request Mar 5, 2022
17 tasks
michael-hawker and others added 3 commits March 7, 2022 10:21
Content Sizer Issues:
- [ ] TargetControl isn't loaded yet causes problems (Expander Issue)
- [ ] Size Direction needs to be more specific (only works Left/Top, not Right/Bottom)
- [ ] Do we support 'Auto'?
- [ ] Need to set Automation Property Name in Code-Behind
- [ ] Content Initial value as binding converter to ResizeDirection?
Bonus also fixes issue with sample loading the first time...
Removed now unused SplitterCursorBehavior property
…en GridSplitter and ContentSizer

- Share XAML template between all controls
  - Includes sharing VSM and logic to control that
- Centralized control manipulation logic to base class
  - Cleaned-up Keyboard handling code to be shared in base class using OnKeyDown override
  - Move OnManipulationDelta to SizerBase
- Share Automation Name and setup via XAML vs. code-behind
- Renamed ResizeDirection to Orientation in the base for ContentSizer and future controls, synced from GridSplitter with original ResizeDirection for polyfill (removed unneeded ContentSizerDirection/SizerResizeDirection enum as using system Orienation now)

TODO:
- Update/Fix AutomationPeer to generalize
- Provide OnLoaded virtual event?
- Figure out Content/ContentTemplate setup do we want this flexibility? Do we just have Content which is set to the TextBlock in Style as Default instead?
- Create Converter to set content for horizontal/vertical text in XAML (bound to Orientation)
- Update GripperCursor in Orientation changed callback
- Do we try inheriting from Thumb? Does that automatically solve the mouse drag back issue?
- Audit Sizer/Splitter/Gripper/Thumb naming???
Rename Horizontal/VerticalMove methods to prefix with On
… own files in the partial class.

Move IsDragInverted to ContentSizer as it is specific to that class for now.
…er all use Cumulative change to update sizes vs. Delta

This fixes long-standing issue where mouse would de-sync from gripper bar and provide a disorienting experience to users. Now the bar only moves when the mouse is over it and ignores extra movement - the same as Thumb controls do within a Slider for instance.
…erBase controls.

Fix issue where we broke keyboard with cumulative change fix in last commit
Remove GripperKeyboardChange constant
Guard against keyboard input during drag event.
Add more comments on abstract methods and behavior in SizerBase
Removed Content/ContentTemplate for now from SizerBase, may want to add back in the future.
Simplified template to include TextBlock and use converter to setup glyphs
Provided more keys for manipulating resource values in template
Fixes issue with ContentSizer Horizontal mouse cursor being incorrect until drag
Clean-up Cursor setting code to be handled in property changed callback of Orientation instead
Will aid in the future if we get a Cursor property in WinUI 3 for ProtectedCursor, one spot to change only.
Comment on lines +21 to +27
DependencyProperty.Register(nameof(HorizontalValue), typeof(object), typeof(TypeToObjectConverter), new PropertyMetadata(null));

/// <summary>
/// Identifies the <see cref="VerticalValue"/> property.
/// </summary>
public static readonly DependencyProperty VerticalValueProperty =
DependencyProperty.Register(nameof(VerticalValue), typeof(object), typeof(TypeToObjectConverter), new PropertyMetadata(null));
Copy link
Member Author

Choose a reason for hiding this comment

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

Need to fix typeof() here referencing TypeToObjectConverter (found in Labs via crash on Skia (go Uno)). Fixed in labs.

@michael-hawker
Copy link
Member Author

Moved this over to labs for now, so this may just get closed out and we'll re-import later for 8.0 via labs restructure/future work there.

@michael-hawker
Copy link
Member Author

This is now an experiment in Toolkit Labs (see #4487 for info on Labs).

It can be found at the following Experiment: CommunityToolkit/Labs-Windows#101

Closing this PR out now as we'll re-integrate from Labs later for 8.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 An unexpected issue that highlights incorrect behavior controls 🎛️ feature request 📬 A request for new changes to improve functionality labs 🧪 Marks an issue/PR involved with Toolkit Labs
Projects
Features 8.0
Awaiting triage
Development

Successfully merging this pull request may close these issues.

Gridsplitter controls sometimes causes the pointer to disappear Redesign of GridSplitter API
2 participants