Skip to content

GradientSlider component creation#769

Open
Avid29 wants to merge 37 commits intoCommunityToolkit:mainfrom
Avid29:gradient_slider
Open

GradientSlider component creation#769
Avid29 wants to merge 37 commits intoCommunityToolkit:mainfrom
Avid29:gradient_slider

Conversation

@Avid29
Copy link
Copy Markdown
Member

@Avid29 Avid29 commented Jan 8, 2026

Introduces the first draft of the GradientSlider component.

Resolves: #768

GradientSlider.mp4

@michael-hawker
Copy link
Copy Markdown
Member

This is so cool! 🦙❤️ Thanks for thinking of this and putting this together, excited to go peek at how you've put it together in a minute.

Did a quick check on the CI, seems like some of the namespaces didn't get globalized properly for WinUI 2:

         D:\a\Labs-Windows\Labs-Windows\components\GradientSlider\src\GradientSlider.cs(5,25): error CS0234: The type or namespace name 'Shapes' does not exist in the namespace 'Microsoft.UI.Xaml' (are you missing an assembly reference?) [D:\a\Labs-Windows\Labs-Windows\components\GradientSlider\src\CommunityToolkit.WinUI.Controls.GradientSlider.csproj::TargetFramework=net9.0-android]
         D:\a\Labs-Windows\Labs-Windows\components\GradientSlider\src\GradientSlider.cs(13,59): error CS0246: The type or namespace name 'Rectangle' could not be found (are you missing a using directive or an assembly reference?) [D:\a\Labs-Windows\Labs-Windows\components\GradientSlider\src\CommunityToolkit.WinUI.Controls.GradientSlider.csproj::TargetFramework=net9.0-android]
         D:\a\Labs-Windows\Labs-Windows\components\GradientSlider\src\GradientSlider.cs(20,13): error CS0246: The type or namespace name 'Rectangle' could not be found (are you missing a using directive or an assembly reference?) [D:\a\Labs-Windows\Labs-Windows\components\GradientSlider\src\CommunityToolkit.WinUI.Controls.GradientSlider.csproj::TargetFramework=net9.0-android]

Copy link
Copy Markdown
Member

@michael-hawker michael-hawker left a comment

Choose a reason for hiding this comment

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

Some initial comments, this is an amazing start! Really interesting use of the Canvas. I'll have to pull it down and play with it a bit more directly.

I'm also wondering since I added Thumbs to the ResizeAdorner, and you have them here if there's any commonalities and if we just need a general Thumb base class like I did for the Sizers (which could honestly maybe re-use that as well, I mean I basically took that code and made it two-dimensional for the Adorner thumb).

Comment on lines +13 to +20
<controls:GradientSlider.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#FF0000" />
<GradientStop Offset="0.3" Color="#00FF00" />
<GradientStop Offset="0.66" Color="#0000FF" />
<GradientStop Offset="1" Color="#FF0000" />
</GradientStopCollection>
</controls:GradientSlider.GradientStops>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What happens if the developer doesn't specify any stops at the start? Could be good to have another example where it's bound to a collection (to show binding) but that collection is also empty to start?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seconded, documenting (and defining if needed) the expected behavior for empty/default properties is a trivial known/expected scenario for any component MVP.

Comment on lines +32 to +33
if (slider._isDragging)
return;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So if a stop is somehow programmatically added while the slide is in use, the slider will never get updated and be out-of-sync? We probably need to call RefreshThumbs or some other sync method when the drag is completed, eh?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seconded. This is another known/expected trivial MVP feature, the various properties on this control should support live updates.

We'll likely need to do a sweep to make sure property change updates are wired everywhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's actually worse than that.

