Merge branch 'main' into shweaver/storage-helpers

This commit is contained in:
Shane Weaver 2021-07-20 09:54:45 -07:00 коммит произвёл GitHub
Родитель 655caf655d f67ccd1863
Коммит 18690395e0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 679 добавлений и 60 удалений

Просмотреть файл

@ -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="&#xE76F;" />
</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>