Browse Source
* Add initial HyperlinkButton control * Remove IsVisitedOnClickProperty * Update HyperlinkButton control theme * Add work-around for HyperlinkButton text underlines * Enable Launcher in HyperlinkButton * Add simple control theme for HyperlinkButton * Fix HyperlinkButton :visited selector * Correct set TextDecorations attached property * Improve HyperlinkButton control themes * Fix reversed accent colorspull/14564/head
committed by
GitHub
8 changed files with 312 additions and 1 deletions
@ -0,0 +1,95 @@ |
|||
using System; |
|||
using Avalonia.Controls.Metadata; |
|||
using Avalonia.Platform.Storage; |
|||
using Avalonia.Threading; |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// A button control that functions as a navigateable hyperlink.
|
|||
/// </summary>
|
|||
[PseudoClasses(pcVisited)] |
|||
public class HyperlinkButton : Button |
|||
{ |
|||
// See: https://www.w3schools.com/cssref/sel_visited.php
|
|||
private const string pcVisited = ":visited"; |
|||
|
|||
/// <summary>
|
|||
/// Defines the <see cref="IsVisited"/> property.
|
|||
/// </summary>
|
|||
public static readonly StyledProperty<bool> IsVisitedProperty = |
|||
AvaloniaProperty.Register<HyperlinkButton, bool>( |
|||
nameof(IsVisited), |
|||
defaultValue: false); |
|||
|
|||
/// <summary>
|
|||
/// Defines the <see cref="NavigateUri"/> property.
|
|||
/// </summary>
|
|||
public static readonly StyledProperty<Uri?> NavigateUriProperty = |
|||
AvaloniaProperty.Register<HyperlinkButton, Uri?>( |
|||
nameof(NavigateUri), |
|||
defaultValue: null); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HyperlinkButton"/> class.
|
|||
/// </summary>
|
|||
public HyperlinkButton() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether the <see cref="NavigateUri"/> has been visited.
|
|||
/// </summary>
|
|||
public bool IsVisited |
|||
{ |
|||
get => GetValue(IsVisitedProperty); |
|||
set => SetValue(IsVisitedProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the Uniform Resource Identifier (URI) automatically navigated to when the
|
|||
/// <see cref="HyperlinkButton"/> is clicked.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The URI may be any website or file location that can be launched using the <see cref="ILauncher"/> service.
|
|||
/// <br/><br/>
|
|||
/// If a URI should not be automatically launched, leave this property unset and use the
|
|||
/// <see cref="Button.Click"/> and <see cref="IsVisited"/> members directly.
|
|||
/// </remarks>
|
|||
public Uri? NavigateUri |
|||
{ |
|||
get => GetValue(NavigateUriProperty); |
|||
set => SetValue(NavigateUriProperty, value); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) |
|||
{ |
|||
base.OnPropertyChanged(change); |
|||
|
|||
if (change.Property == HyperlinkButton.IsVisitedProperty) |
|||
{ |
|||
PseudoClasses.Set(pcVisited, change.GetNewValue<bool>()); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnClick() |
|||
{ |
|||
base.OnClick(); |
|||
|
|||
Uri? uri = NavigateUri; |
|||
if (uri is not null) |
|||
{ |
|||
Dispatcher.UIThread.Post(async () => |
|||
{ |
|||
bool success = await TopLevel.GetTopLevel(this)!.Launcher.LaunchUriAsync(uri); |
|||
if (success) |
|||
{ |
|||
SetCurrentValue(IsVisitedProperty, true); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
<ResourceDictionary xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:ClassModifier="internal"> |
|||
|
|||
<Design.PreviewWith> |
|||
<Border Padding="20"> |
|||
<StackPanel Spacing="20"> |
|||
<HyperlinkButton Content="Click Me!" /> |
|||
</StackPanel> |
|||
</Border> |
|||
</Design.PreviewWith> |
|||
|
|||
<Thickness x:Key="HyperlinkButtonBorderThemeThickness">1</Thickness> |
|||
|
|||
<ControlTheme x:Key="{x:Type HyperlinkButton}" TargetType="HyperlinkButton"> |
|||
<Setter Property="Cursor" Value="Hand" /> |
|||
<Setter Property="Background" Value="{DynamicResource HyperlinkButtonBackground}" /> |
|||
<Setter Property="BackgroundSizing" Value="OuterBorderEdge" /> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForeground}" /> |
|||
<Setter Property="BorderBrush" Value="{DynamicResource HyperlinkButtonBorderBrush}" /> |
|||
<Setter Property="BorderThickness" Value="{DynamicResource HyperlinkButtonBorderThemeThickness}" /> |
|||
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" /> |
|||
<Setter Property="Padding" Value="{DynamicResource ButtonPadding}" /> |
|||
<Setter Property="HorizontalAlignment" Value="Left" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
<Setter Property="RenderTransform" Value="none" /> |
|||
<Setter Property="TextBlock.TextDecorations" Value="Underline" /> |
|||
<Setter Property="Transitions"> |
|||
<Transitions> |
|||
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:.075" /> |
|||
</Transitions> |
|||
</Setter> |
|||
|
|||
<Setter Property="Template"> |
|||
<ControlTemplate> |
|||
<ContentPresenter x:Name="PART_ContentPresenter" |
|||
Background="{TemplateBinding Background}" |
|||
BackgroundSizing="{TemplateBinding BackgroundSizing}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
CornerRadius="{TemplateBinding CornerRadius}" |
|||
Content="{TemplateBinding Content}" |
|||
ContentTemplate="{TemplateBinding ContentTemplate}" |
|||
Padding="{TemplateBinding Padding}" |
|||
RecognizesAccessKey="True" |
|||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" |
|||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" /> |
|||
</ControlTemplate> |
|||
</Setter> |
|||
|
|||
<Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Background" Value="{DynamicResource HyperlinkButtonBackgroundPointerOver}" /> |
|||
<Setter Property="BorderBrush" Value="{DynamicResource HyperlinkButtonBorderBrushPointerOver}" /> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundPointerOver}" /> |
|||
</Style> |
|||
|
|||
<Style Selector="^:pressed"> |
|||
<Setter Property="RenderTransform" Value="scale(0.98)" /> |
|||
</Style> |
|||
|
|||
<Style Selector="^:pressed /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Background" Value="{DynamicResource HyperlinkButtonBackgroundPressed}" /> |
|||
<Setter Property="BorderBrush" Value="{DynamicResource HyperlinkButtonBorderBrushPressed}" /> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundPressed}" /> |
|||
</Style> |
|||
|
|||
<Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Background" Value="{DynamicResource HyperlinkButtonBackgroundDisabled}" /> |
|||
<Setter Property="BorderBrush" Value="{DynamicResource HyperlinkButtonBorderBrushDisabled}" /> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundDisabled}" /> |
|||
</Style> |
|||
|
|||
<Style Selector="^:visited"> |
|||
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundVisited}" /> |
|||
</Style> |
|||
|
|||
<Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundVisitedPointerOver}" /> |
|||
</Style> |
|||
|
|||
<Style Selector="^:pressed /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkButtonForegroundVisitedPressed}" /> |
|||
</Style> |
|||
</Style> |
|||
|
|||
</ControlTheme> |
|||
</ResourceDictionary> |
|||
@ -0,0 +1,51 @@ |
|||
<ResourceDictionary xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:ClassModifier="internal"> |
|||
|
|||
<Design.PreviewWith> |
|||
<Border Padding="20"> |
|||
<StackPanel Spacing="20"> |
|||
<HyperlinkButton Content="Click Me!" /> |
|||
</StackPanel> |
|||
</Border> |
|||
</Design.PreviewWith> |
|||
|
|||
<ControlTheme x:Key="{x:Type HyperlinkButton}" TargetType="HyperlinkButton"> |
|||
<Setter Property="Cursor" Value="Hand" /> |
|||
<Setter Property="Background" Value="Transparent" /> |
|||
<Setter Property="BackgroundSizing" Value="OuterBorderEdge" /> |
|||
<Setter Property="Foreground" Value="{DynamicResource ThemeAccentBrush}" /> |
|||
<Setter Property="BorderBrush" Value="Transparent" /> |
|||
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}" /> |
|||
<Setter Property="Padding" Value="4" /> |
|||
<Setter Property="HorizontalAlignment" Value="Left" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
<Setter Property="TextBlock.TextDecorations" Value="Underline" /> |
|||
|
|||
<Setter Property="Template"> |
|||
<ControlTemplate> |
|||
<ContentPresenter x:Name="PART_ContentPresenter" |
|||
Background="{TemplateBinding Background}" |
|||
BackgroundSizing="{TemplateBinding BackgroundSizing}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
CornerRadius="{TemplateBinding CornerRadius}" |
|||
Content="{TemplateBinding Content}" |
|||
ContentTemplate="{TemplateBinding ContentTemplate}" |
|||
Padding="{TemplateBinding Padding}" |
|||
RecognizesAccessKey="True" |
|||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" |
|||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" /> |
|||
</ControlTemplate> |
|||
</Setter> |
|||
|
|||
<Style Selector="^:disabled"> |
|||
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" /> |
|||
</Style> |
|||
|
|||
<Style Selector="^:visited /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Foreground" Value="{DynamicResource HyperlinkVisitedBrush}" /> |
|||
</Style> |
|||
|
|||
</ControlTheme> |
|||
</ResourceDictionary> |
|||
Loading…
Reference in new issue