Skip to content

Commit a47b51d

Browse files
Merge branch 'master' into fix/tabbedCommandBar
2 parents 2c8a1d6 + b2f8fcb commit a47b51d

File tree

9 files changed

+712
-36
lines changed

9 files changed

+712
-36
lines changed

Microsoft.Toolkit.Uwp.DeveloperTools/FocusTracker/FocusTracker.cs

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,19 @@ public partial class FocusTracker : Control
3434

3535
private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
3636
{
37-
var focusTracker = d as FocusTracker;
38-
39-
if (e.NewValue != null && (bool)e.NewValue)
37+
if (d is FocusTracker focusTracker)
4038
{
41-
focusTracker?.Start();
42-
}
43-
else
44-
{
45-
focusTracker?.Stop();
39+
if (e.NewValue != null && (bool)e.NewValue)
40+
{
41+
focusTracker.Start();
42+
}
43+
else
44+
{
45+
focusTracker.Stop();
46+
}
4647
}
4748
}
4849

49-
private DispatcherQueueTimer updateTimer;
5050
private TextBlock controlName;
5151
private TextBlock controlType;
5252
private TextBlock controlAutomationName;
@@ -69,32 +69,42 @@ public FocusTracker()
6969
DefaultStyleKey = typeof(FocusTracker);
7070
}
7171

72+
/// <summary>
73+
/// Update the visual state of the control when its template is changed.
74+
/// </summary>
75+
protected override void OnApplyTemplate()
76+
{
77+
controlName = GetTemplateChild("ControlName") as TextBlock;
78+
controlType = GetTemplateChild("ControlType") as TextBlock;
79+
controlAutomationName = GetTemplateChild("ControlAutomationName") as TextBlock;
80+
controlFirstParentWithName = GetTemplateChild("ControlFirstParentWithName") as TextBlock;
81+
}
82+
7283
private void Start()
7384
{
74-
if (updateTimer == null)
85+
// Get currently focused control once when we start
86+
if (Windows.Foundation.Metadata.ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot") && XamlRoot != null)
7587
{
76-
updateTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
77-
updateTimer.Tick += UpdateTimer_Tick;
88+
FocusOnControl(FocusManager.GetFocusedElement(XamlRoot) as FrameworkElement);
89+
}
90+
else
91+
{
92+
FocusOnControl(FocusManager.GetFocusedElement() as FrameworkElement);
7893
}
7994

80-
updateTimer.Start();
95+
// Then use FocusManager event from 1809 to listen to updates
96+
FocusManager.GotFocus += FocusManager_GotFocus;
8197
}
8298

8399
private void Stop()
84100
{
85-
updateTimer?.Stop();
101+
FocusManager.GotFocus -= FocusManager_GotFocus;
86102
ClearContent();
87103
}
88104

89-
/// <summary>
90-
/// Update the visual state of the control when its template is changed.
91-
/// </summary>
92-
protected override void OnApplyTemplate()
105+
private void FocusManager_GotFocus(object sender, FocusManagerGotFocusEventArgs e)
93106
{
94-
controlName = GetTemplateChild("ControlName") as TextBlock;
95-
controlType = GetTemplateChild("ControlType") as TextBlock;
96-
controlAutomationName = GetTemplateChild("ControlAutomationName") as TextBlock;
97-
controlFirstParentWithName = GetTemplateChild("ControlFirstParentWithName") as TextBlock;
107+
FocusOnControl(e.NewFocusedElement as FrameworkElement);
98108
}
99109

100110
private void ClearContent()
@@ -105,19 +115,8 @@ private void ClearContent()
105115
controlFirstParentWithName.Text = string.Empty;
106116
}
107117

108-
private void UpdateTimer_Tick(object sender, object e)
118+
private void FocusOnControl(FrameworkElement focusedControl)
109119
{
110-
FrameworkElement focusedControl;
111-
112-
if (Windows.Foundation.Metadata.ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot") && XamlRoot != null)
113-
{
114-
focusedControl = FocusManager.GetFocusedElement(XamlRoot) as FrameworkElement;
115-
}
116-
else
117-
{
118-
focusedControl = FocusManager.GetFocusedElement() as FrameworkElement;
119-
}
120-
121120
if (focusedControl == null)
122121
{
123122
ClearContent();

Microsoft.Toolkit.Uwp.SampleApp/App.xaml.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Threading.Tasks;
67
using Microsoft.Toolkit.Uwp.Helpers;
78
using Microsoft.Toolkit.Uwp.SampleApp.Common;
89
using Microsoft.Toolkit.Uwp.SampleApp.SamplePages;
@@ -163,7 +164,7 @@ private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
163164
/// </summary>
164165
/// <param name="sender">The source of the suspend request.</param>
165166
/// <param name="e">Details about the suspend request.</param>
166-
private void OnSuspending(object sender, SuspendingEventArgs e)
167+
private async void OnSuspending(object sender, SuspendingEventArgs e)
167168
{
168169
var deferral = e.SuspendingOperation.GetDeferral();
169170

@@ -179,7 +180,18 @@ private void OnSuspending(object sender, SuspendingEventArgs e)
179180
// ignore
180181
}
181182

182-
deferral.Complete();
183+
try
184+
{
185+
await Task.Delay(2000);
186+
}
187+
catch
188+
{
189+
// ignore
190+
}
191+
finally
192+
{
193+
deferral.Complete();
194+
}
183195
}
184196
}
185197
}

Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,5 +708,10 @@ public class GitRefObject
708708
[JsonPropertyName("sha")]
709709
public string Sha { get; set; }
710710
}
711+
712+
public override string ToString()
713+
{
714+
return $"SampleApp.Sample<{CategoryName}.{Subcategory}.{Name}>";
715+
}
711716
}
712717
}

