diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/Given_HyperlinkButton.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/Given_HyperlinkButton.cs
new file mode 100644
index 000000000000..4c8e023e5cc5
--- /dev/null
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/Given_HyperlinkButton.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Private.Infrastructure;
+using Windows.UI.Text;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+
+namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls.HyperlinkButtonTests
+{
+ [TestClass]
+ public class Given_HyperlinkButton
+ {
+ [TestMethod]
+ [RunsOnUIThread]
+ public async Task When_HyperlinkButton_With_Implicit_Content_Should_Be_UnderlinedAsync()
+ {
+ var SUT = new HyperlinkButtonPage();
+ TestServices.WindowHelper.WindowContent = SUT;
+ await TestServices.WindowHelper.WaitForIdle();
+
+ var underlinedImplicitTextBlock = VisualTreeHelper.GetChild(SUT.ShouldBeUnderlinedHyperlinkButton.GetTemplateChild("ContentPresenter"), 0) as TextBlock;
+ Assert.IsInstanceOfType(underlinedImplicitTextBlock, typeof(ImplicitTextBlock));
+ Assert.AreEqual(TextDecorations.Underline, underlinedImplicitTextBlock.TextDecorations);
+
+ var notUnderlinedTextBlock = VisualTreeHelper.GetChild(SUT.ShouldNotBeUnderlinedHyperlinkButton.GetTemplateChild("ContentPresenter"), 0) as TextBlock;
+ Assert.IsNotInstanceOfType(notUnderlinedTextBlock, typeof(ImplicitTextBlock));
+ Assert.AreEqual(TextDecorations.None, notUnderlinedTextBlock.TextDecorations);
+ }
+ }
+}
diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/HyperlinkButtonPage.xaml b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/HyperlinkButtonPage.xaml
new file mode 100644
index 000000000000..f44ff3b14754
--- /dev/null
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/HyperlinkButtonPage.xaml
@@ -0,0 +1,17 @@
+
+
+
+ Should be underlined text
+
+ Shouldn't be underlined text
+
+
+
diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/HyperlinkButtonPage.xaml.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/HyperlinkButtonPage.xaml.cs
new file mode 100644
index 000000000000..38982bc121a0
--- /dev/null
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HyperlinkButtonTests/HyperlinkButtonPage.xaml.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
+
+namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls.HyperlinkButtonTests
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class HyperlinkButtonPage : Page
+ {
+ public HyperlinkButton ShouldBeUnderlinedHyperlinkButton => ShouldBeUnderlined_HyperlinkButton;
+ public HyperlinkButton ShouldNotBeUnderlinedHyperlinkButton => ShouldNotBeUnderlined_HyperlinkButton;
+ public TextBlock ShouldNotBeUnderlinedTextBlock => ShouldNotBeUnderlined_TextBlock;
+
+ public HyperlinkButtonPage()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
diff --git a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj
index f01beed1a1bf..7aebf99eac8f 100644
--- a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj
+++ b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj
@@ -112,6 +112,14 @@
+
+
+
+
+
+
+
+
diff --git a/src/Uno.UI/UI/Xaml/Controls/Button/HyperlinkButton.cs b/src/Uno.UI/UI/Xaml/Controls/Button/HyperlinkButton.cs
index 32b72ce0f711..7c4fa6dac48c 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Button/HyperlinkButton.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Button/HyperlinkButton.cs
@@ -19,9 +19,26 @@ public HyperlinkButton()
DefaultStyleKey = typeof(HyperlinkButton);
}
- ///
- /// Gets or sets the Uniform Resource Identifier (URI) to navigate to when the HyperlinkButton is clicked.
- ///
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ // This differs from UWP, where it looks for a template child named "ContentPresenter",
+ // but ultimately sets the underline on the TextBlock of the first ContentPresenter with a {TemplateBinding Content}.
+ // UWP also doesn't seem to do this in OnApplyTemplate (it's done between the first Measure and the first Arrange).
+ if (GetTemplateChild("ContentPresenter") is ContentPresenter contentPresenter)
+ {
+ // Forces ContentPresenter to materialize its template.
+ contentPresenter.Measure(new Size(0, 0));
+ if (VisualTreeHelper.GetChildrenCount(contentPresenter) == 1 && VisualTreeHelper.GetChild(contentPresenter, 0) is ImplicitTextBlock textBlock)
+ {
+ textBlock.TextDecorations = Windows.UI.Text.TextDecorations.Underline;
+ }
+ }
+ }
+
+ #region NavigateUri
+
public Uri NavigateUri
{
get => (Uri)GetValue(NavigateUriProperty);