Avalonia
Avalonia copied to clipboard
Add HyperlinkButton
Is your feature request related to a problem? Please describe.
Other XAML frameworks have a HyperlinkButton (not to be confused with an inline hyperlink text element inside of a text control). This control is useful to:
- Simplify the common use case of a hyperlink button
- Provide a standard look-and-feel for hyperlinks in the framework
- Provide a cross-platform way of navigating to Uri like webpages.
- Automatically manages a change in text color after a link is clicked the first time.
There are additional opportunities here as well. The HyperlinkButton
could have a new NavigateUri
property added (like UWP). If a NavigateUri is set, then the HyperlinkButton is pressed, that Uri would be opened in a platform-specific way. This would greatly simplify opening something like a webpage on each platform.
Describe the solution you'd like
Add a new HyperlinkButton control derived from button with a standardized style.
Describe alternatives you've considered
I've seen often times in the past developers are told to just create their own custom Button style and use that instead.
Additional context Add any other context or screenshots about the feature request here.
I've seen often times in the past developers are told to just create their own custom Button style and use that instead.
Yes.
Snipped from one of my projects:
<Style Selector="Button.link">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Padding" Value="0" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.Styles>
<Style Selector="TextBlock">
<Setter Property="Foreground" Value="{TemplateBinding Foreground}"/>
<Setter Property="FontSize" Value="{TemplateBinding FontSize}"/>
<Setter Property="TextDecorations" Value="Underline"/>
</Style>
</ContentPresenter.Styles>
</ContentPresenter>
</ControlTemplate>
</Setter>
</Style>
It can be easily extended to include some kind of icons as well or richer content.
The HyperlinkButton could have a new NavigateUri property added (like UWP). If a NavigateUri is set, then the HyperlinkButton is pressed, that Uri would be opened in a platform-specific way. This would greatly simplify opening something like a webpage on each platform.
It might be controversial, but I don't agree NavigateUri is useful. It's very business-requirements specific. Sometimes you don't need to open link in the browser, but open link inside of your app. Or execute simple command. Click handling should be delegated to the developers, who know better what is needed in their application. But at this point we have another question "why it's called hyperlink button then? only because of visual style?". And yes, in my app it's about visual style, and only in one place it actually opens link in the browser (in other places it opens helper popup).
On other hand, though, there is at least one more scenario when basic Button style is not enough - special visual state when button was already pressed once. Of course it can be easily implemented in the application, but some might consider it as a an important part of hyperlink button visual.
Can't we have a build in command to navigate to a Hyperlink, which accepts an URI as CommandParameter?
This would make it easy to use and also keep the flexibility.
You don't have to use NavigateUri if you don't want to. In apps I've worked on its quite helpful for quickly going to online to docs, user agreements, etc.
The already pressed state is a good point I thought about a while ago but forgot to add. I'll update, thanks.
Whoops, forgot about this one when I said I didn't have plans for more controls from WinUI in Avalonia. @maxkatz6 I'm assuming the core team will generally frown on a PR to implement this? I can hold off for a while after other discussions are resolved.
If this control will be more useful than "button with a style", I am good with it. Especially if most of the code can be reused from the Button control. Tbh I don't remember if WPF/UWP HyperlinkButton is actually better than that.
But I still think it's not really necessary control, so I wouldn't put any high priority on it.
@maxkatz6 Well, it will also open hyperlinks if a Navigate URL is provided and have a new pseudoclass :navigated or something to change the color after a link is clicked. Basically 1-4 in the description. It will be very lightweight though and derive from button.
Which reminds me: I made changes to Button a while ago for DropDownButton that make inheriting for SplitButton make even more sense. I've also kept searching on why Microsoft didn't derive SplitButton from Button and the best guess is to flatten the Visual Tree / controls hierarchy for performance. This means I might change SplitButton to derive from Button as well -- so you would get your preference there after all.
I've decided not to add this control for 11.0. I still plan to add it at some point in the future -- probably for 12.0 in a year or so. But time is limited and this isn't critical. This control can be added without any breaking changes at any point in the future.
I think we can add also the help-wanted label, so anyone having some free time can implement this feature.
I will take a look at the uwp implementation and see if I can finish this in v11
@rabbitism I had several ideas I was going to include as well. Also the FluentAvalonia one is a good base. Actually, the existence of the Fluent Avalonia one and this not being a blocker for other controls is why I deprioritized this myself.
Aside from the 4 original points above (with cross platform navigation link in Fluent Avalonia with mobile added) I was going to add a property that could specify if the link was already navigated or not.
That property would be automatically set to true after the first click. It would then set a 'navigated' pseudoclass to change the colors in the template. I never figured out good names for the property and pseudoclass though.
visited
would be my favorite. But I'm happy with whatever name is used. The question for me is how to handle this in virtualized controls like ListBox
and what happens if several buttons share the same URL and you want to mark all as visited
if one of these buttons where clicked. I personally think this should be a property in the ViewModel
, so the developer has full control over it.
Well, the point of making it a separate property was to allow apps direct control over showing the hyperlink as having been navigated to or not. I suppose an additional property to control this is needed to disable marking the link as visited on click if the app is truly managing it all.
Here are some quick notes based on latest discussion.
// Same as UWP/WinUI
public Uri NavigateUri { get; set; }
// Gets or sets a value indicating whether the navigate URI has already been visited.
// Remarks: When true, the hyperlink will change visual state to indicate the link has already been visited.
public bool IsUriVisited { get; set; }
// This property isn't needed. Auto-navigate will always be enabled if a NavigateUri is provided.
// Otherwise, no navigation will be done on click. However, the app may still set IsUriVisited to change pseudoclasses
// public bool IsAutoNavigateEnabled { get; set; }
// Pseudoclasses
":visited"
Note that this enables both automatic URI navigation and changing the control style accordingly -- or -- don't provide a NavigateUri and control everything through a view model with the IsUriVisited property. Best of both worlds.
I have added a new direct property: bool SetVisitedOnClick, to control whether the state should be managed by the control itself or by user.
I wonder if that property should be styled property in order to manage it for all controls
I wonder if that property should be styled property in order to manage it for all controls
Hmmm, let me think about it.
I have added a new direct property: bool SetVisitedOnClick, to control whether the state should be managed by the control itself or by user.
Is the property itself really necessary though? If state should be managed by the user then most of the time no NavigateUri will be provided and instead Click
will be used externally. That's why I decided there was no need for the 'AutoNavigateEnabled' property above. I realize controlling style state is slightly different but in practical use-cases I'm not sure it will be used much.
I would also make this a styled property though if it stays. "DirectProperty" in my mind is more for content -- and items lists -- that are never used in the styling system. We might want to set this new property in ControlTheme and style classes.
Finally, for bool
properties I try very hard to maintain the "Is" convention. IsVisitedAutoSet
or IsVisitedSetOnClick
are better names IMO (assuming the property stays of course).
Edit: All names ideas so far:
-
SetVisitedOnClick
-
IsVisitedAutoSet
-
IsVisitedSetOnClick
-
AutoSetVisited