Microsoft.Toolkit.Uwp.SampleApp/Properties/Default.rd.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,8 @@
2727
<!-- Add your application specific runtime directives here. -->
2828
<Type Name="Windows.UI.Xaml.Controls.Border" Dynamic="Required Public" />
2929

30+
<!-- Fix for https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/3883 -->
31+
<Type Name="Windows.UI.Xaml.Controls.TextBlock" Dynamic="Required Public" />
32+
3033
</Application>
3134
</Directives>

Microsoft.Toolkit.Uwp.UI/Extensions/UIElementExtensions.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using Windows.UI.Xaml;
66
using Windows.UI.Xaml.Hosting;
7+
using Point = Windows.Foundation.Point;
78

89
namespace Microsoft.Toolkit.Uwp.UI
910
{
@@ -44,5 +45,31 @@ private static void OnClipToBoundsPropertyChanged(DependencyObject d, Dependency
4445
visual.Clip = clipToBounds ? visual.Compositor.CreateInsetClip() : null;
4546
}
4647
}
48+
49+
/// <summary>
50+
/// Provides the distance in a <see cref="Point"/> from the passed in element to the element being called on.
51+
/// For instance, calling child.CoordinatesFrom(container) will return the position of the child within the container.
52+
/// Helper for <see cref="UIElement.TransformToVisual(UIElement)"/>.
53+
/// </summary>
54+
/// <param name="target">Element to measure distance.</param>
55+
/// <param name="parent">Starting parent element to provide coordinates from.</param>
56+
/// <returns><see cref="Point"/> containing difference in position of elements.</returns>
57+
public static Point CoordinatesFrom(this UIElement target, UIElement parent)
58+
{
59+
return target.TransformToVisual(parent).TransformPoint(default(Point));
60+
}
61+
62+
/// <summary>
63+
/// Provides the distance in a <see cref="Point"/> to the passed in element from the element being called on.
64+
/// For instance, calling container.CoordinatesTo(child) will return the position of the child within the container.
65+
/// Helper for <see cref="UIElement.TransformToVisual(UIElement)"/>.
66+
/// </summary>
67+
/// <param name="parent">Starting parent element to provide coordinates from.</param>
68+
/// <param name="target">Element to measure distance to.</param>
69+
/// <returns><see cref="Point"/> containing difference in position of elements.</returns>
70+
public static Point CoordinatesTo(this UIElement parent, UIElement target)
71+
{
72+
return target.TransformToVisual(parent).TransformPoint(default(Point));
73+
}
4774
}
4875
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using Microsoft.Toolkit.Uwp;
8+
using Microsoft.Toolkit.Uwp.UI;
9+
using Microsoft.Toolkit.Uwp.UI.Controls;
10+
using Microsoft.VisualStudio.TestTools.UnitTesting;
11+
using Windows.UI.Xaml;
12+
using Windows.UI.Xaml.Controls;
13+
using Windows.UI.Xaml.Markup;
14+
15+
namespace UnitTests.Extensions
16+
{
17+
[TestClass]
18+
public class Test_UIElementExtensions_Coordinates : VisualUITestBase
19+
{
20+
[TestCategory("UIElementExtensions")]
21+
[TestMethod]
22+
public async Task Test_UIElement_Extensions_CoordinatesTo()
23+
{
24+
await App.DispatcherQueue.EnqueueAsync(async () =>
25+
{
26+
var treeRoot = XamlReader.Load(@"<Page
27+
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
28+
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
29+
<Border x:Name=""Target"" Margin=""150,100,0,0""/>
30+
</Page>") as Page;
31+
32+
// Test Setup
33+
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
34+
35+
// Initialize Visual Tree
36+
await SetTestContentAsync(treeRoot);
37+
38+
// Main Test
39+
var border = treeRoot.FindDescendant("Target");
40+
41+
Assert.IsNotNull(border, "Expected to find something.");
42+
Assert.IsInstanceOfType(border, typeof(Border), "Didn't find expected typed element.");
43+
44+
var point = treeRoot.CoordinatesTo(border);
45+
46+
Assert.AreEqual(150, point.X);
47+
Assert.AreEqual(100, point.Y);
48+
49+
// And otherway
50+
point = border.CoordinatesTo(treeRoot);
51+
52+
Assert.AreEqual(-150, point.X);
53+
Assert.AreEqual(-100, point.Y);
54+
});
55+
}
56+
57+
[TestCategory("UIElementExtensions")]
58+
[TestMethod]
59+
public async Task Test_UIElement_Extensions_CoordinatesFrom()
60+
{
61+
await App.DispatcherQueue.EnqueueAsync(async () =>
62+
{
63+
var treeRoot = XamlReader.Load(@"<Page
64+
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
65+
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
66+
<Border x:Name=""Target"" Margin=""100,150,0,0""/>
67+
</Page>") as Page;
68+
69+
// Test Setup
70+
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
71+
72+
// Initialize Visual Tree
73+
await SetTestContentAsync(treeRoot);
74+
75+
// Main Test
76+
var border = treeRoot.FindDescendant("Target");
77+
78+
Assert.IsNotNull(border, "Expected to find something.");
79+
Assert.IsInstanceOfType(border, typeof(Border), "Didn't find expected typed element.");
80+
81+
var point = border.CoordinatesFrom(treeRoot);
82+
83+
Assert.AreEqual(100, point.X);
84+
Assert.AreEqual(150, point.Y);
85+
86+
// And Backwards
87+
point = treeRoot.CoordinatesFrom(border);
88+
89+
Assert.AreEqual(-100, point.X);
90+
Assert.AreEqual(-150, point.Y);
91+
});
92+
}
93+
}
94+
}

0 commit comments

Comments
 (0)