Merge branch 'main' into shweaver/storage-helpers
This commit is contained in:
Коммит
18690395e0
|
@ -271,44 +271,46 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.Controls
|
|||
else if (firstInline is TextRunInline textRunInline)
|
||||
{
|
||||
var key = textRunInline.Text.Split(' ').FirstOrDefault();
|
||||
if (styles.TryGetValue(key, out var style) && !style.Ignore)
|
||||
if (styles.TryGetValue(key, out var style))
|
||||
{
|
||||
noteType = style;
|
||||
header = style.IdentifierReplacement;
|
||||
symbolGlyph = style.Glyph;
|
||||
|
||||
// Removes the identifier from the text
|
||||
textRunInline.Text = textRunInline.Text.Replace(key, string.Empty);
|
||||
|
||||
if (theme == ElementTheme.Light)
|
||||
if (!style.Ignore)
|
||||
{
|
||||
localForeground = style.LightForeground;
|
||||
localBackground = style.LightBackground;
|
||||
noteType = style;
|
||||
header = style.IdentifierReplacement;
|
||||
symbolGlyph = style.Glyph;
|
||||
|
||||
// Removes the identifier from the text
|
||||
textRunInline.Text = textRunInline.Text.Replace(key, string.Empty);
|
||||
|
||||
if (theme == ElementTheme.Light)
|
||||
{
|
||||
localForeground = style.LightForeground;
|
||||
localBackground = style.LightBackground;
|
||||
}
|
||||
else
|
||||
{
|
||||
localForeground = new SolidColorBrush(Colors.White);
|
||||
localBackground = style.DarkBackground;
|
||||
}
|
||||
|
||||
// Apply special formatting context.
|
||||
if (noteType != null)
|
||||
{
|
||||
if (localContext?.Clone() is UIElementCollectionRenderContext newContext)
|
||||
{
|
||||
localContext = newContext;
|
||||
|
||||
localContext.TrimLeadingWhitespace = true;
|
||||
QuoteForeground = Foreground;
|
||||
LinkForeground = localForeground;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
localForeground = new SolidColorBrush(Colors.White);
|
||||
localBackground = style.DarkBackground;
|
||||
// Blank entire block
|
||||
textRunInline.Text = string.Empty;
|
||||
}
|
||||
|
||||
// Apply special formatting context.
|
||||
if (noteType != null)
|
||||
{
|
||||
if (localContext?.Clone() is UIElementCollectionRenderContext newContext)
|
||||
{
|
||||
localContext = newContext;
|
||||
|
||||
localContext.TrimLeadingWhitespace = true;
|
||||
QuoteForeground = Foreground;
|
||||
LinkForeground = localForeground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (style.Ignore)
|
||||
{
|
||||
// Blank entire block
|
||||
textRunInline.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,29 +4,37 @@
|
|||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPointerOver" Color="{ThemeResource SystemBaseLowColor}" />
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPressed" Color="{ThemeResource SystemBaseHighColor}" />
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPointerOver"
|
||||
Color="{ThemeResource SystemBaseLowColor}" />
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPressed"
|
||||
Color="{ThemeResource SystemBaseHighColor}" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPointerOver" Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPressed" Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="SystemControlSplitterPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style TargetType="local:GridSplitter">
|
||||
<Setter Property="IsTabStop" Value="True"></Setter>
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True"></Setter>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
|
||||
<Setter Property="VerticalAlignment" Value="Stretch"></Setter>
|
||||
<Setter Property="IsFocusEngagementEnabled" Value="True"></Setter>
|
||||
<Setter Property="MinWidth" Value="16"></Setter>
|
||||
<Setter Property="MinHeight" Value="16"></Setter>
|
||||
<Setter Property="Background" Value="{ThemeResource SystemControlHighlightChromeHighBrush}"></Setter>
|
||||
<Setter Property="IsTabStop" Value="True" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="IsFocusEngagementEnabled" Value="True" />
|
||||
<Setter Property="MinWidth" Value="16" />
|
||||
<Setter Property="MinHeight" Value="16" />
|
||||
<Setter Property="Background" Value="{ThemeResource SystemControlHighlightChromeHighBrush}" />
|
||||
<Setter Property="GripperForeground" Value="{ThemeResource SystemControlForegroundAltHighBrush}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:GridSplitter">
|
||||
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
|
||||
<Grid x:Name="RootGrid"
|
||||
Background="{TemplateBinding Background}">
|
||||
<ContentPresenter HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
Content="{TemplateBinding Element}" />
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="GridSplitterStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
|
@ -42,7 +50,6 @@
|
|||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<ContentPresenter Content="{TemplateBinding Element}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Toolkit.Mvvm.Messaging;
|
||||
using UITests.App.Pages;
|
||||
|
@ -49,6 +50,8 @@ namespace UITests.App
|
|||
return;
|
||||
}
|
||||
|
||||
Log.Comment("Received Command: {0}", cmd);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case "OpenPage":
|
||||
|
@ -65,6 +68,44 @@ namespace UITests.App
|
|||
|
||||
await args.Request.SendResponseAsync(pageResponse ? OkResult : BadResult);
|
||||
|
||||
break;
|
||||
case "Custom":
|
||||
if (!TryGetValueAndLog(message, "Id", out var id) || !_customCommands.ContainsKey(id))
|
||||
{
|
||||
await args.Request.SendResponseAsync(BadResult);
|
||||
break;
|
||||
}
|
||||
|
||||
Log.Comment("Received request for custom command: {0}", id);
|
||||
|
||||
try
|
||||
{
|
||||
ValueSet response = await _customCommands[id].Invoke(message);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
response.Add("Status", "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
await args.Request.SendResponseAsync(BadResult);
|
||||
break;
|
||||
}
|
||||
|
||||
await args.Request.SendResponseAsync(response);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ValueSet errmsg = new() { { "Status", "BAD" }, { "Exception", e.Message }, { "StackTrace", e.StackTrace } };
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
errmsg.Add("InnerException", e.InnerException.Message);
|
||||
errmsg.Add("InnerExceptionStackTrace", e.InnerException.StackTrace);
|
||||
}
|
||||
|
||||
await args.Request.SendResponseAsync(errmsg);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -77,11 +118,15 @@ namespace UITests.App
|
|||
|
||||
private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
|
||||
{
|
||||
Log.Error("Background Task Instance Canceled. Reason: {0}", reason.ToString());
|
||||
|
||||
_appServiceDeferral.Complete();
|
||||
}
|
||||
|
||||
private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
|
||||
{
|
||||
Log.Error("AppServiceConnection Service Closed. AppServicesClosedStatus: {0}", args.Status.ToString());
|
||||
|
||||
_appServiceDeferral.Complete();
|
||||
}
|
||||
|
||||
|
@ -118,5 +163,12 @@ namespace UITests.App
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Dictionary<string, Func<ValueSet, Task<ValueSet>>> _customCommands = new();
|
||||
|
||||
internal void RegisterCustomCommand(string id, Func<ValueSet, Task<ValueSet>> customCommandFunction)
|
||||
{
|
||||
_customCommands.Add(id, customCommandFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UITests.App.Commands;
|
||||
using UITests.App.Pages;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Toolkit;
|
||||
using Microsoft.Toolkit.Uwp;
|
||||
using Microsoft.Toolkit.Uwp.UI;
|
||||
using UITests.App.Pages;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace UITests.App.Commands
|
||||
{
|
||||
public static class VisualTreeHelperCommands
|
||||
{
|
||||
private static DispatcherQueue Queue { get; set; }
|
||||
|
||||
private static JsonSerializerOptions SerializerOptions { get; } = new JsonSerializerOptions(JsonSerializerDefaults.General)
|
||||
{
|
||||
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
|
||||
};
|
||||
|
||||
public static void Initialize(DispatcherQueue uiThread)
|
||||
{
|
||||
Queue = uiThread;
|
||||
|
||||
(App.Current as App).RegisterCustomCommand("VisualTreeHelper.FindElementProperty", FindElementProperty);
|
||||
}
|
||||
|
||||
public static async Task<ValueSet> FindElementProperty(ValueSet arguments)
|
||||
{
|
||||
ValueSet results = new ValueSet();
|
||||
|
||||
if (Queue == null)
|
||||
{
|
||||
Log.Error("VisualTreeHelper - Missing UI DispatcherQueue");
|
||||
return null;
|
||||
}
|
||||
|
||||
await Queue.EnqueueAsync(() =>
|
||||
{
|
||||
// Dispatch?
|
||||
var content = Window.Current.Content as Frame;
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
Log.Error("VisualTreeHelper.FindElementProperty - Window has no content.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (arguments.TryGetValue("ElementName", out object value) && value is string name &&
|
||||
arguments.TryGetValue("Property", out object value2) && value2 is string propertyName)
|
||||
{
|
||||
Log.Comment("VisualTreeHelper.FindElementProperty('{0}', '{1}')", name, propertyName);
|
||||
|
||||
// 1. Find Element in Visual Tree
|
||||
var element = content.FindDescendant(name);
|
||||
|
||||
try
|
||||
{
|
||||
Log.Comment("VisualTreeHelper.FindElementProperty - Found Element? {0}", element != null);
|
||||
|
||||
var typeinfo = element.GetType().GetTypeInfo();
|
||||
|
||||
Log.Comment("Element Type: {0}", typeinfo.FullName);
|
||||
|
||||
var prop = element.GetType().GetTypeInfo().GetProperty(propertyName);
|
||||
|
||||
if (prop == null)
|
||||
{
|
||||
Log.Error("VisualTreeHelper.FindElementProperty - Couldn't find Property named {0} on type {1}", propertyName, typeinfo.FullName);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Get the property using reflection
|
||||
var propValue = prop.GetValue(element);
|
||||
|
||||
// 3. Serialize and return the result
|
||||
results.Add("Result", JsonSerializer.Serialize(propValue, SerializerOptions));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Error {0}", e.Message);
|
||||
Log.Error("StackTrace:\n{0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (results.Count > 0)
|
||||
{
|
||||
return results;
|
||||
}
|
||||
|
||||
return null; // Failure
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ using System.Reflection;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Toolkit.Mvvm.Messaging;
|
||||
using Microsoft.Toolkit.Uwp;
|
||||
using UITests.App.Commands;
|
||||
using UITests.App.Pages;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
|
@ -33,6 +34,9 @@ namespace UITests.App
|
|||
WeakReferenceMessenger.Default.Register<RequestPageMessage>(this);
|
||||
|
||||
_queue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
// Initialize Custom Commands for AppService
|
||||
VisualTreeHelperCommands.Initialize(_queue);
|
||||
}
|
||||
|
||||
public void Receive(RequestPageMessage message)
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
IgnorableNamespaces="uap mp">
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap mp rescap">
|
||||
|
||||
<Identity
|
||||
Name="3568ebdf-5b6b-4ddd-bb17-462d614ba50f"
|
||||
|
@ -48,5 +49,7 @@
|
|||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<!-- Our AppService Background Connection will Timeout after a period of time otherwise. -->
|
||||
<rescap:Capability Name="extendedBackgroundTaskTime"/>
|
||||
</Capabilities>
|
||||
</Package>
|
|
@ -21,6 +21,8 @@
|
|||
the application package. The asterisks are not wildcards.
|
||||
-->
|
||||
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||
<Namespace Name="Windows.UI.Xaml.Controls" Dynamic="Required All" />
|
||||
<Namespace Name="Microsoft.UI.Xaml.Controls" Dynamic="Required All" />
|
||||
<!-- Add your application specific runtime directives here. -->
|
||||
</Application>
|
||||
</Directives>
|
|
@ -2,7 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace UITests.App.Pages
|
||||
|
@ -37,9 +37,13 @@ namespace UITests.App.Pages
|
|||
format = format.Replace("{", "{{").Replace("}", "}}");
|
||||
}
|
||||
|
||||
var message = string.Format(format, args);
|
||||
|
||||
Debug.WriteLine(message);
|
||||
|
||||
// Send back to Test Harness via AppService
|
||||
// TODO: Make this a cleaner connection/pattern
|
||||
((App)Application.Current).SendLogMessage(level, string.Format(format, args));
|
||||
_ = ((App)Application.Current).SendLogMessage(level, message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -132,6 +132,7 @@
|
|||
<Compile Include="App.AppService.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Commands\VisualTreeHelperCommands.cs" />
|
||||
<Compile Include="HomePage.xaml.cs">
|
||||
<DependentUpon>HomePage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -178,6 +179,9 @@
|
|||
<PackageReference Include="MUXAppTestHelpers">
|
||||
<Version>0.0.4</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Text.Json">
|
||||
<Version>5.0.2</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="UITests.App.pfx" />
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.5.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="Microsoft.Windows.Apps.Test" Version="1.0.181205002" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\UITests.Tests.Shared\UITests.Tests.Shared.projitems" Label="Shared" />
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.Windows.Apps.Test.Foundation;
|
||||
using Microsoft.Windows.Apps.Test.Foundation.Controls;
|
||||
using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Common;
|
||||
using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Infra;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System;
|
||||
|
||||
#if USING_TAEF
|
||||
using WEX.Logging.Interop;
|
||||
using WEX.TestExecution;
|
||||
using WEX.TestExecution.Markup;
|
||||
#else
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
#endif
|
||||
|
||||
namespace UITests.Tests
|
||||
{
|
||||
|
||||
[TestClass]
|
||||
public class GridSplitterTest : UITestBase
|
||||
{
|
||||
[ClassInitialize]
|
||||
[TestProperty("RunAs", "User")]
|
||||
[TestProperty("Classification", "ScenarioTestSuite")]
|
||||
[TestProperty("Platform", "Any")]
|
||||
public static void ClassInitialize(TestContext testContext)
|
||||
{
|
||||
TestEnvironment.Initialize(testContext, WinUICsUWPSampleApp);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[TestPage("GridSplitterTestPage")]
|
||||
public async Task TestGridSplitterDragHorizontalAsync()
|
||||
{
|
||||
var amount = 50;
|
||||
var tolerance = 10;
|
||||
|
||||
var grid = FindElement.ByName("GridSplitterRoot");
|
||||
var gridSplitter = FindElement.ById("GridSplitterHorizontal");
|
||||
var box = FindElement.ByName("TopLeftBox");
|
||||
|
||||
Verify.IsNotNull(grid, "Can't find GridSplitterRoot");
|
||||
Verify.IsNotNull(gridSplitter, "Can't find Horizontal GridSplitter");
|
||||
Verify.IsNotNull(box, "Can't find box");
|
||||
|
||||
var width = box.BoundingRectangle.Width;
|
||||
|
||||
ColumnDefinition columnDefinitionStart = (await VisualTreeHelper.FindElementPropertyAsync<List<ColumnDefinition>>("GridSplitterRoot", "ColumnDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Verify.IsNotNull(columnDefinitionStart, "Couldn't retrieve Column Definition");
|
||||
|
||||
// Drag to the Left
|
||||
InputHelper.DragDistance(gridSplitter, amount, Direction.West, 1000);
|
||||
|
||||
Wait.ForMilliseconds(1050);
|
||||
Wait.ForIdle();
|
||||
|
||||
ColumnDefinition columnDefinitionEnd = (await VisualTreeHelper.FindElementPropertyAsync<List<ColumnDefinition>>("GridSplitterRoot", "ColumnDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Wait.ForIdle();
|
||||
|
||||
Verify.IsTrue(Math.Abs(columnDefinitionStart.ActualWidth - amount - columnDefinitionEnd.ActualWidth) <= tolerance, $"ColumnDefinition not in range expected {columnDefinitionStart.ActualWidth - amount} was {columnDefinitionEnd.ActualWidth}");
|
||||
|
||||
Verify.IsTrue(Math.Abs(width - amount - box.BoundingRectangle.Width) <= tolerance, $"Bounding box not in range expected {width - amount} was {box.BoundingRectangle.Width}.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[TestPage("GridSplitterTestPage")]
|
||||
public async Task TestGridSplitterDragHorizontalPastMinimumAsync()
|
||||
{
|
||||
var amount = 150;
|
||||
|
||||
var gridSplitter = FindElement.ById("GridSplitterHorizontal");
|
||||
|
||||
Verify.IsNotNull(gridSplitter, "Can't find Horizontal GridSplitter");
|
||||
|
||||
// Drag to the Left
|
||||
InputHelper.DragDistance(gridSplitter, amount, Direction.West, 1000);
|
||||
|
||||
Wait.ForMilliseconds(1050);
|
||||
Wait.ForIdle();
|
||||
|
||||
ColumnDefinition columnDefinitionEnd = (await VisualTreeHelper.FindElementPropertyAsync<List<ColumnDefinition>>("GridSplitterRoot", "ColumnDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Wait.ForIdle();
|
||||
|
||||
Verify.AreEqual(columnDefinitionEnd.MinWidth, columnDefinitionEnd.ActualWidth, "Column was not the minimum size expected.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[TestPage("GridSplitterTestPage")]
|
||||
public async Task TestGridSplitterDragHorizontalPastMaximumAsync()
|
||||
{
|
||||
var amount = 150;
|
||||
|
||||
var gridSplitter = FindElement.ById("GridSplitterHorizontal");
|
||||
|
||||
Verify.IsNotNull(gridSplitter, "Can't find Horizontal GridSplitter");
|
||||
|
||||
// Drag to the Left
|
||||
InputHelper.DragDistance(gridSplitter, amount, Direction.East, 1000);
|
||||
|
||||
Wait.ForMilliseconds(1050);
|
||||
Wait.ForIdle();
|
||||
|
||||
ColumnDefinition columnDefinitionEnd = (await VisualTreeHelper.FindElementPropertyAsync<List<ColumnDefinition>>("GridSplitterRoot", "ColumnDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Wait.ForIdle();
|
||||
|
||||
Verify.AreEqual(columnDefinitionEnd.MaxWidth, columnDefinitionEnd.ActualWidth, "Column was not the maximum size expected.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[TestPage("GridSplitterTestPage")]
|
||||
public async Task TestGridSplitterDragVerticalAsync()
|
||||
{
|
||||
var amount = 50;
|
||||
var tolerance = 10;
|
||||
|
||||
var grid = FindElement.ByName("GridSplitterRoot");
|
||||
var gridSplitter = FindElement.ById("GridSplitterVertical");
|
||||
|
||||
Verify.IsNotNull(grid, "Can't find GridSplitterRoot");
|
||||
Verify.IsNotNull(gridSplitter, "Can't find Vertical GridSplitter");
|
||||
|
||||
RowDefinition rowDefinitionStart = (await VisualTreeHelper.FindElementPropertyAsync<List<RowDefinition>>("GridSplitterRoot", "RowDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Verify.IsNotNull(rowDefinitionStart, "Couldn't retrieve Row Definition");
|
||||
|
||||
// Drag to the Left
|
||||
InputHelper.DragDistance(gridSplitter, amount, Direction.North, 1000);
|
||||
|
||||
Wait.ForMilliseconds(1050);
|
||||
Wait.ForIdle();
|
||||
|
||||
RowDefinition rowDefinitionEnd = (await VisualTreeHelper.FindElementPropertyAsync<List<RowDefinition>>("GridSplitterRoot", "RowDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Wait.ForIdle();
|
||||
|
||||
Verify.IsTrue(Math.Abs(rowDefinitionStart.ActualHeight - amount - rowDefinitionEnd.ActualHeight) <= tolerance, $"RowDefinition not in range expected {rowDefinitionStart.ActualHeight - amount} was {rowDefinitionEnd.ActualHeight}");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[TestPage("GridSplitterTestPage")]
|
||||
public async Task TestGridSplitterDragVerticalPastMinimumAsync()
|
||||
{
|
||||
var amount = 150;
|
||||
|
||||
var gridSplitter = FindElement.ById("GridSplitterVertical");
|
||||
|
||||
Verify.IsNotNull(gridSplitter, "Can't find Vertical GridSplitter");
|
||||
|
||||
// Drag to the Left
|
||||
InputHelper.DragDistance(gridSplitter, amount, Direction.North, 1000);
|
||||
|
||||
Wait.ForMilliseconds(1050);
|
||||
Wait.ForIdle();
|
||||
|
||||
RowDefinition rowDefinitionEnd = (await VisualTreeHelper.FindElementPropertyAsync<List<RowDefinition>>("GridSplitterRoot", "RowDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Wait.ForIdle();
|
||||
|
||||
Verify.AreEqual(rowDefinitionEnd.MinHeight, rowDefinitionEnd.ActualHeight, "Row was not the minimum size expected.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[TestPage("GridSplitterTestPage")]
|
||||
public async Task TestGridSplitterDragVerticalPastMaximumAsync()
|
||||
{
|
||||
var amount = 150;
|
||||
|
||||
var gridSplitter = FindElement.ById("GridSplitterVertical");
|
||||
|
||||
Verify.IsNotNull(gridSplitter, "Can't find Vertical GridSplitter");
|
||||
|
||||
// Drag to the Left
|
||||
InputHelper.DragDistance(gridSplitter, amount, Direction.South, 1000);
|
||||
|
||||
Wait.ForMilliseconds(1050);
|
||||
Wait.ForIdle();
|
||||
|
||||
RowDefinition rowDefinitionEnd = (await VisualTreeHelper.FindElementPropertyAsync<List<RowDefinition>>("GridSplitterRoot", "RowDefinitions"))?.FirstOrDefault();
|
||||
|
||||
Wait.ForIdle();
|
||||
|
||||
Verify.AreEqual(rowDefinitionEnd.MaxHeight, rowDefinitionEnd.ActualHeight, "Row was not the maximum size expected.");
|
||||
}
|
||||
|
||||
private class ColumnDefinition
|
||||
{
|
||||
public GridLength Width { get; set; }
|
||||
|
||||
public double ActualWidth { get; set; }
|
||||
|
||||
public double MinWidth { get; set; }
|
||||
|
||||
public double MaxWidth { get; set; }
|
||||
}
|
||||
|
||||
private class RowDefinition
|
||||
{
|
||||
public GridLength Height { get; set; }
|
||||
|
||||
public double ActualHeight { get; set; }
|
||||
|
||||
public double MinHeight { get; set; }
|
||||
|
||||
public double MaxHeight { get; set; }
|
||||
}
|
||||
|
||||
private class GridLength
|
||||
{
|
||||
public int GridUnitType { get; set; } // 0 Auto, 1 Pixel, 2 Star
|
||||
|
||||
public double Value { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<Page x:Class="UITests.App.Pages.GridSplitterTestPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sys="using:System"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="1,1,0,0" />
|
||||
<Setter Property="Padding" Value="16" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlHighlightChromeHighBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
</Style>
|
||||
</Page.Resources>
|
||||
|
||||
<!-- Grid isn't normally an element that's findable so we need to use AutomationProperties.Name -->
|
||||
<Grid x:Name="GridSplitterRoot"
|
||||
Height="500"
|
||||
Margin="48"
|
||||
VerticalAlignment="Top"
|
||||
AutomationProperties.Name="GridSplitterRoot"
|
||||
BorderBrush="{ThemeResource SystemControlHighlightChromeHighBrush}"
|
||||
BorderThickness="0,0,1,1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="200"
|
||||
MinHeight="100"
|
||||
MaxHeight="300" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200"
|
||||
MinWidth="100"
|
||||
MaxWidth="300" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
AutomationProperties.Name="TopLeftBox">
|
||||
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect RowDefinition MinHeight='100'" />
|
||||
</Border>
|
||||
<Border Grid.Row="0"
|
||||
Grid.Column="1">
|
||||
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
|
||||
</Border>
|
||||
<Border Grid.Row="0"
|
||||
Grid.Column="2">
|
||||
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1"
|
||||
Grid.Column="0">
|
||||
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
|
||||
</Border>
|
||||
<Border Grid.Row="1"
|
||||
Grid.Column="1">
|
||||
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
|
||||
</Border>
|
||||
<Border Grid.Row="1"
|
||||
Grid.Column="2">
|
||||
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
|
||||
</Border>
|
||||
|
||||
<!-- Column Grid Splitter -->
|
||||
<controls:GridSplitter x:Name="GridSplitterHorizontal"
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
HorizontalAlignment="Left"/>
|
||||
|
||||
<!-- Row Grid Splitter -->
|
||||
<controls:GridSplitter x:Name="GridSplitterVertical"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="16"
|
||||
VerticalAlignment="Top">
|
||||
<controls:GridSplitter.Element>
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Foreground="White"
|
||||
IsHitTestVisible="False"
|
||||
Text="" />
|
||||
</controls:GridSplitter.Element>
|
||||
</controls:GridSplitter>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,20 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace UITests.App.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class GridSplitterTestPage : Page
|
||||
{
|
||||
public GridSplitterTestPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ namespace UITests.Tests
|
|||
CommunicationService = new AppServiceConnection();
|
||||
|
||||
CommunicationService.RequestReceived += CommunicationService_RequestReceived;
|
||||
CommunicationService.ServiceClosed += CommunicationService_ServiceClosed;
|
||||
|
||||
// Here, we use the app service name defined in the app service
|
||||
// provider's Package.appxmanifest file in the <Extension> section.
|
||||
|
@ -63,6 +64,11 @@ namespace UITests.Tests
|
|||
}
|
||||
}
|
||||
|
||||
private static void CommunicationService_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
|
||||
{
|
||||
Log.Warning("[Harness] Communication Service Closed! AppServiceClosedStatus: {0}", args.Status.ToString());
|
||||
}
|
||||
|
||||
internal static Task<bool> OpenPage(string pageName)
|
||||
{
|
||||
Log.Comment("[Harness] Sending Host Page Request: {0}", pageName);
|
||||
|
@ -74,6 +80,16 @@ namespace UITests.Tests
|
|||
});
|
||||
}
|
||||
|
||||
internal static async Task<AppServiceResponse> SendCustomMessageToApp(ValueSet message)
|
||||
{
|
||||
if (CommunicationService is null)
|
||||
{
|
||||
await InitalizeComService();
|
||||
}
|
||||
|
||||
return await CommunicationService.SendMessageAsync(message);
|
||||
}
|
||||
|
||||
private static async Task<bool> SendMessageToApp(ValueSet message)
|
||||
{
|
||||
if (CommunicationService is null)
|
||||
|
@ -83,10 +99,20 @@ namespace UITests.Tests
|
|||
|
||||
var response = await CommunicationService.SendMessageAsync(message);
|
||||
|
||||
return CheckResponseStatusOK(response);
|
||||
}
|
||||
|
||||
internal static bool CheckResponseStatusOK(AppServiceResponse response)
|
||||
{
|
||||
object message = null;
|
||||
var hasMessage = response?.Message?.TryGetValue("Status", out message) is true;
|
||||
|
||||
Log.Comment("[Harness] Checking Response AppServiceResponseStatus({0}), Message Status: {1}", response.Status.ToString(), message?.ToString());
|
||||
|
||||
return response.Status == AppServiceResponseStatus.Success
|
||||
&& response.Message.TryGetValue("Status", out var s)
|
||||
&& s is string status
|
||||
&& status == "OK";
|
||||
&& hasMessage
|
||||
&& message is string status
|
||||
&& status == "OK";
|
||||
}
|
||||
|
||||
private static void CommunicationService_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<HasSharedItems>true</HasSharedItems>
|
||||
|
@ -7,20 +7,19 @@
|
|||
<PropertyGroup Label="Configuration">
|
||||
<Import_RootNamespace>UITests.Tests.Shared</Import_RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<Choose>
|
||||
<!-- When we're in the test harness include all '*Test.cs' files -->
|
||||
<When Condition="'$(IsTestHarness)' == 'true'">
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)**\*Test.cs" Exclude="**\bin\**\*Test.cs;**\obj\**\*Test.cs"/>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)**\*Test.cs" Exclude="**\bin\**\*Test.cs;**\obj\**\*Test.cs" />
|
||||
<!-- Base test helpers -->
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UITestBase.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TestAssembly.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TestPageAttribute.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)VisualTreeHelper.cs" />
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
|
||||
<Choose>
|
||||
<!-- When we're in the UI app used by the test harness, include all the pages -->
|
||||
<When Condition="'$(IsTestHost)' == 'true'">
|
||||
|
@ -30,15 +29,15 @@
|
|||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
|
||||
<!-- Have a None Include as well to make all items visible in VS in the Shared Project -->
|
||||
<ItemGroup>
|
||||
<None Include="$(MSBuildThisFileDirectory)**\*Test.cs" Exclude="**\bin\**\*Test.cs;**\obj\**\*Test.cs"/>
|
||||
<None Include="$(MSBuildThisFileDirectory)**\*Test.cs" Exclude="**\bin\**\*Test.cs;**\obj\**\*Test.cs" />
|
||||
<None Include="$(MSBuildThisFileDirectory)**\*Page.xaml" Exclude="**\bin\**\*Page.xaml;**\obj\**\*Page.xaml" SubType="Designer" Generator="MSBuild:Compile" />
|
||||
<None Include="$(MSBuildThisFileDirectory)**\*Page.xaml.cs" DependentUpon="%(Filename)" />
|
||||
<!-- Base test helpers -->
|
||||
<None Include="$(MSBuildThisFileDirectory)UITestBase.cs" />
|
||||
<None Include="$(MSBuildThisFileDirectory)TestAssembly.cs" />
|
||||
<None Include="$(MSBuildThisFileDirectory)TestPageAttribute.cs" />
|
||||
<None Include="$(MSBuildThisFileDirectory)VisualTreeHelper.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,67 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
#if USING_TAEF
|
||||
using WEX.Logging.Interop;
|
||||
#endif
|
||||
|
||||
namespace UITests.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to access some VisualTree info through our communication pipeline to the host app
|
||||
/// using TestAssembly.SendMessageToApp.
|
||||
/// </summary>
|
||||
internal static class VisualTreeHelper
|
||||
{
|
||||
private static JsonSerializerOptions SerializerOptions { get; } = new JsonSerializerOptions(JsonSerializerDefaults.General)
|
||||
{
|
||||
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Looks for the specified element by name and retrieves the specified property path.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of element to search for.</param>
|
||||
/// <param name="property">Name of property to retrieve from element.</param>
|
||||
/// <typeparam name="T">Type of data to serialize result back as.</typeparam>
|
||||
/// <returns>Retrieved value or default.</returns>
|
||||
public static async Task<T> FindElementPropertyAsync<T>(string name, string property)
|
||||
{
|
||||
var response = await TestAssembly.SendCustomMessageToApp(new()
|
||||
{
|
||||
{ "Command", "Custom" },
|
||||
{ "Id", "VisualTreeHelper.FindElementProperty" },
|
||||
{ "ElementName", name },
|
||||
{ "Property", property },
|
||||
});
|
||||
|
||||
if (!TestAssembly.CheckResponseStatusOK(response))
|
||||
{
|
||||
Log.Error("[Harness] VisualTreeHelper: Error trying to retrieve property {0} from element named {1}.", property, name);
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
if (response.Message.TryGetValue("Result", out object value) && value is string str)
|
||||
{
|
||||
Log.Comment("[Harness] VisualTreeHelper.FindElementPropertyAsync - Received: {0}", str);
|
||||
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(str, SerializerOptions);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Error("[Harness] VisualTreeHelper.FindElementPropertyAsync - Couldn't deserialize result as {0}", typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,8 @@
|
|||
Version="10.0.19041.0" />
|
||||
|
||||
<PackageReference Include="MUXTestInfra.TAEF" Version="0.0.4" />
|
||||
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.2" />
|
||||
<PackageReference Include="TAEF.Redist.Wlk" Version="10.31.180822002" GeneratePathProperty="true" />
|
||||
<PackageReference Include="MUXCustomBuildTasks" Version="1.0.67" GeneratePathProperty="true" />
|
||||
</ItemGroup>
|
||||
|
@ -52,7 +54,7 @@
|
|||
<None Include="$(MSBuildThisFileDirectory)\..\UITests.App\AppPackages\*\*.msix" Link="%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="$(MSBuildThisFileDirectory)\..\UITests.App\AppPackages\*\Dependencies\$(PlatformTarget)\*.appx" Link="%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="$(MSBuildThisFileDirectory)\..\UITests.App\*.pfx" Link="%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="$(PkgMUXCustomBuildTasks)\tools\x86\WttLog.dll" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="$(PkgMUXCustomBuildTasks)\tools\x86\WttLog.dll" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче