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

TeachingTip: Pressing F6 now sets focus on custom content of light-dismissable tip #3545

26 changes: 25 additions & 1 deletion dev/TeachingTip/InteractionTests/TeachingTipTestPageElements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ public TextBlock GetPopupVerticalOffsetTextBlock()
}
private TextBlock popupVerticalOffsetTextBlock;

public ComboBox GetContentComboBox()
{
return GetElement(ref contentComboBox, "ContentComboBox");
}
private ComboBox contentComboBox;

public Button GetSetContentButton()
{
return GetElement(ref setContentButton, "SetContentButton");
}
private Button setContentButton;

public ComboBox GetHeroContentComboBox()
{
return GetElement(ref heroContentComboBox, "HeroContentComboBox");
Expand Down Expand Up @@ -483,14 +495,26 @@ public enum PlacementOptions
Auto
}

public enum HeroContentOptions
public enum ContentOptions
{
RedSquare,
BlueSquare,
Image,
AutoSaveImage,
ShortText,
LongText,
Button,
NoContent
}

public enum HeroContentOptions
{
RedSquare,
BlueSquare,
Image,
NoContent
}

public enum TitleContentOptions
{
No,
Expand Down
96 changes: 90 additions & 6 deletions dev/TeachingTip/InteractionTests/TeachingTipTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public void TestCleanup()
TestCleanupHelper.Cleanup();
}


[TestMethod]
public void CloseReasonIsAccurate()
{
Expand Down Expand Up @@ -693,7 +692,6 @@ public void SpecifiedPlacementRTL()
}
}


[TestMethod]
public void NoIconDoesNotCrash()
{
Expand All @@ -718,7 +716,6 @@ public void NoIconDoesNotCrash()
}
}


[TestMethod]
public void CanSwitchShouldConstrainToRootBounds()
{
Expand Down Expand Up @@ -752,7 +749,6 @@ public void CanSwitchShouldConstrainToRootBounds()
}
}


[TestMethod]
public void TipsWhichDoNotFitDoNotOpen()
{
Expand All @@ -768,7 +764,6 @@ public void TipsWhichDoNotFitDoNotOpen()
ScrollBy(10);
UseTestWindowBounds(10, 10, 10, 10);


elements.GetShowButton().InvokeAndWait();

var message1 = GetTeachingTipDebugMessage(1);
Expand All @@ -787,7 +782,6 @@ public void TipsWhichDoNotFitDoNotOpen()
}
}


[TestMethod]
public void VerifyTheming()
{
Expand Down Expand Up @@ -1010,6 +1004,47 @@ void EnableLightDismiss()
}
}

[TestMethod]
public void F6PutsFocusOnContentIfNoCloseButton()
{
using (var setup = new TestSetupHelper(new[] { "TeachingTip Tests", "TeachingTip Test" }))
{
elements = new TeachingTipTestPageElements();
ScrollTargetIntoView();

ClearTeachingTipDebugMessages();

// A light-dismissable teaching tip has no close button.
EnableLightDismiss(true);

// Configure the teaching tip so that it only has one focusable child element - a content button.
SetContent(ContentOptions.Button);
SetHeroContent(HeroContentOptions.NoContent);

OpenTeachingTip();

Log.Comment("Set focus on custom button by pressing F6.");
KeyboardHelper.PressKey(Key.F6);

var message = GetTeachingTipDebugMessage(0);
Verify.IsTrue(message.ToString().Contains("Content Button GotKeyboardFocus Event"));

Log.Comment("Set focus back to teaching tip by pressing F6 again.");
KeyboardHelper.PressKey(Key.F6);

message = GetTeachingTipDebugMessage(1);
Verify.IsTrue(message.ToString().Contains("Content Button LostFocus Event"));

Log.Comment("Verify teaching tip is still open.");
WaitAndVerifyIfCheckStateUnchanged(elements.GetIsOpenCheckBox(), ToggleState.On);

Log.Comment("Close teaching tip by pressing Esc.");
KeyboardHelper.PressKey(Key.Escape);

WaitForTipClosed();
}
}

private void CloseOpenAndCloseWithJustKeyboardViaF6()
{
KeyboardHelper.PressKey(Key.F6);
Expand Down Expand Up @@ -1215,6 +1250,39 @@ private void SetPreferredPlacement(PlacementOptions placement)
elements.GetSetPreferredPlacementButton().InvokeAndWait();
}

private void SetContent(ContentOptions content)
{
switch (content)
{
case ContentOptions.RedSquare:
elements.GetContentComboBox().SelectItemByName("Red Square");
break;
case ContentOptions.BlueSquare:
elements.GetContentComboBox().SelectItemByName("Blue Square");
break;
case ContentOptions.Image:
elements.GetContentComboBox().SelectItemByName("Image");
break;
case ContentOptions.AutoSaveImage:
elements.GetContentComboBox().SelectItemByName("AutoSave Image");
break;
case ContentOptions.ShortText:
elements.GetContentComboBox().SelectItemByName("Short Text");
break;
case ContentOptions.LongText:
elements.GetContentComboBox().SelectItemByName("Long Text");
break;
case ContentOptions.Button:
elements.GetContentComboBox().SelectItemByName("Button");
break;
default:
elements.GetContentComboBox().SelectItemByName("No Content");
break;
}

elements.GetSetContentButton().InvokeAndWait();
}

private void SetHeroContent(HeroContentOptions heroContent)
{
switch (heroContent)
Expand Down Expand Up @@ -1561,5 +1629,21 @@ private bool WaitForOffsetToSettle(Edit text, double millisecondsTimeout, bool f
return false;
}
}