There is no event or callback on the GradientStopCollection to detect a stop being added/removed. The actual limitation here is that if the GradientStops property values changes (as in the reference to the GradientStopsCollection object, while the user is dragging then it will become completely out of sync until the next RefreshThumbs() event.

Comment on lines +104 to +108
<FlyoutBase.AttachedFlyout>
<Flyout Placement="Bottom">
<muxc:ColorPicker x:Name="PART_ColorPicker" />
</Flyout>
</FlyoutBase.AttachedFlyout>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm always leery of adding intertwined children/parents, but I think in this case, it'd be nice if there was a single attachedflyout was part of the parent control and the child invoked that atop itself? Obviously, requires a bit more coordination, but...

Then I think it gets easier to expose the properties of the ColorPicker itself in one place on the GradientSlider. i.e. if they want to show a specific color palette or other things instead, they just have to restyle the parent control which is much simpler than the thumb.

Should we also use the WCT ColorPicker by default instead? Or should we expose a ColorPicker property on the slider so the developer themselves provide the picker they want to use configured exactly how they want (we can have a style value set with a default basic one in case they don't provide one)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just to make sure I understand what you're saying, we shouldn't have to retemplate the entire control to swap out the color picker or add any custom content around it? That instead, we could pass it in via a DP deriving ColorPicker, or if we wanted to allow custom content, a Control instance or DataTemplate?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@Arlodotexe Yes, but as a result the GradientSlider would own the ColorPicker. This has a cost of higher control coupling, but it is more layout optimized and makes this control more easily extensible (even though its components become less extensible).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would think, double-tapping on the slider should be the mechanism to add a new stop, eh? @niels9001 any suggestions on input here?

I'm trying to think of how you'd remove a stop, would it be dragging it further off some amount the end of the slider?

The only other scenario I'm thinking of here that'd be more complex to add is if you wanted a specific input box for the offset vs. drag input. (It could be nice in either case as you're dragging to see the offset value as a float [0-1] and/or percentage maybe?) Maybe it's not something we provide by default out-of-the-box, but something we should have a sample on how to extend the control to enable. i.e. could the flyout be customized to contain more than just a colorpicker, would we have to search the flyout for the colorpicker instance then?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've added a "Placeholder Thumb" that shows under a hovering mouse. My idea is that clicking there will add a stop in that position.

image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm a fan of the hover-to-add interaction method, though it doesn't cover removal. We can defer addressing both of these until later, but let's track it in a new ticket after closing this PR.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Currently you can right-click to remove a stop. Not the most intuitive solution, but just making clear that there is a way to remove stops right now.

@Avid29 Avid29 marked this pull request as draft January 9, 2026 18:37
@Avid29 Avid29 requested a review from michael-hawker February 5, 2026 20:55
@Avid29 Avid29 marked this pull request as ready for review February 5, 2026 20:55
@Arlodotexe Arlodotexe self-requested a review April 10, 2026 03:23
/// An example sample page of a custom control inheriting from Panel.
/// </summary>

[ToolkitSample(id: nameof(GradientSliderSample), "Custom control", description: $"A sample for showing how to create and use a {nameof(GradientSlider)} custom control.")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Default text (name/description) should be replaced so it's displayed properly in the sample app.

Copy link
Copy Markdown
Member

@Arlodotexe Arlodotexe left a comment

Choose a reason for hiding this comment

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

Reviewed and approved, there are improvements to make but nothing we can't defer. Let's take the lingering review comments and turn them into tracking issues, once we've resolved the review threads by deferring them to issues, we can merge the code and close the PR.

Avid29 and others added 4 commits April 10, 2026 12:41
@Avid29
Copy link
Copy Markdown
Member Author

Avid29 commented Apr 10, 2026

I've taken care of the simpler problems (default strings and metadata)

@michael-hawker
Copy link
Copy Markdown
Member

michael-hawker commented Apr 10, 2026

@Arlodotexe seems like WIP is stuck again... 🤔 I confirmed our installation is this repo: https://github.com/wip/action - they have a status here which shows it's been up: https://stats.uptimerobot.com/Dq46zf6PY - maybe we should file an issue anyway? I'm not sure how we get more details about what's holding it up though (it's a simple action and it hasn't changed).

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.

🧪 [Experiment] GradientSlider

3 participants