private bool WaitAndVerifyIfCheckStateUnchanged(CheckBox checkBox, ToggleState state, double millisecondsTimeout = 2000)
{
using (UIEventWaiter waiter = checkBox.GetToggledWaiter())
{
if (checkBox.ToggleState != state)
{
return false;
}

Log.Comment($"Waiting for {millisecondsTimeout}ms after which a toggle state change would have typically occured", millisecondsTimeout);
waiter.TryWait(TimeSpan.FromMilliseconds(millisecondsTimeout));

return checkBox.ToggleState == state;
}
}
}
}
23 changes: 17 additions & 6 deletions dev/TeachingTip/TeachingTip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ void TeachingTip::OnApplyTemplate()
m_contentRootGrid.set(GetTemplateChildT<winrt::Grid>(s_contentRootGridName, controlProtected));
m_nonHeroContentRootGrid.set(GetTemplateChildT<winrt::Grid>(s_nonHeroContentRootGridName, controlProtected));
m_heroContentBorder.set(GetTemplateChildT<winrt::Border>(s_heroContentBorderName, controlProtected));
m_mainContentPresenter.set(GetTemplateChildT<winrt::ContentPresenter>(s_mainContentPresenterName, controlProtected));
m_actionButton.set(GetTemplateChildT<winrt::Button>(s_actionButtonName, controlProtected));
m_alternateCloseButton.set(GetTemplateChildT<winrt::Button>(s_alternateCloseButtonName, controlProtected));
m_closeButton.set(GetTemplateChildT<winrt::Button>(s_closeButtonName, controlProtected));
Expand Down Expand Up @@ -1100,7 +1101,7 @@ void TeachingTip::OnF6AcceleratorKeyClicked(const winrt::CoreDispatcher&, const
}
else
{
const winrt::Button f6Button = [this]() -> winrt::Button
const winrt::DependencyObject f6FocusableElement = [this]() -> winrt::DependencyObject
{
auto firstButton = m_closeButton.get();
auto secondButton = m_alternateCloseButton.get();
Expand All @@ -1117,15 +1118,25 @@ void TeachingTip::OnF6AcceleratorKeyClicked(const winrt::CoreDispatcher&, const
{
return secondButton;
}
// If there is no close button, try setting focus on the tip's custom content.
else if (const auto mainContentPresenter = m_mainContentPresenter.get())
{
return winrt::FocusManager::FindFirstFocusableElement(mainContentPresenter);
}
return nullptr;
}();

if (f6Button)
if (f6FocusableElement)
{
auto const scopedRevoker = f6Button.GettingFocus(winrt::auto_revoke, [this](auto const&, auto const& args) {
m_previouslyFocusedElement = winrt::make_weak(args.OldFocusedElement());
});
const bool setFocus = f6Button.Focus(winrt::FocusState::Keyboard);
const auto previouslyFocusedElement = winrt::FocusManager::GetFocusedElement();
const bool setFocus = SetFocus(f6FocusableElement, winrt::FocusState::Keyboard);
if (setFocus)
{
if (const auto previouslyFocusedElementAsDO = previouslyFocusedElement.try_as<winrt::DependencyObject>())
{
m_previouslyFocusedElement = winrt::make_weak(previouslyFocusedElementAsDO);
}
}
args.Handled(setFocus);
}
}
Expand Down
1 change: 1 addition & 0 deletions dev/TeachingTip/TeachingTip.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class TeachingTip :
tracker_ref<winrt::Grid> m_contentRootGrid{ this };
tracker_ref<winrt::Grid> m_nonHeroContentRootGrid{ this };
tracker_ref<winrt::Border> m_heroContentBorder{ this };
tracker_ref<winrt::ContentPresenter> m_mainContentPresenter{ this };
tracker_ref<winrt::Button> m_actionButton{ this };
tracker_ref<winrt::Button> m_alternateCloseButton{ this };
tracker_ref<winrt::Button> m_closeButton{ this };
Expand Down
25 changes: 13 additions & 12 deletions dev/TeachingTip/TestUI/TeachingTipPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
<ScrollViewer x:Name="ContentScrollViewer">
<StackPanel x:Name="ContentStackPanel">
<Grid Background="Green" Width="100" Height="1000"/>
<muxc:TeachingTip x:Name="TeachingTipInVisualTree"
AutomationProperties.Name="TeachingTipInVisualTree"
Title="We've Added Auto Saving!"
Subtitle="Documents will now automatically save to OneDrive."
Closed="OnTeachingTipClosed"
Closing="OnTeachingTipClosing"
ActionButtonClick="OnTeachingTipActionButtonClicked"
CloseButtonClick="OnTeachingTipCloseButtonClicked"
Target="{x:Bind targetButton}">
<muxc:TeachingTip x:Name="TeachingTipInVisualTree"
AutomationProperties.Name="TeachingTipInVisualTree"
Title="We've Added Auto Saving!"
Subtitle="Documents will now automatically save to OneDrive."
Closed="OnTeachingTipClosed"
Closing="OnTeachingTipClosing"
ActionButtonClick="OnTeachingTipActionButtonClicked"
CloseButtonClick="OnTeachingTipCloseButtonClicked"
Target="{x:Bind targetButton}">
<muxc:TeachingTip.IconSource>
<muxc:SymbolIconSource Symbol="People"/>
</muxc:TeachingTip.IconSource>
Expand Down Expand Up @@ -183,16 +183,17 @@
<Button AutomationProperties.Name="SetSubtitleButton" Click="OnSetSubtitleButtonClicked" Grid.Row="9" Grid.Column="1">Set</Button>

<TextBlock Grid.Row="10" Text="Content:" Foreground="Red"/>
<ComboBox x:Name="ContentComboBox" Grid.Row="11">
<ComboBox x:Name="ContentComboBox" AutomationProperties.Name="ContentComboBox" Grid.Row="11">
<ComboBoxItem x:Name="ContentRedSquare">Red Square</ComboBoxItem>
<ComboBoxItem x:Name="ContentBlueSquare">Blue Square</ComboBoxItem>
<ComboBoxItem x:Name="ContentImage">Image</ComboBoxItem>
<ComboBoxItem x:Name="ContentShort">Short Text</ComboBoxItem>
<ComboBoxItem x:Name="ContentLong">Long Text</ComboBoxItem>
<ComboBoxItem x:Name="ContentAutoSave">AutoSaveImage</ComboBoxItem>
<ComboBoxItem x:Name="ContentAutoSave">AutoSave Image</ComboBoxItem>
<ComboBoxItem x:Name="ContentButton">Button</ComboBoxItem>
<ComboBoxItem x:Name="ContentNo">No Content</ComboBoxItem>
</ComboBox>
<Button Click="OnSetContentButtonClicked" Grid.Row="11" Grid.Column="1">Set</Button>
<Button AutomationProperties.Name="SetContentButton" Click="OnSetContentButtonClicked" Grid.Row="11" Grid.Column="1">Set</Button>

<TextBlock Grid.Row="12" Text="ActionButtonContent:" Foreground="Red"/>
<ComboBox x:Name="ActionButtonContentComboBox" SelectedIndex="0" Grid.Row="13">
Expand Down
46 changes: 30 additions & 16 deletions dev/TeachingTip/TestUI/TeachingTipPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ public void OnSetIconButtonClicked(object sender, RoutedEventArgs args)
SymbolIconSource symbolIconSource = new SymbolIconSource();
symbolIconSource.Symbol = Symbol.People;
getTeachingTip().IconSource = symbolIconSource;

}
else
{
Expand Down Expand Up @@ -325,6 +324,23 @@ public void OnSetContentButtonClicked(object sender, RoutedEventArgs args)
image.Source = bitmapImage;
getTeachingTip().Content = image;
}
else if (this.ContentComboBox.SelectedItem == ContentButton)
{
Button button = new Button() { Content = "Content Button" };
button.GotFocus += (s, e) =>
{
if (button.FocusState == FocusState.Keyboard)
{
AddToMessageBoard("Content Button GotKeyboardFocus Event");
}
};
button.LostFocus += (s, e) => AddToMessageBoard("Content Button LostFocus Event");

StackPanel panel = new StackPanel() { Orientation = Orientation.Horizontal };
panel.Children.Add(button);

getTeachingTip().Content = panel;
}
else
{
getTeachingTip().Content = null;
Expand Down Expand Up @@ -828,20 +844,12 @@ public void OnTipShadowUnchecked(object sender, RoutedEventArgs args)

public void OnTeachingTipClosed(object sender, TeachingTipClosedEventArgs args)
{
if (lstTeachingTipEvents != null)
{
lstTeachingTipEvents.Items.Add(lstTeachingTipEvents.Items.Count.ToString() + ") " + args.ToString() + " Reason: " + args.Reason.ToString());
lstTeachingTipEvents.ScrollIntoView(lstTeachingTipEvents.Items.Last<object>());
}
AddToMessageBoard(args.ToString() + " Reason: " + args.Reason.ToString());
}

public void OnTeachingTipClosing(TeachingTip sender, TeachingTipClosingEventArgs args)
{
if (lstTeachingTipEvents != null)
{
lstTeachingTipEvents.Items.Add(lstTeachingTipEvents.Items.Count.ToString() + ") " + args.ToString() + " Reason: " + args.Reason.ToString());
lstTeachingTipEvents.ScrollIntoView(lstTeachingTipEvents.Items.Last<object>());
}
AddToMessageBoard(args.ToString() + " Reason: " + args.Reason.ToString());

CheckBox cancelClosesCheckBox = null;
if (sender == TeachingTipInResources)
Expand Down Expand Up @@ -872,14 +880,21 @@ private void Timer_Tick(object sender, object e)

public void OnTeachingTipActionButtonClicked(object sender, object args)
{
lstTeachingTipEvents.Items.Add(lstTeachingTipEvents.Items.Count.ToString() + ") " + "Action Button Clicked Event");
lstTeachingTipEvents.ScrollIntoView(lstTeachingTipEvents.Items.Last<object>());
AddToMessageBoard("Action Button Clicked Event");
}

public void OnTeachingTipCloseButtonClicked(object sender, object args)
{
lstTeachingTipEvents.Items.Add(lstTeachingTipEvents.Items.Count.ToString() + ") " + "Close Button Clicked Event");
lstTeachingTipEvents.ScrollIntoView(lstTeachingTipEvents.Items.Last<object>());
AddToMessageBoard("Close Button Clicked Event");
}

private void AddToMessageBoard(string message)
{
if (lstTeachingTipEvents != null)
{
lstTeachingTipEvents.Items.Add(lstTeachingTipEvents.Items.Count.ToString() + ") " + message);
lstTeachingTipEvents.ScrollIntoView(lstTeachingTipEvents.Items.Last<object>());
}
}

private void BtnClearTeachingTipEvents_Click(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -988,6 +1003,5 @@ private void RemoveOpenButton_Click(object sender, RoutedEventArgs e)
{
ContentStackPanel.Children.Remove(targetButton);
}

}
}