diff --git a/Directory.Build.props b/Directory.Build.props
index 3d8bfe70145..bf865da4779 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -40,6 +40,16 @@
+
+
+
+
+ false
+ false
+
+
+
+
diff --git a/GazeInputTest/GazeInputTest.csproj b/GazeInputTest/GazeInputTest.csproj
index 481e440e2d7..7735a9bb1a5 100644
--- a/GazeInputTest/GazeInputTest.csproj
+++ b/GazeInputTest/GazeInputTest.csproj
@@ -150,7 +150,7 @@
- 6.2.9
+ 6.2.10
1.0.2
diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs
index 30fd17ac770..97e20f13aec 100644
--- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs
+++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs
@@ -8,12 +8,12 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using Windows.ApplicationModel.Core;
+using Microsoft.Toolkit.Uwp.Helpers;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Enumeration;
using Windows.Foundation.Metadata;
-using Windows.UI.Core;
+using Windows.System;
namespace Microsoft.Toolkit.Uwp.Connectivity
{
@@ -59,11 +59,19 @@ public class BluetoothLEHelper
///
private BluetoothAdapter _adapter;
+ ///
+ /// Gets or sets which DispatcherQueue is used to dispatch UI updates.
+ ///
+ public DispatcherQueue DispatcherQueue { get; set; }
+
///
/// Prevents a default instance of the class from being created.
///
- private BluetoothLEHelper()
+ /// The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.
+ private BluetoothLEHelper(DispatcherQueue dispatcherQueue = null)
{
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
+
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Init();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
@@ -201,8 +209,7 @@ private async Task Init()
/// The advertisement.
private async void AdvertisementWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
- CoreDispatcherPriority.Normal,
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
() =>
{
if (_readerWriterLockSlim.TryEnterReadLock(TimeSpan.FromSeconds(1)))
@@ -217,7 +224,7 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
_readerWriterLockSlim.ExitReadLock();
}
- });
+ }, DispatcherQueuePriority.Normal);
}
///
@@ -286,19 +293,20 @@ private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformation
// Protect against race condition if the task runs after the app stopped the deviceWatcher.
if (sender == _deviceWatcher)
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
- {
- if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1)))
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
+ () =>
{
- var device = BluetoothLeDevices.FirstOrDefault(i => i.DeviceInfo.Id == deviceInfoUpdate.Id);
- BluetoothLeDevices.Remove(device);
+ if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1)))
+ {
+ var device = BluetoothLeDevices.FirstOrDefault(i => i.DeviceInfo.Id == deviceInfoUpdate.Id);
+ BluetoothLeDevices.Remove(device);
- var unusedDevice = _unusedDevices.FirstOrDefault(i => i.Id == deviceInfoUpdate.Id);
- _unusedDevices?.Remove(unusedDevice);
+ var unusedDevice = _unusedDevices.FirstOrDefault(i => i.Id == deviceInfoUpdate.Id);
+ _unusedDevices?.Remove(unusedDevice);
- _readerWriterLockSlim.ExitWriteLock();
- }
- });
+ _readerWriterLockSlim.ExitWriteLock();
+ }
+ }, DispatcherQueuePriority.Normal);
}
}
@@ -327,7 +335,7 @@ private async Task AddDeviceToList(DeviceInformation deviceInfo)
// Make sure device name isn't blank or already present in the list.
if (!string.IsNullOrEmpty(deviceInfo?.Name))
{
- var device = new ObservableBluetoothLEDevice(deviceInfo);
+ var device = new ObservableBluetoothLEDevice(deviceInfo, DispatcherQueue);
var connectable = (device.DeviceInfo.Properties.Keys.Contains("System.Devices.Aep.Bluetooth.Le.IsConnectable") &&
(bool)device.DeviceInfo.Properties["System.Devices.Aep.Bluetooth.Le.IsConnectable"]) ||
(device.DeviceInfo.Properties.Keys.Contains("System.Devices.Aep.IsConnected") &&
@@ -335,8 +343,7 @@ private async Task AddDeviceToList(DeviceInformation deviceInfo)
if (connectable)
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
- CoreDispatcherPriority.Normal,
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
() =>
{
if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1)))
@@ -348,7 +355,7 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
_readerWriterLockSlim.ExitWriteLock();
}
- });
+ }, DispatcherQueuePriority.Normal);
return;
}
diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs
index b39312d417a..e54d84f4ef8 100644
--- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs
+++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs
@@ -11,10 +11,11 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
-using Windows.ApplicationModel.Core;
+using Microsoft.Toolkit.Uwp.Helpers;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
+using Windows.System;
using Windows.UI.Core;
using Windows.UI.Xaml.Media.Imaging;
@@ -134,17 +135,25 @@ public int Compare(object x, object y)
private ObservableCollection _services =
new ObservableCollection();
+ ///
+ /// Gets or sets which DispatcherQueue is used to dispatch UI updates.
+ ///
+ public DispatcherQueue DispatcherQueue { get; set; }
+
///
/// Initializes a new instance of the class.
///
/// The device information.
- public ObservableBluetoothLEDevice(DeviceInformation deviceInfo)
+ /// The DispatcherQueue that should be used to dispatch UI updates for this BluetoothLE Device, or null if this is being called from the UI thread.
+ public ObservableBluetoothLEDevice(DeviceInformation deviceInfo, DispatcherQueue dispatcherQueue = null)
{
DeviceInfo = deviceInfo;
Name = DeviceInfo.Name;
IsPaired = DeviceInfo.Pairing.IsPaired;
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
+
LoadGlyph();
this.PropertyChanged += ObservableBluetoothLEDevice_PropertyChanged;
@@ -395,7 +404,8 @@ private void ObservableBluetoothLEDevice_PropertyChanged(object sender, Property
/// Thorws Exception when no permission to access device
public async Task ConnectAsync()
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
+ async () =>
{
if (BluetoothLEDevice == null)
{
@@ -442,7 +452,7 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPrio
throw new Exception(_result.ProtocolError.GetErrorString());
}
}
- });
+ }, DispatcherQueuePriority.Normal);
}
///
@@ -468,8 +478,7 @@ public async Task DoInAppPairingAsync()
/// The task of the update.
public async Task UpdateAsync(DeviceInformationUpdate deviceUpdate)
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
- CoreDispatcherPriority.Normal,
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
() =>
{
DeviceInfo.Update(deviceUpdate);
@@ -479,7 +488,7 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
LoadGlyph();
OnPropertyChanged("DeviceInfo");
- });
+ }, DispatcherQueuePriority.Normal);
}
///
@@ -512,9 +521,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
/// The arguments.
private async void BluetoothLEDevice_NameChanged(BluetoothLEDevice sender, object args)
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
- CoreDispatcherPriority.Normal,
- () => { Name = BluetoothLEDevice.Name; });
+ await DispatcherQueue.ExecuteOnUIThreadAsync(() => { Name = BluetoothLEDevice.Name; }, DispatcherQueuePriority.Normal);
}
///
@@ -524,13 +531,12 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
/// The arguments.
private async void BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
- CoreDispatcherPriority.Normal,
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
() =>
{
IsPaired = DeviceInfo.Pairing.IsPaired;
IsConnected = BluetoothLEDevice.ConnectionStatus == BluetoothConnectionStatus.Connected;
- });
+ }, DispatcherQueuePriority.Normal);
}
///
@@ -538,15 +544,14 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
///
private async void LoadGlyph()
{
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
- CoreDispatcherPriority.Normal,
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
async () =>
{
var deviceThumbnail = await DeviceInfo.GetGlyphThumbnailAsync();
var glyphBitmapImage = new BitmapImage();
await glyphBitmapImage.SetSourceAsync(deviceThumbnail);
Glyph = glyphBitmapImage;
- });
+ }, DispatcherQueuePriority.Normal);
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs
index 38f3d6331ab..c1ab661c904 100644
--- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs
+++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs
@@ -7,10 +7,12 @@
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;
+using Windows.System;
namespace Microsoft.Toolkit.Uwp.Connectivity
{
@@ -110,13 +112,21 @@ public enum DisplayTypes
///
private string _value;
+ ///
+ /// Gets or sets which DispatcherQueue is used to dispatch UI updates.
+ ///
+ public DispatcherQueue DispatcherQueue { get; set; }
+
///
/// Initializes a new instance of the class.
///
/// The characteristic.
/// The parent.
- public ObservableGattCharacteristics(GattCharacteristic characteristic, ObservableGattDeviceService parent)
+ /// The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.
+ public ObservableGattCharacteristics(GattCharacteristic characteristic, ObservableGattDeviceService parent, DispatcherQueue dispatcherQueue = null)
{
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
+
Characteristic = characteristic;
Parent = parent;
Name = GattUuidsService.ConvertUuidToName(Characteristic.Uuid);
@@ -459,9 +469,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
/// The instance containing the event data.
private async void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
- await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
- Windows.UI.Core.CoreDispatcherPriority.Normal,
- () => { SetValue(args.CharacteristicValue); });
+ await DispatcherQueue.ExecuteOnUIThreadAsync(() => { SetValue(args.CharacteristicValue); }, DispatcherQueuePriority.Normal);
}
///
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Controls/CodeRenderer.cs b/Microsoft.Toolkit.Uwp.SampleApp/Controls/CodeRenderer.cs
index d8ce3386a76..ea744557440 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/Controls/CodeRenderer.cs
+++ b/Microsoft.Toolkit.Uwp.SampleApp/Controls/CodeRenderer.cs
@@ -87,10 +87,14 @@ protected override void OnApplyTemplate()
private void RenderDocument()
{
- _codeView?.Blocks?.Clear();
- _formatter = new RichTextBlockFormatter(_theme);
- _formatter.FormatRichTextBlock(_displayedText, _language, _codeView);
- _rendered = true;
+ if (_codeView != null)
+ {
+ _codeView.Blocks?.Clear();
+ _formatter = new RichTextBlockFormatter(_theme);
+
+ _formatter.FormatRichTextBlock(_displayedText, _language, _codeView);
+ _rendered = true;
+ }
}
private void CopyButton_Click(object sender, RoutedEventArgs e)
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
index 77be6020d17..17b8faa23de 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
+++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
@@ -106,7 +106,7 @@
- 6.2.9
+ 6.2.10
10.1901.28001
@@ -292,7 +292,7 @@
-
+
@@ -456,7 +456,7 @@
-
+
Designer
@@ -726,8 +726,8 @@
BackgroundTaskHelperPage.xaml
-
- DispatcherHelperPage.xaml
+
+ DispatcherQueueHelperPage.xaml
DropShadowPanelPage.xaml
@@ -1151,7 +1151,7 @@
Designer
MSBuild:Compile
-
+
Designer
MSBuild:Compile
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatchHelper.png b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatchQueueHelper.png
similarity index 100%
rename from Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatchHelper.png
rename to Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatchQueueHelper.png
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatcherHelperCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperCode.bind
similarity index 73%
rename from Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatcherHelperCode.bind
rename to Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperCode.bind
index 0641c40f79b..bda6b73042b 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatcherHelperCode.bind
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperCode.bind
@@ -1,8 +1,12 @@
+// From a UI thread, capture the DispatcherQueue once:
+var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
+
+// The use it from any other thread
int crossThreadReturnedValue = await Task.Run( async () =>
{
// Task.Run() will guarantee the given piece of code be executed on a seperate thread pool.
// This is used to simulate the scenario of updating the UI element from a different thread.
- int returnedFromUIThread = await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ int returnedFromUIThread = await dispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
NormalTextBlock.Text = "Updated from a random thread!";
return 1;
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatcherHelperPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml
similarity index 97%
rename from Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatcherHelperPage.xaml
rename to Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml
index 02543e03990..9001b65cb39 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherHelper/DispatcherHelperPage.xaml
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml
@@ -1,4 +1,4 @@
-(async () =>
{
- int returnedFromUIThread = await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ int returnedFromUIThread = await dispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
NormalTextBlock.Text = "Updated from a random thread!";
return 1;
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MasterDetailsView/MasterDetailsViewPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MasterDetailsView/MasterDetailsViewPage.xaml.cs
index 012b87981cb..bf7758af228 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MasterDetailsView/MasterDetailsViewPage.xaml.cs
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MasterDetailsView/MasterDetailsViewPage.xaml.cs
@@ -15,8 +15,6 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
///
public sealed partial class MasterDetailsViewPage : Page, IXamlRenderListener
{
- private double _previousWidth = Window.Current.Bounds.Width;
-
public MasterDetailsViewPage()
{
Emails = new List
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
index e7f77241fb6..ba2268cb6cc 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
@@ -791,14 +791,14 @@
"DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/helpers/PrintHelper.md"
},
{
- "Name": "DispatcherHelper",
- "Type": "DispatcherHelperPage",
+ "Name": "DispatcherQueueHelper",
+ "Type": "DispatcherQueueHelperPage",
"Subcategory": "Developer",
- "About": "Allows easy interaction with Windows Runtime core message dispatcher for multi-threaded scenario (I.E: Run code on UI thread). ",
- "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs",
- "CodeFile": "DispatcherHelperCode.bind",
+ "About": "Allows easy interaction with Windows Runtime message dispatcher queue for multi-threaded scenario (I.E: Run code on UI thread).",
+ "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs",
+ "CodeFile": "DispatcherQueueHelperCode.bind",
"Icon": "/Assets/Helpers.png",
- "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/helpers/DispatcherHelper.md"
+ "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/helpers/DispatcherQueueHelper.md"
},
{
"Name": "AdvancedCollectionView",
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Shell.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/Shell.xaml.cs
index 36875adcb58..8dfc02c5471 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/Shell.xaml.cs
+++ b/Microsoft.Toolkit.Uwp.SampleApp/Shell.xaml.cs
@@ -6,6 +6,7 @@
using Microsoft.Toolkit.Uwp.Helpers;
using Microsoft.Toolkit.Uwp.SampleApp.Pages;
using Microsoft.Toolkit.Uwp.UI.Extensions;
+using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
@@ -127,7 +128,7 @@ private void SamplePickerGridView_Loaded(object sender, Windows.UI.Xaml.RoutedEv
{
if (s is UIElement samplePicker && samplePicker.Visibility == Visibility.Visible)
{
- DispatcherHelper.ExecuteOnUIThreadAsync(() => SamplePickerGridView.Focus(FocusState.Keyboard));
+ DispatcherQueue.GetForCurrentThread().ExecuteOnUIThreadAsync(() => SamplePickerGridView.Focus(FocusState.Keyboard));
}
});
}
diff --git a/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj b/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj
index b60b5c9d5cf..dae807b42d6 100644
--- a/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj
+++ b/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj
@@ -109,7 +109,7 @@
- 6.2.9
+ 6.2.10
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Microsoft.Toolkit.Uwp.UI.Animations.csproj b/Microsoft.Toolkit.Uwp.UI.Animations/Microsoft.Toolkit.Uwp.UI.Animations.csproj
index 2c5453812fe..a236696ac54 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Microsoft.Toolkit.Uwp.UI.Animations.csproj
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Microsoft.Toolkit.Uwp.UI.Animations.csproj
@@ -21,7 +21,7 @@
-
+
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/DataGrid/DataGridColumn.cs b/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/DataGrid/DataGridColumn.cs
index 26064167cdb..fee5a1b7b13 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/DataGrid/DataGridColumn.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/DataGrid/DataGridColumn.cs
@@ -8,6 +8,7 @@
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Microsoft.Toolkit.Uwp.UI.Data.Utilities;
+using Microsoft.Toolkit.Uwp.Utilities;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
@@ -1059,7 +1060,16 @@ internal void ComputeLayoutRoundedWidth(double leftEdge)
{
if (this.OwningGrid != null && this.OwningGrid.UseLayoutRounding)
{
- double scale = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+ double scale;
+ if (TypeHelper.IsXamlRootAvailable && OwningGrid.XamlRoot != null)
+ {
+ scale = OwningGrid.XamlRoot.RasterizationScale;
+ }
+ else
+ {
+ scale = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+ }
+
double roundedLeftEdge = Math.Floor((scale * leftEdge) + 0.5) / scale;
double roundedRightEdge = Math.Floor((scale * (leftEdge + this.ActualWidth)) + 0.5) / scale;
this.LayoutRoundedWidth = roundedRightEdge - roundedLeftEdge;
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/Utilities/TypeHelper.cs b/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/Utilities/TypeHelper.cs
index 3792cb88f4c..672c2cea195 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/Utilities/TypeHelper.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/Utilities/TypeHelper.cs
@@ -17,8 +17,9 @@ internal static class TypeHelper
internal const char PropertyNameSeparator = '.';
internal const char RightIndexerToken = ']';
- private static bool isAPIContractAvailableInitialized = false;
+ private static bool isAPIsAvailableInitialized = false;
private static bool isRS3OrHigher = false;
+ private static bool isXamlRootAvailable = false;
// Methods
private static Type FindGenericType(Type definition, Type type)
@@ -412,19 +413,33 @@ internal static bool IsRS3OrHigher
{
get
{
- if (!isAPIContractAvailableInitialized)
+ if (!isAPIsAvailableInitialized)
{
- InitializeAPIContractAvailable();
+ InitializeAPIsAvailable();
}
return isRS3OrHigher;
}
}
- internal static void InitializeAPIContractAvailable()
+ internal static bool IsXamlRootAvailable
+ {
+ get
+ {
+ if (!isAPIsAvailableInitialized)
+ {
+ InitializeAPIsAvailable();
+ }
+
+ return isXamlRootAvailable;
+ }
+ }
+
+ internal static void InitializeAPIsAvailable()
{
isRS3OrHigher = Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 5);
- isAPIContractAvailableInitialized = true;
+ isXamlRootAvailable = Windows.Foundation.Metadata.ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot");
+ isAPIsAvailableInitialized = true;
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/ControlHelpers.XamlHost.cs b/Microsoft.Toolkit.Uwp.UI.Controls/ControlHelpers.XamlHost.cs
new file mode 100644
index 00000000000..90514de7cd6
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/ControlHelpers.XamlHost.cs
@@ -0,0 +1,14 @@
+// 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.
+
+namespace Microsoft.Toolkit.Uwp.UI.Controls
+{
+ ///
+ /// Internal class used to provide helpers for controls
+ ///
+ internal static partial class ControlHelpers
+ {
+ internal static bool IsXamlRootAvailable { get; } = Windows.Foundation.Metadata.ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot");
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/DropShadowPanel/DropShadowPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/DropShadowPanel/DropShadowPanel.cs
index dfa1609587c..9178516e57d 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/DropShadowPanel/DropShadowPanel.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/DropShadowPanel/DropShadowPanel.cs
@@ -86,6 +86,8 @@ protected override void OnContentChanged(object oldContent, object newContent)
}
}
+ UpdateShadowMask();
+
base.OnContentChanged(oldContent, newContent);
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Logic.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Logic.cs
index 7cebf555f61..c6c894fe5ea 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Logic.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Logic.cs
@@ -36,7 +36,7 @@ private void UpdateEyedropper(Point position)
UpdatePreview(x, y);
}
- private void UpadateWorkArea()
+ private void UpdateWorkArea()
{
if (_targetGrid == null)
{
@@ -50,9 +50,20 @@ private void UpadateWorkArea()
else
{
var left = WorkArea.Left;
- var right = Window.Current.Bounds.Width - WorkArea.Right;
var top = WorkArea.Top;
- var bottom = Window.Current.Bounds.Height - WorkArea.Bottom;
+ double right;
+ double bottom;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ right = XamlRoot.Size.Width - WorkArea.Right;
+ bottom = XamlRoot.Size.Height - WorkArea.Bottom;
+ }
+ else
+ {
+ right = Window.Current.Bounds.Width - WorkArea.Right;
+ bottom = Window.Current.Bounds.Height - WorkArea.Bottom;
+ }
+
_targetGrid.Margin = new Thickness(left, top, right, bottom);
}
}
@@ -98,14 +109,41 @@ private void UpdatePreview(int centerX, int centerY)
internal async Task UpdateAppScreenshotAsync()
{
- var renderTarget = new RenderTargetBitmap();
- var diaplayInfo = DisplayInformation.GetForCurrentView();
- var scale = diaplayInfo.RawPixelsPerViewPixel;
- var scaleWidth = (int)Math.Ceiling(Window.Current.Bounds.Width / scale);
- var scaleHeight = (int)Math.Ceiling(Window.Current.Bounds.Height / scale);
- await renderTarget.RenderAsync(Window.Current.Content, scaleWidth, scaleHeight);
- var pixels = await renderTarget.GetPixelsAsync();
- _appScreenshot = CanvasBitmap.CreateFromBytes(_device, pixels, renderTarget.PixelWidth, renderTarget.PixelHeight, DirectXPixelFormat.B8G8R8A8UIntNormalized);
+ double scale;
+ double width;
+ double height;
+ UIElement content;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ scale = XamlRoot.RasterizationScale;
+ width = XamlRoot.Size.Width;
+ height = XamlRoot.Size.Height;
+ content = XamlRoot.Content;
+ }
+ else
+ {
+ var displayInfo = DisplayInformation.GetForCurrentView();
+ scale = displayInfo.RawPixelsPerViewPixel;
+ width = Window.Current.Bounds.Width;
+ height = Window.Current.Bounds.Height;
+ content = Window.Current.Content;
+ }
+
+ try
+ {
+ var renderTarget = new RenderTargetBitmap();
+ var scaleWidth = (int)Math.Ceiling(width / scale);
+ var scaleHeight = (int)Math.Ceiling(height / scale);
+ await renderTarget.RenderAsync(content, scaleWidth, scaleHeight);
+ var pixels = await renderTarget.GetPixelsAsync();
+ _appScreenshot?.Dispose();
+ _appScreenshot = null;
+ _appScreenshot = CanvasBitmap.CreateFromBytes(_device, pixels, renderTarget.PixelWidth, renderTarget.PixelHeight, DirectXPixelFormat.B8G8R8A8UIntNormalized);
+ }
+ catch (OutOfMemoryException ex)
+ {
+ System.Diagnostics.Debug.WriteLine(ex);
+ }
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Properties.cs
index 915461e609f..785fc6b033f 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Properties.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.Properties.cs
@@ -71,7 +71,7 @@ private static void OnWorkAreaChanged(DependencyObject d, DependencyPropertyChan
{
if (d is Eyedropper eyedropper)
{
- eyedropper.UpadateWorkArea();
+ eyedropper.UpdateWorkArea();
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.cs
index b84edb7239d..082bed75c66 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/Eyedropper.cs
@@ -32,15 +32,16 @@ public partial class Eyedropper : Control
private static readonly CoreCursor MoveCursor = new CoreCursor(CoreCursorType.Cross, 1);
private readonly CanvasDevice _device = CanvasDevice.GetSharedDevice();
private readonly TranslateTransform _layoutTransform = new TranslateTransform();
-
- private readonly Popup _popup;
private readonly CanvasImageSource _previewImageSource;
private readonly Grid _rootGrid;
private readonly Grid _targetGrid;
+
+ private Popup _popup;
private CanvasBitmap _appScreenshot;
private Action _lazyTask;
private uint? _pointerId = null;
private TaskCompletionSource _taskSource;
+ private double _currentDpi;
///
/// Initializes a new instance of the class.
@@ -53,10 +54,7 @@ public Eyedropper()
{
Background = new SolidColorBrush(Color.FromArgb(0x01, 0x00, 0x00, 0x00))
};
- _popup = new Popup
- {
- Child = _rootGrid
- };
+
RenderTransform = _layoutTransform;
_previewImageSource = new CanvasImageSource(_device, PreviewPixelsPerRawPixel * PixelCountPerRow, PreviewPixelsPerRawPixel * PixelCountPerRow, 96f);
Preview = _previewImageSource;
@@ -100,12 +98,38 @@ public async Task Open(Point? startPoint = null)
_rootGrid.Children.Add(_targetGrid);
_rootGrid.Children.Add(this);
- _rootGrid.Width = Window.Current.Bounds.Width;
- _rootGrid.Height = Window.Current.Bounds.Height;
- UpadateWorkArea();
+
+ if (_popup != null)
+ {
+ _popup.IsOpen = false;
+ }
+
+ _popup = new Popup
+ {
+ Child = _rootGrid
+ };
+
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ _popup.XamlRoot = XamlRoot;
+ }
+
+ if (ControlHelpers.IsXamlRootAvailable && _popup.XamlRoot != null)
+ {
+ _rootGrid.Width = _popup.XamlRoot.Size.Width;
+ _rootGrid.Height = _popup.XamlRoot.Size.Height;
+ }
+ else
+ {
+ _rootGrid.Width = Window.Current.Bounds.Width;
+ _rootGrid.Height = Window.Current.Bounds.Height;
+ }
+
+ UpdateWorkArea();
_popup.IsOpen = true;
var result = await _taskSource.Task;
_taskSource = null;
+ _popup = null;
_rootGrid.Children.Clear();
return result;
}
@@ -117,28 +141,72 @@ public void Close()
{
if (_taskSource != null && !_taskSource.Task.IsCanceled)
{
- _taskSource.SetCanceled();
+ _taskSource.TrySetCanceled();
_rootGrid.Children.Clear();
}
}
private void HookUpEvents()
{
+ Unloaded -= Eyedropper_Unloaded;
Unloaded += Eyedropper_Unloaded;
- Window.Current.SizeChanged += Window_SizeChanged;
- DisplayInformation.GetForCurrentView().DpiChanged += Eyedropper_DpiChanged;
+
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ XamlRoot.Changed -= XamlRoot_Changed;
+ XamlRoot.Changed += XamlRoot_Changed;
+ _currentDpi = XamlRoot.RasterizationScale;
+ }
+ else
+ {
+ var window = Window.Current;
+ window.SizeChanged -= Window_SizeChanged;
+ window.SizeChanged += Window_SizeChanged;
+ var displayInformation = DisplayInformation.GetForCurrentView();
+ displayInformation.DpiChanged -= Eyedropper_DpiChanged;
+ displayInformation.DpiChanged += Eyedropper_DpiChanged;
+ _currentDpi = displayInformation.LogicalDpi;
+ }
+
+ _targetGrid.PointerEntered -= TargetGrid_PointerEntered;
_targetGrid.PointerEntered += TargetGrid_PointerEntered;
+ _targetGrid.PointerExited -= TargetGrid_PointerExited;
_targetGrid.PointerExited += TargetGrid_PointerExited;
+ _targetGrid.PointerPressed -= TargetGrid_PointerPressed;
_targetGrid.PointerPressed += TargetGrid_PointerPressed;
+ _targetGrid.PointerMoved -= TargetGrid_PointerMoved;
_targetGrid.PointerMoved += TargetGrid_PointerMoved;
+ _targetGrid.PointerReleased -= TargetGrid_PointerReleased;
_targetGrid.PointerReleased += TargetGrid_PointerReleased;
}
+ private async void XamlRoot_Changed(XamlRoot sender, XamlRootChangedEventArgs args)
+ {
+ if (_rootGrid.Width != sender.Size.Width || _rootGrid.Height != sender.Size.Height)
+ {
+ UpdateRootGridSize(sender.Size.Width, sender.Size.Height);
+ }
+
+ if (_currentDpi != sender.RasterizationScale)
+ {
+ _currentDpi = sender.RasterizationScale;
+ await UpdateAppScreenshotAsync();
+ }
+ }
+
private void UnhookEvents()
{
Unloaded -= Eyedropper_Unloaded;
- Window.Current.SizeChanged -= Window_SizeChanged;
- DisplayInformation.GetForCurrentView().DpiChanged -= Eyedropper_DpiChanged;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ XamlRoot.Changed -= XamlRoot_Changed;
+ }
+ else
+ {
+ Window.Current.SizeChanged -= Window_SizeChanged;
+ DisplayInformation.GetForCurrentView().DpiChanged -= Eyedropper_DpiChanged;
+ }
+
if (_targetGrid != null)
{
_targetGrid.PointerEntered -= TargetGrid_PointerEntered;
@@ -172,49 +240,68 @@ private void TargetGrid_PointerEntered(object sender, PointerRoutedEventArgs e)
private async void Eyedropper_DpiChanged(DisplayInformation sender, object args)
{
+ _currentDpi = sender.LogicalDpi;
await UpdateAppScreenshotAsync();
}
private async void TargetGrid_PointerReleased(object sender, PointerRoutedEventArgs e)
{
- var pointer = e.Pointer;
- if (pointer.PointerId == _pointerId)
+ var point = e.GetCurrentPoint(_rootGrid);
+ await InternalPointerReleasedAsync(e.Pointer.PointerId, point.Position);
+ }
+
+ // Internal abstraction is used by the Unit Tests
+ internal async Task InternalPointerReleasedAsync(uint pointerId, Point position)
+ {
+ if (pointerId == _pointerId)
{
- var point = e.GetCurrentPoint(_rootGrid);
if (_appScreenshot == null)
{
await UpdateAppScreenshotAsync();
}
- UpdateEyedropper(point.Position);
- PickCompleted?.Invoke(this, EventArgs.Empty);
+ UpdateEyedropper(position);
_pointerId = null;
- if (!_taskSource.Task.IsCanceled)
+ if (_taskSource != null && !_taskSource.Task.IsCanceled)
{
- _taskSource.SetResult(Color);
+ _taskSource.TrySetResult(Color);
}
+
+ PickCompleted?.Invoke(this, EventArgs.Empty);
}
}
private void TargetGrid_PointerMoved(object sender, PointerRoutedEventArgs e)
{
var pointer = e.Pointer;
- if (pointer.PointerId == _pointerId)
+ var point = e.GetCurrentPoint(_rootGrid);
+ InternalPointerMoved(pointer.PointerId, point.Position);
+ }
+
+ // Internal abstraction is used by the Unit Tests
+ internal void InternalPointerMoved(uint pointerId, Point position)
+ {
+ if (pointerId == _pointerId)
{
- var point = e.GetCurrentPoint(_rootGrid);
- UpdateEyedropper(point.Position);
+ UpdateEyedropper(position);
}
}
private async void TargetGrid_PointerPressed(object sender, PointerRoutedEventArgs e)
{
- _pointerId = e.Pointer.PointerId;
var point = e.GetCurrentPoint(_rootGrid);
+ await InternalPointerPressedAsync(e.Pointer.PointerId, point.Position, e.Pointer.PointerDeviceType);
+ }
+
+ // Internal abstraction is used by the Unit Tests
+ internal async Task InternalPointerPressedAsync(uint pointerId, Point position, Windows.Devices.Input.PointerDeviceType pointerDeviceType)
+ {
+ _pointerId = pointerId;
PickStarted?.Invoke(this, EventArgs.Empty);
await UpdateAppScreenshotAsync();
- UpdateEyedropper(point.Position);
+ UpdateEyedropper(position);
- if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
+ if (pointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
{
VisualStateManager.GoToState(this, TouchState, false);
}
@@ -244,11 +331,16 @@ private void Eyedropper_Unloaded(object sender, RoutedEventArgs e)
}
private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs e)
+ {
+ UpdateRootGridSize(Window.Current.Bounds.Width, Window.Current.Bounds.Height);
+ }
+
+ private void UpdateRootGridSize(double width, double height)
{
if (_rootGrid != null)
{
- _rootGrid.Width = Window.Current.Bounds.Width;
- _rootGrid.Height = Window.Current.Bounds.Height;
+ _rootGrid.Width = width;
+ _rootGrid.Height = height;
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.Properties.cs
index 15638ec6de8..59a29380918 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.Properties.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.Properties.cs
@@ -80,6 +80,11 @@ private static void OnEyedropperEnabledChanged(DependencyObject d, DependencyPro
if (eyedropperToolButton.EyedropperEnabled)
{
VisualStateManager.GoToState(eyedropperToolButton, eyedropperToolButton.IsPointerOver ? EyedropperEnabledPointerOverState : EyedropperEnabledState, true);
+ if (ControlHelpers.IsXamlRootAvailable && eyedropperToolButton.XamlRoot != null)
+ {
+ eyedropperToolButton._eyedropper.XamlRoot = eyedropperToolButton.XamlRoot;
+ }
+
eyedropperToolButton._eyedropper.Open().ConfigureAwait(false);
}
else
@@ -125,14 +130,14 @@ private void HookUpTargetElementEvents(FrameworkElement target)
}
}
- private void Target_PointerEntered(object sender, PointerRoutedEventArgs e)
+ private async void Target_PointerEntered(object sender, PointerRoutedEventArgs e)
{
- UpdateEyedropperWorkArea();
+ await UpdateEyedropperWorkAreaAsync();
}
- private void Target_SizeChanged(object sender, SizeChangedEventArgs e)
+ private async void Target_SizeChanged(object sender, SizeChangedEventArgs e)
{
- UpdateEyedropperWorkArea();
+ await UpdateEyedropperWorkAreaAsync();
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.cs
index cd2cd5c9828..3e67a6b1436 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Eyedropper/EyedropperToolButton.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
@@ -55,12 +56,29 @@ public EyedropperToolButton()
private void HookUpEvents()
{
+ Click -= EyedropperToolButton_Click;
Click += EyedropperToolButton_Click;
+ Unloaded -= EyedropperToolButton_Unloaded;
Unloaded += EyedropperToolButton_Unloaded;
+ ActualThemeChanged -= EyedropperToolButton_ActualThemeChanged;
ActualThemeChanged += EyedropperToolButton_ActualThemeChanged;
- Window.Current.SizeChanged += Window_SizeChanged;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ XamlRoot.Changed -= XamlRoot_Changed;
+ XamlRoot.Changed += XamlRoot_Changed;
+ _eyedropper.XamlRoot = XamlRoot;
+ }
+ else
+ {
+ Window.Current.SizeChanged -= Window_SizeChanged;
+ Window.Current.SizeChanged += Window_SizeChanged;
+ }
+
+ _eyedropper.ColorChanged -= Eyedropper_ColorChanged;
_eyedropper.ColorChanged += Eyedropper_ColorChanged;
+ _eyedropper.PickStarted -= Eyedropper_PickStarted;
_eyedropper.PickStarted += Eyedropper_PickStarted;
+ _eyedropper.PickCompleted -= Eyedropper_PickCompleted;
_eyedropper.PickCompleted += Eyedropper_PickCompleted;
}
@@ -69,7 +87,15 @@ private void UnhookEvents()
Click -= EyedropperToolButton_Click;
Unloaded -= EyedropperToolButton_Unloaded;
ActualThemeChanged -= EyedropperToolButton_ActualThemeChanged;
- Window.Current.SizeChanged -= Window_SizeChanged;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ XamlRoot.Changed -= XamlRoot_Changed;
+ }
+ else
+ {
+ Window.Current.SizeChanged -= Window_SizeChanged;
+ }
+
_eyedropper.ColorChanged -= Eyedropper_ColorChanged;
_eyedropper.PickStarted -= Eyedropper_PickStarted;
_eyedropper.PickCompleted -= Eyedropper_PickCompleted;
@@ -165,18 +191,38 @@ private void EyedropperToolButton_Click(object sender, RoutedEventArgs e)
EyedropperEnabled = !EyedropperEnabled;
}
- private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs e)
+ private async void Window_SizeChanged(object sender, WindowSizeChangedEventArgs e)
+ {
+ await UpdateEyedropperWorkAreaAsync();
+ }
+
+ private async void XamlRoot_Changed(XamlRoot sender, XamlRootChangedEventArgs args)
{
- UpdateEyedropperWorkArea();
+ await UpdateEyedropperWorkAreaAsync();
}
- private async void UpdateEyedropperWorkArea()
+ private async Task UpdateEyedropperWorkAreaAsync()
{
if (TargetElement != null)
{
- var transform = TargetElement.TransformToVisual(Window.Current.Content);
+ UIElement content;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ content = XamlRoot.Content;
+ }
+ else
+ {
+ content = Window.Current.Content;
+ }
+
+ var transform = TargetElement.TransformToVisual(content);
var position = transform.TransformPoint(default(Point));
_eyedropper.WorkArea = new Rect(position, new Size(TargetElement.ActualWidth, TargetElement.ActualHeight));
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ _eyedropper.XamlRoot = XamlRoot;
+ }
+
await _eyedropper.UpdateAppScreenshotAsync();
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.cs
index 1b59b69f842..199704bdcf5 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.cs
@@ -78,7 +78,15 @@ internal void ConfigureSpriteVisual(double width, double height, float zoomFacto
internal void SetScale(float zoomFactor)
{
- _screenScale = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ _screenScale = XamlRoot.RasterizationScale;
+ }
+ else
+ {
+ _screenScale = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+ }
+
var scale = _screenScale * zoomFactor;
_surfaceBrush.Scale = new Vector2((float)(1 / scale));
_surfaceBrush.BitmapInterpolationMode = CompositionBitmapInterpolationMode.NearestNeighbor;
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/InfiniteCanvas.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/InfiniteCanvas.cs
index c2c80be3b4f..23cb0a3ef3c 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/InfiniteCanvas.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/InfiniteCanvas.cs
@@ -181,13 +181,55 @@ public double MinZoomFactor
private Rect ViewPort => new Rect(_infiniteCanvasScrollViewer.HorizontalOffset / _infiniteCanvasScrollViewer.ZoomFactor, _infiniteCanvasScrollViewer.VerticalOffset / _infiniteCanvasScrollViewer.ZoomFactor, ViewPortWidth, ViewPortHeight);
- private double ViewPortHeight => (double.IsNaN(_infiniteCanvasScrollViewer.Height)
- ? Window.Current.Bounds.Height
- : _infiniteCanvasScrollViewer.ViewportHeight) / _infiniteCanvasScrollViewer.ZoomFactor;
+ private double ViewPortHeight
+ {
+ get
+ {
+ double height;
+ if (double.IsNaN(_infiniteCanvasScrollViewer.Height))
+ {
+ if (ControlHelpers.IsXamlRootAvailable && _infiniteCanvasScrollViewer.XamlRoot != null)
+ {
+ height = _infiniteCanvasScrollViewer.XamlRoot.Size.Height;
+ }
+ else
+ {
+ height = Window.Current.Bounds.Height;
+ }
+ }
+ else
+ {
+ height = _infiniteCanvasScrollViewer.ViewportHeight;
+ }
+
+ return height / _infiniteCanvasScrollViewer.ZoomFactor;
+ }
+ }
- private double ViewPortWidth => (double.IsNaN(_infiniteCanvasScrollViewer.Width)
- ? Window.Current.Bounds.Width
- : _infiniteCanvasScrollViewer.ViewportWidth) / _infiniteCanvasScrollViewer.ZoomFactor;
+ private double ViewPortWidth
+ {
+ get
+ {
+ double width;
+ if (double.IsNaN(_infiniteCanvasScrollViewer.Width))
+ {
+ if (ControlHelpers.IsXamlRootAvailable && _infiniteCanvasScrollViewer.XamlRoot != null)
+ {
+ width = _infiniteCanvasScrollViewer.XamlRoot.Size.Width;
+ }
+ else
+ {
+ width = Window.Current.Bounds.Width;
+ }
+ }
+ else
+ {
+ width = _infiniteCanvasScrollViewer.ViewportWidth;
+ }
+
+ return width / _infiniteCanvasScrollViewer.ZoomFactor;
+ }
+ }
///
/// Initializes a new instance of the class.
@@ -227,12 +269,26 @@ protected override void OnApplyTemplate()
if (double.IsNaN(_infiniteCanvasScrollViewer.Width))
{
- _infiniteCanvasScrollViewer.Width = Window.Current.Bounds.Width;
+ if (ControlHelpers.IsXamlRootAvailable && _infiniteCanvasScrollViewer.XamlRoot != null)
+ {
+ _infiniteCanvasScrollViewer.Width = _infiniteCanvasScrollViewer.XamlRoot.Size.Width;
+ }
+ else
+ {
+ _infiniteCanvasScrollViewer.Width = Window.Current.Bounds.Width;
+ }
}
if (double.IsNaN(_infiniteCanvasScrollViewer.Height))
{
- _infiniteCanvasScrollViewer.Height = Window.Current.Bounds.Height;
+ if (ControlHelpers.IsXamlRootAvailable && _infiniteCanvasScrollViewer.XamlRoot != null)
+ {
+ _infiniteCanvasScrollViewer.Height = _infiniteCanvasScrollViewer.XamlRoot.Size.Height;
+ }
+ else
+ {
+ _infiniteCanvasScrollViewer.Height = Window.Current.Bounds.Height;
+ }
}
base.OnApplyTemplate();
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Menu/Menu.Logic.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Menu/Menu.Logic.cs
index 84fe733e1c4..12768168ffd 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Menu/Menu.Logic.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Menu/Menu.Logic.cs
@@ -190,14 +190,30 @@ internal bool UpdateMenuItemsFlyoutPlacement()
internal FlyoutPlacementMode GetMenuFlyoutPlacementMode()
{
- var ttv = TransformToVisual(Window.Current.Content);
+ UIElement content;
+ double height;
+ double width;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ content = XamlRoot.Content;
+ height = XamlRoot.Size.Height;
+ width = XamlRoot.Size.Width;
+ }
+ else
+ {
+ content = Window.Current.Content;
+ height = Window.Current.Bounds.Height;
+ width = Window.Current.Bounds.Width;
+ }
+
+ var ttv = TransformToVisual(content);
var menuCoords = ttv.TransformPoint(new Point(0, 0));
if (Orientation == Orientation.Horizontal)
{
var menuCenter = menuCoords.Y + (ActualHeight / 2);
- if (menuCenter <= Window.Current.Bounds.Height / 2)
+ if (menuCenter <= height / 2)
{
return FlyoutPlacementMode.Bottom;
}
@@ -210,7 +226,7 @@ internal FlyoutPlacementMode GetMenuFlyoutPlacementMode()
{
var menuCenter = menuCoords.X + (ActualWidth / 2);
- if (menuCenter <= Window.Current.Bounds.Width / 2)
+ if (menuCenter <= width / 2)
{
return FlyoutPlacementMode.Right;
}
@@ -287,7 +303,7 @@ private void HideMenuItemsTooltips()
internal void CalculateBounds()
{
- var ttv = TransformToVisual(Window.Current.Content);
+ var ttv = TransformToVisual(ControlHelpers.IsXamlRootAvailable && XamlRoot != null ? XamlRoot.Content : Window.Current.Content);
Point screenCoords = ttv.TransformPoint(new Point(0, 0));
_bounds.X = screenCoords.X;
_bounds.Y = screenCoords.Y;
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Menu/MenuItem.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Menu/MenuItem.cs
index 684fece2370..d12750d85b0 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Menu/MenuItem.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Menu/MenuItem.cs
@@ -111,6 +111,11 @@ protected override void OnApplyTemplate()
MenuFlyout.Closed -= MenuFlyout_Closed;
}
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ MenuFlyout.XamlRoot = XamlRoot;
+ }
+
if (FlyoutButton != null)
{
FlyoutButton.PointerExited -= FlyoutButton_PointerExited;
@@ -150,7 +155,17 @@ private void MenuItem_IsEnabledChanged(object sender, DependencyPropertyChangedE
internal void CalculateBounds()
{
- var ttv = TransformToVisual(Window.Current.Content);
+ UIElement content;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ content = XamlRoot.Content;
+ }
+ else
+ {
+ content = Window.Current.Content;
+ }
+
+ var ttv = TransformToVisual(content);
Point screenCoords = ttv.TransformPoint(new Point(0, 0));
_bounds.X = screenCoords.X;
_bounds.Y = screenCoords.Y;
@@ -321,7 +336,26 @@ private void MenuFlyout_Opened(object sender, object e)
if (!_menuFlyoutRepositioned)
{
- var popup = VisualTreeHelper.GetOpenPopups(Window.Current).FirstOrDefault(p => p.Child is MenuFlyoutPresenter);
+ IReadOnlyList popups;
+ UIElement content;
+ double outerContentWidth;
+ double outerContentHeight;
+ if (ControlHelpers.IsXamlRootAvailable && MenuFlyout.XamlRoot != null)
+ {
+ popups = VisualTreeHelper.GetOpenPopupsForXamlRoot(MenuFlyout.XamlRoot);
+ content = MenuFlyout.XamlRoot.Content;
+ outerContentWidth = MenuFlyout.XamlRoot.Size.Width;
+ outerContentHeight = MenuFlyout.XamlRoot.Size.Height;
+ }
+ else
+ {
+ popups = VisualTreeHelper.GetOpenPopups(Window.Current);
+ content = Window.Current.Content;
+ outerContentWidth = Window.Current.Bounds.Width;
+ outerContentHeight = Window.Current.Bounds.Height;
+ }
+
+ var popup = popups.FirstOrDefault(p => p.Child is MenuFlyoutPresenter);
if (popup != null)
{
@@ -329,11 +363,11 @@ private void MenuFlyout_Opened(object sender, object e)
var height = mfp.ActualHeight;
var width = mfp.ActualWidth;
- var flytoutButtonPoint = FlyoutButton.TransformToVisual(Window.Current.Content).TransformPoint(new Point(0, 0));
+ var flytoutButtonPoint = FlyoutButton.TransformToVisual(content).TransformPoint(new Point(0, 0));
- if ((width > Window.Current.Bounds.Width - flytoutButtonPoint.X &&
+ if ((width > outerContentWidth - flytoutButtonPoint.X &&
(MenuFlyout.Placement == FlyoutPlacementMode.Bottom)) ||
- (height > Window.Current.Bounds.Height - flytoutButtonPoint.Y &&
+ (height > outerContentHeight - flytoutButtonPoint.Y &&
(MenuFlyout.Placement == FlyoutPlacementMode.Right)))
{
ShowMenuRepositioned(width, height);
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/OrbitView/OrbitViewPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/OrbitView/OrbitViewPanel.cs
index 1c36bbf65fd..ee6e75568ba 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/OrbitView/OrbitViewPanel.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/OrbitView/OrbitViewPanel.cs
@@ -64,12 +64,26 @@ protected override Size MeasureOverride(Size availableSize)
if (double.IsInfinity(width))
{
- width = Window.Current.Bounds.Width;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ width = XamlRoot.Size.Width;
+ }
+ else
+ {
+ width = Window.Current.Bounds.Width;
+ }
}
if (double.IsInfinity(height))
{
- height = Window.Current.Bounds.Height;
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ height = XamlRoot.Size.Height;
+ }
+ else
+ {
+ height = Window.Current.Bounds.Height;
+ }
}
var finalSize = new Size(width, height);
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Properties/AssemblyInfo.cs b/Microsoft.Toolkit.Uwp.UI.Controls/Properties/AssemblyInfo.cs
index 64a4e43ebc0..d2b81648fed 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/Properties/AssemblyInfo.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/Properties/AssemblyInfo.cs
@@ -9,4 +9,5 @@
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: InternalsVisibleTo("UnitTests")]
+[assembly: InternalsVisibleTo("UnitTests.XamlIslands.UWPApp")]
[assembly: NeutralResourcesLanguage("en-US")]
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/TextToolbar/Formats/MarkDown/MarkDownFormatter.cs b/Microsoft.Toolkit.Uwp.UI.Controls/TextToolbar/Formats/MarkDown/MarkDownFormatter.cs
index 113fe7f77bf..a68de9da77a 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/TextToolbar/Formats/MarkDown/MarkDownFormatter.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/TextToolbar/Formats/MarkDown/MarkDownFormatter.cs
@@ -40,6 +40,11 @@ public void StyleHeader(ToolbarButton button)
var list = new ListBox { Margin = new Thickness(0), Padding = new Thickness(0) };
headerFlyout = new Flyout { Content = list };
+ if (ControlHelpers.IsXamlRootAvailable && button.XamlRoot != null)
+ {
+ headerFlyout.XamlRoot = button.XamlRoot;
+ }
+
string headerVal = "#";
for (int i = 1; i <= 5; i++)
{
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/TokenizingTextBox/TokenizingTextBox.cs b/Microsoft.Toolkit.Uwp.UI.Controls/TokenizingTextBox/TokenizingTextBox.cs
index 1d3f7a59125..51ef091685f 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls/TokenizingTextBox/TokenizingTextBox.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls/TokenizingTextBox/TokenizingTextBox.cs
@@ -121,6 +121,11 @@ protected override void OnApplyTemplate()
selectAllMenuItem.Click += (s, e) => SelectAll();
var menuFlyout = new MenuFlyout();
menuFlyout.Items.Add(selectAllMenuItem);
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ menuFlyout.XamlRoot = XamlRoot;
+ }
+
ContextFlyout = menuFlyout;
}
@@ -325,6 +330,11 @@ private async Task AddToken(object data)
var menuFlyout = new MenuFlyout();
menuFlyout.Items.Add(removeMenuItem);
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ menuFlyout.XamlRoot = XamlRoot;
+ }
+
item.ContextFlyout = menuFlyout;
var i = _wrapPanel.Children.Count - 1;
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Microsoft.Toolkit.Uwp.UI.Media.csproj b/Microsoft.Toolkit.Uwp.UI.Media/Microsoft.Toolkit.Uwp.UI.Media.csproj
index c0e7bba86e7..56d5358d419 100644
--- a/Microsoft.Toolkit.Uwp.UI.Media/Microsoft.Toolkit.Uwp.UI.Media.csproj
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Microsoft.Toolkit.Uwp.UI.Media.csproj
@@ -23,6 +23,6 @@
-
+
diff --git a/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs b/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs
index 22191f7871e..ece261b30b7 100644
--- a/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs
+++ b/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs
@@ -10,6 +10,7 @@
using Microsoft.Toolkit.Uwp.Helpers;
using Windows.Storage;
using Windows.Storage.Streams;
+using Windows.System;
using Windows.UI.Xaml.Media.Imaging;
namespace Microsoft.Toolkit.Uwp.UI
@@ -34,11 +35,18 @@ public class ImageCache : CacheBase
///
public static ImageCache Instance => _instance ?? (_instance = new ImageCache());
+ ///
+ /// Gets or sets which DispatcherQueue is used to dispatch UI updates.
+ ///
+ public DispatcherQueue DispatcherQueue { get; set; }
+
///
/// Initializes a new instance of the class.
///
- public ImageCache()
+ /// The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.
+ public ImageCache(DispatcherQueue dispatcherQueue = null)
{
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
_extendedPropertyNames.Add(DateAccessedProperty);
}
@@ -55,7 +63,7 @@ protected override async Task InitializeTypeAsync(Stream stream, Li
throw new FileNotFoundException();
}
- return await DispatcherHelper.ExecuteOnUIThreadAsync(async () =>
+ return await DispatcherQueue.ExecuteOnUIThreadAsync(async () =>
{
BitmapImage image = new BitmapImage();
diff --git a/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs b/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs
index 112c178df0c..9b20f6f2e4e 100644
--- a/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs
+++ b/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs
@@ -4,8 +4,10 @@
using System;
using System.Threading;
+using Microsoft.Toolkit.Uwp.Helpers;
using Windows.Devices.Input;
using Windows.Foundation;
+using Windows.System;
using Windows.UI.Core;
using Windows.UI.Input;
using Windows.UI.Xaml;
@@ -90,7 +92,7 @@ private static void UpdateChange(bool newValue)
///
/// Function to set default value and subscribe to events
///
- private static void SubscribeMiddleClickScrolling()
+ private static void SubscribeMiddleClickScrolling(DispatcherQueue dispatcherQueue)
{
_isPressed = true;
_isMoved = false;
@@ -101,7 +103,7 @@ private static void SubscribeMiddleClickScrolling()
_isCursorAvailable = IsCursorResourceAvailable();
_timer?.Dispose();
- _timer = new Timer(Scroll, null, 5, 5);
+ _timer = new Timer(Scroll, dispatcherQueue, 5, 5);
Window.Current.CoreWindow.PointerMoved -= CoreWindow_PointerMoved;
Window.Current.CoreWindow.PointerReleased -= CoreWindow_PointerReleased;
@@ -135,10 +137,16 @@ private static void UnsubscribeMiddleClickScrolling()
/// Default param for . In this function it will be `null`
private static void Scroll(object state)
{
+ var dispatcherQueue = state as DispatcherQueue;
+ if (dispatcherQueue == null)
+ {
+ return;
+ }
+
var offsetX = _currentPosition.X - _startPosition.X;
var offsetY = _currentPosition.Y - _startPosition.Y;
- SetCursorType(offsetX, offsetY);
+ SetCursorType(dispatcherQueue, offsetX, offsetY);
if (Math.Abs(offsetX) > _threshold || Math.Abs(offsetY) > _threshold)
{
@@ -154,7 +162,7 @@ private static void Scroll(object state)
offsetX = offsetX > _maxSpeed ? _maxSpeed : offsetX;
offsetY = offsetY > _maxSpeed ? _maxSpeed : offsetY;
- RunInUIThread(() =>
+ RunInUIThread(dispatcherQueue, () =>
{
_scrollViewer?.ChangeView(_scrollViewer.HorizontalOffset + offsetX, _scrollViewer.VerticalOffset + offsetY, null, true);
});
@@ -190,7 +198,7 @@ private static void ScrollViewer_PointerPressed(object sender, PointerRoutedEven
// SubscribeMiddle if middle button is pressed
if (pointerPoint.Properties.IsMiddleButtonPressed)
{
- SubscribeMiddleClickScrolling();
+ SubscribeMiddleClickScrolling(DispatcherQueue.GetForCurrentThread());
_startPosition = Window.Current.CoreWindow.PointerPosition;
_currentPosition = Window.Current.CoreWindow.PointerPosition;
@@ -242,7 +250,7 @@ private static void CoreWindow_PointerReleased(CoreWindow sender, PointerEventAr
Window.Current.CoreWindow.PointerPressed -= CoreWindow_PointerPressed;
Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;
- SetCursorType(0, 0);
+ SetCursorType(DispatcherQueue.GetForCurrentThread(), 0, 0);
}
else
{
@@ -270,12 +278,7 @@ private static void CoreWindow_PointerExited(CoreWindow sender, PointerEventArgs
UnsubscribeMiddleClickScrolling();
}
- ///
- /// Change cursor type depend upon offset from starting position
- ///
- /// Horizontal offset from starting position
- /// Vertical offset from starting position
- private static void SetCursorType(double offsetX, double offsetY)
+ private static void SetCursorType(DispatcherQueue dispatcherQueue, double offsetX, double offsetY)
{
if (!_isCursorAvailable)
{
@@ -323,7 +326,7 @@ private static void SetCursorType(double offsetX, double offsetY)
if (_oldCursorID != cursorID)
{
- RunInUIThread(() =>
+ RunInUIThread(dispatcherQueue, () =>
{
Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Custom, cursorID);
});
@@ -364,16 +367,9 @@ private static bool IsCursorResourceAvailable()
return isCursorAvailable;
}
- ///
- /// Run the give input action in UIThread
- ///
- /// Action to be run on UIThread
- private static async void RunInUIThread(Action action)
+ private static async void RunInUIThread(DispatcherQueue dispatcherQueue, Action action)
{
- await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
- {
- action();
- });
+ await dispatcherQueue.ExecuteOnUIThreadAsync(action, DispatcherQueuePriority.Normal);
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI/Extensions/TitleBar/TitleBarExtensions.cs b/Microsoft.Toolkit.Uwp.UI/Extensions/TitleBar/TitleBarExtensions.cs
index 457614d405e..33353b8f485 100644
--- a/Microsoft.Toolkit.Uwp.UI/Extensions/TitleBar/TitleBarExtensions.cs
+++ b/Microsoft.Toolkit.Uwp.UI/Extensions/TitleBar/TitleBarExtensions.cs
@@ -4,7 +4,6 @@
using Windows.UI;
using Windows.UI.ViewManagement;
-using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Extensions
@@ -405,7 +404,7 @@ public static void SetInactiveForegroundColor(Page page, Color value)
private static ApplicationViewTitleBar GetTitleBar()
{
- return IsTitleBarSupported ? Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().TitleBar : null;
+ return IsTitleBarSupported ? ApplicationView.GetForCurrentView()?.TitleBar : null;
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs b/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs
index 42e75842550..9dc2559d506 100644
--- a/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs
+++ b/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs
@@ -4,11 +4,16 @@
using System;
using System.Diagnostics;
-using Windows.ApplicationModel.Core;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
using Windows.Foundation.Metadata;
+using Windows.System;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
+[assembly: InternalsVisibleTo("UnitTests.XamlIslands.UWPApp")]
+
namespace Microsoft.Toolkit.Uwp.UI.Helpers
{
///
@@ -42,6 +47,11 @@ public string CurrentThemeName
///
public bool IsHighContrast { get; set; }
+ ///
+ /// Gets or sets which DispatcherQueue is used to dispatch UI updates.
+ ///
+ public DispatcherQueue DispatcherQueue { get; set; }
+
///
/// An event that fires if the Theme changes.
///
@@ -53,16 +63,22 @@ public string CurrentThemeName
///
/// Initializes a new instance of the class.
///
- public ThemeListener()
+ /// The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.
+ public ThemeListener(DispatcherQueue dispatcherQueue = null)
{
CurrentTheme = Application.Current.RequestedTheme;
IsHighContrast = _accessible.HighContrast;
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
+
_accessible.HighContrastChanged += Accessible_HighContrastChanged;
_settings.ColorValuesChanged += Settings_ColorValuesChanged;
// Fallback in case either of the above fail, we'll check when we get activated next.
- Window.Current.CoreWindow.Activated += CoreWindow_Activated;
+ if (Window.Current != null)
+ {
+ Window.Current.CoreWindow.Activated += CoreWindow_Activated;
+ }
}
private void Accessible_HighContrastChanged(AccessibilitySettings sender, object args)
@@ -76,21 +92,28 @@ private void Accessible_HighContrastChanged(AccessibilitySettings sender, object
// Note: This can get called multiple times during HighContrast switch, do we care?
private async void Settings_ColorValuesChanged(UISettings sender, object args)
+ {
+ await OnColorValuesChanged();
+ }
+
+ // Internal abstraction is used by the Unit Tests
+ internal Task OnColorValuesChanged()
{
// Getting called off thread, so we need to dispatch to request value.
- await CoreApplication.MainView?.CoreWindow?.Dispatcher?.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
- {
- // TODO: This doesn't stop the multiple calls if we're in our faked 'White' HighContrast Mode below.
- if (CurrentTheme != Application.Current.RequestedTheme ||
- IsHighContrast != _accessible.HighContrast)
+ return DispatcherQueue.ExecuteOnUIThreadAsync(
+ () =>
{
+ // TODO: This doesn't stop the multiple calls if we're in our faked 'White' HighContrast Mode below.
+ if (CurrentTheme != Application.Current.RequestedTheme ||
+ IsHighContrast != _accessible.HighContrast)
+ {
#if DEBUG
- Debug.WriteLine("Color Values Changed");
+ Debug.WriteLine("Color Values Changed");
#endif
- UpdateProperties();
- }
- });
+ UpdateProperties();
+ }
+ }, DispatcherQueuePriority.Normal);
}
private void CoreWindow_Activated(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.WindowActivatedEventArgs args)
@@ -133,7 +156,10 @@ public void Dispose()
{
_accessible.HighContrastChanged -= Accessible_HighContrastChanged;
_settings.ColorValuesChanged -= Settings_ColorValuesChanged;
- Window.Current.CoreWindow.Activated -= CoreWindow_Activated;
+ if (Window.Current != null)
+ {
+ Window.Current.CoreWindow.Activated -= CoreWindow_Activated;
+ }
}
}
}
diff --git a/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs b/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs
index b70792c75a7..ac3fe240312 100644
--- a/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs
+++ b/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs
@@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.
using Windows.ApplicationModel.Resources;
+using Windows.UI;
+using Windows.UI.WindowManagement;
+using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.Extensions
{
@@ -17,17 +20,41 @@ public static class StringExtensions
/// Retrieves the provided resource for the current view context.
///
/// Resource key to retrieve.
+ /// to be used to get the from.
+ /// You can retrieve this from a , (XamlIslands), or .
/// string value for given resource or empty string if not found.
- public static string GetViewLocalized(this string resourceKey)
- => ResourceLoader.GetForCurrentView().GetString(resourceKey);
+ public static string GetViewLocalized(this string resourceKey, UIContext uiContext = null)
+ {
+ if (uiContext != null)
+ {
+ var resourceLoader = ResourceLoader.GetForUIContext(uiContext);
+ return resourceLoader.GetString(resourceKey);
+ }
+ else
+ {
+ return ResourceLoader.GetForCurrentView().GetString(resourceKey);
+ }
+ }
///
/// Retrieves the provided resource for the given key for use independent of the UI thread.
///
/// Resource key to retrieve.
+ /// to be used to get the from.
+ /// You can retrieve this from a , (XamlIslands), or .
/// string value for given resource or empty string if not found.
- public static string GetLocalized(this string resourceKey)
- => IndependentLoader.GetString(resourceKey);
+ public static string GetLocalized(this string resourceKey, UIContext uiContext = null)
+ {
+ if (uiContext != null)
+ {
+ var resourceLoader = ResourceLoader.GetForUIContext(uiContext);
+ return resourceLoader.GetString(resourceKey);
+ }
+ else
+ {
+ return IndependentLoader.GetString(resourceKey);
+ }
+ }
///
/// Retrieves the provided resource for the given key for use independent of the UI thread.
diff --git a/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs
index e1389f5122e..f8e78311c55 100644
--- a/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs
+++ b/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs
@@ -12,6 +12,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers
///
/// This class provides static methods helper for executing code in UI thread of the main window.
///
+ [Obsolete]
public static class DispatcherHelper
{
///
diff --git a/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs
new file mode 100644
index 00000000000..93f47ecc2f8
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs
@@ -0,0 +1,239 @@
+// 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.Threading.Tasks;
+using Windows.Foundation.Metadata;
+using Windows.System;
+
+namespace Microsoft.Toolkit.Uwp.Helpers
+{
+ ///
+ /// This class provides static methods helper for executing code in a DispatcherQueue.
+ ///
+ public static class DispatcherQueueHelper
+ {
+ ///
+ /// Extension method for . Offering an actual awaitable with optional result that will be executed on the given dispatcher.
+ ///
+ /// DispatcherQueue of a thread to run .
+ /// Function to be executed on the given dispatcher.
+ /// DispatcherQueue execution priority, default is normal.
+ /// An awaitable for the operation.
+ /// If the current thread has UI access, will be invoked directly.
+ public static Task ExecuteOnUIThreadAsync(this DispatcherQueue dispatcher, Action function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal)
+ {
+ if (function is null)
+ {
+ throw new ArgumentNullException(nameof(function));
+ }
+
+ /* Run the function directly when we have thread access.
+ * Also reuse Task.CompletedTask in case of success,
+ * to skip an unnecessary heap allocation for every invocation. */
+ if (HasThreadAccess(dispatcher))
+ {
+ try
+ {
+ function();
+
+ return Task.CompletedTask;
+ }
+ catch (Exception e)
+ {
+ return Task.FromException(e);
+ }
+ }
+
+ var taskCompletionSource = new TaskCompletionSource
private PrintHelperOptions _defaultPrintHelperOptions;
+ ///
+ /// Gets or sets which DispatcherQueue is used to dispatch UI updates.
+ ///
+ public DispatcherQueue DispatcherQueue { get; set; }
+
///
/// Initializes a new instance of the class.
///
/// XAML panel used to attach printing canvas. Can be hidden in your UI with Opacity = 0 for instance
/// Default settings for the print tasks
- public PrintHelper(Panel canvasContainer, PrintHelperOptions defaultPrintHelperOptions = null)
+ /// The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.
+ public PrintHelper(Panel canvasContainer, PrintHelperOptions defaultPrintHelperOptions = null, DispatcherQueue dispatcherQueue = null)
{
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
+
if (canvasContainer == null)
{
throw new ArgumentNullException();
@@ -197,7 +205,7 @@ public void Dispose()
}
_printCanvas = null;
- DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ DispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
_printDocument.Paginate -= CreatePrintPreviewPages;
_printDocument.GetPreviewPage -= GetPrintPreviewPage;
@@ -221,7 +229,7 @@ private async Task DetachCanvas()
{
if (!_directPrint)
{
- await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ await DispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
_canvasContainer.Children.Remove(_printCanvas);
_printCanvas.Children.Clear();
@@ -254,32 +262,33 @@ private void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs
printTask.Completed += async (s, args) =>
{
// Notify the user when the print operation fails.
- await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
- {
- foreach (var element in _stateBags.Keys)
- {
- _stateBags[element].Restore(element);
- }
-
- _stateBags.Clear();
- _canvasContainer.RequestedTheme = ElementTheme.Default;
- await DetachCanvas();
-
- switch (args.Completion)
+ await DispatcherQueue.ExecuteOnUIThreadAsync(
+ async () =>
{
- case PrintTaskCompletion.Failed:
- OnPrintFailed?.Invoke();
- break;
-
- case PrintTaskCompletion.Canceled:
- OnPrintCanceled?.Invoke();
- break;
-
- case PrintTaskCompletion.Submitted:
- OnPrintSucceeded?.Invoke();
- break;
- }
- });
+ foreach (var element in _stateBags.Keys)
+ {
+ _stateBags[element].Restore(element);
+ }
+
+ _stateBags.Clear();
+ _canvasContainer.RequestedTheme = ElementTheme.Default;
+ await DetachCanvas();
+
+ switch (args.Completion)
+ {
+ case PrintTaskCompletion.Failed:
+ OnPrintFailed?.Invoke();
+ break;
+
+ case PrintTaskCompletion.Canceled:
+ OnPrintCanceled?.Invoke();
+ break;
+
+ case PrintTaskCompletion.Submitted:
+ OnPrintSucceeded?.Invoke();
+ break;
+ }
+ }, DispatcherQueuePriority.Normal);
};
sourceRequested.SetSource(_printDocumentSource);
@@ -471,7 +480,7 @@ private Task AddOnePrintPreviewPage(FrameworkElement element, PrintPageDescripti
// Save state
if (!_stateBags.ContainsKey(element))
{
- var stateBag = new PrintHelperStateBag();
+ var stateBag = new PrintHelperStateBag(DispatcherQueue);
stateBag.Capture(element);
_stateBags.Add(element, stateBag);
}
@@ -506,7 +515,7 @@ private Task AddOnePrintPreviewPage(FrameworkElement element, PrintPageDescripti
element.Margin = new Thickness(marginWidth / 2, marginHeight / 2, marginWidth / 2, marginHeight / 2);
page.Content = element;
- return DispatcherHelper.ExecuteOnUIThreadAsync(
+ return DispatcherQueue.ExecuteOnUIThreadAsync(
() =>
{
// Add the (newly created) page to the print canvas which is part of the visual tree and force it to go
@@ -517,12 +526,12 @@ private Task AddOnePrintPreviewPage(FrameworkElement element, PrintPageDescripti
// Add the page to the page preview collection
_printPreviewPages.Add(page);
- }, Windows.UI.Core.CoreDispatcherPriority.High);
+ }, DispatcherQueuePriority.High);
}
private Task ClearPageCache()
{
- return DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ return DispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
if (!_directPrint)
{
diff --git a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs
index b98c3dd7984..7be4a651451 100644
--- a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs
+++ b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs
@@ -2,6 +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 Windows.System;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.Helpers
@@ -11,6 +12,13 @@ namespace Microsoft.Toolkit.Uwp.Helpers
///
internal class PrintHelperStateBag
{
+ private readonly DispatcherQueue _dispatcherQueue;
+
+ internal PrintHelperStateBag(DispatcherQueue dispatcherQueue)
+ {
+ _dispatcherQueue = dispatcherQueue;
+ }
+
///
/// Gets or sets the stored horizontal alignment.
///
@@ -55,7 +63,7 @@ public void Capture(FrameworkElement element)
/// Element to restore state to
public void Restore(FrameworkElement element)
{
- DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ _dispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
element.HorizontalAlignment = HorizontalAlignment;
element.VerticalAlignment = VerticalAlignment;
diff --git a/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs
index ecfa44c2553..1601ef903c5 100644
--- a/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs
+++ b/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs
@@ -7,6 +7,7 @@
using System.Collections.ObjectModel;
using System.Linq;
using Windows.Foundation.Metadata;
+using Windows.System;
using Windows.System.RemoteSystems;
using Windows.System.Threading;
@@ -24,11 +25,18 @@ public class RemoteDeviceHelper
private RemoteSystemWatcher _remoteSystemWatcher;
+ ///
+ /// Gets or sets which DispatcherQueue is used to dispatch UI updates.
+ ///
+ public DispatcherQueue DispatcherQueue { get; set; }
+
///
/// Initializes a new instance of the class.
///
- public RemoteDeviceHelper()
+ /// The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.
+ public RemoteDeviceHelper(DispatcherQueue dispatcherQueue = null)
{
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
RemoteSystems = new ObservableCollection();
GenerateSystems();
}
@@ -36,8 +44,11 @@ public RemoteDeviceHelper()
///
/// Initializes a new instance of the class.
///
- public RemoteDeviceHelper(List filter)
+ /// Initiate Enumeration with specific RemoteSysemKind with Filters
+ /// The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.
+ public RemoteDeviceHelper(List filter, DispatcherQueue dispatcherQueue = null)
{
+ DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
RemoteSystems = new ObservableCollection();
GenerateSystemsWithFilterAsync(filter);
}
@@ -86,7 +97,7 @@ private void RemoteSystemWatcher_EnumerationCompleted(RemoteSystemWatcher sender
private async void RemoteSystemWatcher_RemoteSystemUpdated(RemoteSystemWatcher sender, RemoteSystemUpdatedEventArgs args)
{
- await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ await DispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
RemoteSystems.Remove(RemoteSystems.First(a => a.Id == args.RemoteSystem.Id));
RemoteSystems.Add(args.RemoteSystem);
@@ -95,7 +106,7 @@ await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
private async void RemoteSystemWatcher_RemoteSystemRemoved(RemoteSystemWatcher sender, RemoteSystemRemovedEventArgs args)
{
- await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ await DispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
RemoteSystems.Remove(RemoteSystems.First(a => a.Id == args.RemoteSystemId));
});
@@ -103,7 +114,7 @@ await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
private async void RemoteSystemWatcher_RemoteSystemAdded(RemoteSystemWatcher sender, RemoteSystemAddedEventArgs args)
{
- await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
+ await DispatcherQueue.ExecuteOnUIThreadAsync(() =>
{
RemoteSystems.Add(args.RemoteSystem);
});
diff --git a/Microsoft.Toolkit.Uwp/Helpers/ScreenUnitHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ScreenUnitHelper.cs
index 0fb75aa4fd5..45b929272d6 100644
--- a/Microsoft.Toolkit.Uwp/Helpers/ScreenUnitHelper.cs
+++ b/Microsoft.Toolkit.Uwp/Helpers/ScreenUnitHelper.cs
@@ -4,6 +4,7 @@
using System;
using Windows.Graphics.Display;
+using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.Helpers
{
@@ -22,8 +23,9 @@ public static class ScreenUnitHelper
/// Start unit
/// End unit
/// The value to convert (using start unit)
+ /// The XamlRoot that will be used to get the screen scale. Required on Xaml Islands.
/// The result of the conversion
- public static float Convert(ScreenUnit from, ScreenUnit to, float value)
+ public static float Convert(ScreenUnit from, ScreenUnit to, float value, XamlRoot xamlRoot = null)
{
if (from == to)
{
@@ -45,7 +47,7 @@ public static float Convert(ScreenUnit from, ScreenUnit to, float value)
if (to == ScreenUnit.EffectivePixel)
{
- return value / (float)DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+ return value / GetScale(xamlRoot);
}
throw new ArgumentOutOfRangeException(nameof(to));
@@ -79,7 +81,7 @@ public static float Convert(ScreenUnit from, ScreenUnit to, float value)
case ScreenUnit.EffectivePixel:
if (to == ScreenUnit.Pixel)
{
- return value * (float)DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+ return value * GetScale(xamlRoot);
}
throw new ArgumentOutOfRangeException(nameof(to));
@@ -88,5 +90,17 @@ public static float Convert(ScreenUnit from, ScreenUnit to, float value)
throw new ArgumentOutOfRangeException(nameof(from));
}
}
+
+ private static float GetScale(XamlRoot xamlRoot)
+ {
+ if (xamlRoot != null)
+ {
+ return (float)xamlRoot.RasterizationScale;
+ }
+ else
+ {
+ return (float)DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+ }
+ }
}
}
diff --git a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs
index 978aa9a3ef1..9c5ffd40d32 100644
--- a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs
+++ b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs
@@ -12,6 +12,7 @@
using Windows.System;
using Windows.System.Profile;
using Windows.System.UserProfile;
+using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.Helpers
{
@@ -180,7 +181,8 @@ public TimeSpan AppUptime
/// Tracks information about the app's launch.
///
/// Details about the launch request and process.
- public void TrackAppUse(LaunchActivatedEventArgs args)
+ /// The XamlRoot object from your visual tree.
+ public void TrackAppUse(IActivatedEventArgs args, XamlRoot xamlRoot = null)
{
if (args.PreviousExecutionState == ApplicationExecutionState.ClosedByUser
|| args.PreviousExecutionState == ApplicationExecutionState.NotRunning)
@@ -213,24 +215,42 @@ public void TrackAppUse(LaunchActivatedEventArgs args)
: DateTime.MinValue;
}
- void App_VisibilityChanged(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.VisibilityChangedEventArgs e)
+ if (xamlRoot != null)
{
- if (e.Visible)
+ void XamlRoot_Changed(XamlRoot sender, XamlRootChangedEventArgs e)
{
- _sessionStart = DateTime.UtcNow;
+ UpdateVisibility(sender.IsHostVisible);
}
- else
+
+ xamlRoot.Changed -= XamlRoot_Changed;
+ xamlRoot.Changed += XamlRoot_Changed;
+ }
+ else
+ {
+ void App_VisibilityChanged(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.VisibilityChangedEventArgs e)
{
- var subsessionLength = DateTime.UtcNow.Subtract(_sessionStart).Ticks;
+ UpdateVisibility(e.Visible);
+ }
- var uptimeSoFar = _localObjectStorageHelper.Read(nameof(AppUptime));
+ Windows.UI.Core.CoreWindow.GetForCurrentThread().VisibilityChanged -= App_VisibilityChanged;
+ Windows.UI.Core.CoreWindow.GetForCurrentThread().VisibilityChanged += App_VisibilityChanged;
+ }
+ }
- _localObjectStorageHelper.Save(nameof(AppUptime), uptimeSoFar + subsessionLength);
- }
+ private void UpdateVisibility(bool visible)
+ {
+ if (visible)
+ {
+ _sessionStart = DateTime.UtcNow;
}
+ else
+ {
+ var subsessionLength = DateTime.UtcNow.Subtract(_sessionStart).Ticks;
- Windows.UI.Core.CoreWindow.GetForCurrentThread().VisibilityChanged -= App_VisibilityChanged;
- Windows.UI.Core.CoreWindow.GetForCurrentThread().VisibilityChanged += App_VisibilityChanged;
+ var uptimeSoFar = _localObjectStorageHelper.Read(nameof(AppUptime));
+
+ _localObjectStorageHelper.Save(nameof(AppUptime), uptimeSoFar + subsessionLength);
+ }
}
///
diff --git a/UnitTests/Helpers/Test_DispatcherHelper.cs b/UnitTests/Helpers/Test_DispatcherHelper.cs
index 3f6803e65fb..94e37242419 100644
--- a/UnitTests/Helpers/Test_DispatcherHelper.cs
+++ b/UnitTests/Helpers/Test_DispatcherHelper.cs
@@ -13,6 +13,7 @@
namespace UnitTests.Helpers
{
+#pragma warning disable CS0612 // Type or member is obsolete
[TestClass]
public class Test_DispatcherHelper
{
@@ -30,9 +31,9 @@ public void Test_DispatcherHelper_Action_Ok_UIThread()
{
DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
- var textBlock = new TextBlock { Text = nameof(Test_DispatcherHelper_Action_Ok_NonUIThread) };
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherHelper_Action_Ok_UIThread) };
- Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_Action_Ok_NonUIThread));
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_Action_Ok_UIThread));
}).Wait();
}
@@ -77,10 +78,10 @@ public void Test_DispatcherHelper_FuncOfT_Ok_UIThread()
{
var textBlock = DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
- return new TextBlock { Text = nameof(Test_DispatcherHelper_FuncOfT_Ok_NonUIThread) };
+ return new TextBlock { Text = nameof(Test_DispatcherHelper_FuncOfT_Ok_UIThread) };
}).Result;
- Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_FuncOfT_Ok_NonUIThread));
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_FuncOfT_Ok_UIThread));
}
[TestCategory("Helpers")]
@@ -128,9 +129,9 @@ public void Test_DispatcherHelper_FuncOfTask_Ok_UIThread()
{
DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
- var textBlock = new TextBlock { Text = nameof(Test_DispatcherHelper_FuncOfTask_Ok_NonUIThread) };
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherHelper_FuncOfTask_Ok_UIThread) };
- Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_FuncOfTask_Ok_NonUIThread));
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_FuncOfTask_Ok_UIThread));
return Task.CompletedTask;
}).Wait();
@@ -179,9 +180,9 @@ public void Test_DispatcherHelper_FuncOfTaskOfT_Ok_UIThread()
{
DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
- var textBlock = new TextBlock { Text = nameof(Test_DispatcherHelper_FuncOfTaskOfT_Ok_NonUIThread) };
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherHelper_FuncOfTaskOfT_Ok_UIThread) };
- Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_FuncOfTaskOfT_Ok_NonUIThread));
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherHelper_FuncOfTaskOfT_Ok_UIThread));
return Task.FromResult(1);
}).Wait();
@@ -218,4 +219,5 @@ public void Test_DispatcherHelper_FuncOfTaskOfT_Exception()
Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException));
}
}
+#pragma warning restore CS0612 // Type or member is obsolete
}
diff --git a/UnitTests/Helpers/Test_DispatcherQueueHelper.cs b/UnitTests/Helpers/Test_DispatcherQueueHelper.cs
new file mode 100644
index 00000000000..ba81bb1afc6
--- /dev/null
+++ b/UnitTests/Helpers/Test_DispatcherQueueHelper.cs
@@ -0,0 +1,293 @@
+// 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.Diagnostics.CodeAnalysis;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System.Linq;
+using System.Threading.Tasks;
+using Windows.UI.Xaml.Controls;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Windows.ApplicationModel.Core;
+using Windows.UI.Core;
+using Windows.System;
+
+namespace UnitTests.Helpers
+{
+ [TestClass]
+ [Ignore("Ignored until issue on .Net Native is fixed. These are working.")]
+ public class Test_DispatcherQueueHelper
+ {
+ private const int TIME_OUT = 5000;
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void Test_DispatcherQueueHelper_Action_Null()
+ {
+ DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Action));
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_Action_Ok_UIThread()
+ {
+ DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () =>
+ {
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_Action_Ok_UIThread) };
+
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_Action_Ok_UIThread));
+ }).Wait();
+ }
+
+ [TestCategory("Helpers")]
+ [TestMethod]
+ public async Task Test_DispatcherQueueHelper_Action_Ok_NonUIThread()
+ {
+ var taskSource = new TaskCompletionSource();
+ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
+ CoreDispatcherPriority.Normal, async () =>
+ {
+ try
+ {
+ var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
+ await Task.Run(async () =>
+ {
+ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () =>
+ {
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_Action_Ok_NonUIThread) };
+
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_Action_Ok_NonUIThread));
+
+ taskSource.SetResult(null);
+ });
+ });
+ }
+ catch (Exception e)
+ {
+ taskSource.SetException(e);
+ }
+ });
+ await taskSource.Task;
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_Action_Exception()
+ {
+ var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () =>
+ {
+ throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_Action_Exception));
+ });
+
+ Assert.IsNotNull(task);
+ Assert.AreEqual(task.Status, TaskStatus.Faulted);
+ Assert.IsNotNull(task.Exception);
+ Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException));
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void Test_DispatcherQueueHelper_FuncOfT_Null()
+ {
+ DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Func));
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_FuncOfT_Ok_UIThread()
+ {
+ var textBlock = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () =>
+ {
+ return new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_UIThread) };
+ }).Result;
+
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_UIThread));
+ }
+
+ [TestCategory("Helpers")]
+ [TestMethod]
+ public async Task Test_DispatcherQueueHelper_FuncOfT_Ok_NonUIThread()
+ {
+ var taskSource = new TaskCompletionSource();
+ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
+ CoreDispatcherPriority.Normal, async () =>
+ {
+ try
+ {
+ var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
+ await Task.Run(async () =>
+ {
+ var textBlock = await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () =>
+ {
+ return new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_NonUIThread) };
+ });
+ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () =>
+ {
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_NonUIThread));
+ taskSource.SetResult(null);
+ });
+ });
+ }
+ catch (Exception e)
+ {
+ taskSource.SetException(e);
+ }
+ });
+ await taskSource.Task;
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_FuncOfT_Exception()
+ {
+ var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), new Func(() =>
+ {
+ throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_FuncOfT_Exception));
+ }));
+
+ Assert.IsNotNull(task);
+ Assert.AreEqual(task.Status, TaskStatus.Faulted);
+ Assert.IsNotNull(task.Exception);
+ Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException));
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ [SuppressMessage("Style", "IDE0034", Justification = "Explicit overload for clarity")]
+ public void Test_DispatcherQueueHelper_FuncOfTask_Null()
+ {
+ DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Func));
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_FuncOfTask_Ok_UIThread()
+ {
+ DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () =>
+ {
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfTask_Ok_UIThread) };
+
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfTask_Ok_UIThread));
+
+ return Task.CompletedTask;
+ }).Wait();
+ }
+
+ [TestCategory("Helpers")]
+ [TestMethod]
+ public async Task Test_DispatcherQueueHelper_FuncOfTask_Ok_NonUIThread()
+ {
+ var taskSource = new TaskCompletionSource();
+ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
+ CoreDispatcherPriority.Normal, async () =>
+ {
+ try
+ {
+ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), async () =>
+ {
+ await Task.Yield();
+
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfTask_Ok_NonUIThread) };
+
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfTask_Ok_NonUIThread));
+
+ taskSource.SetResult(null);
+ });
+ }
+ catch (Exception e)
+ {
+ taskSource.SetException(e);
+ }
+ });
+ await taskSource.Task;
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_FuncOfTask_Exception()
+ {
+ var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), new Func(() =>
+ {
+ throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_FuncOfTask_Exception));
+ }));
+
+ Assert.IsNotNull(task);
+ Assert.AreEqual(task.Status, TaskStatus.Faulted);
+ Assert.IsNotNull(task.Exception);
+ Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException));
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void Test_DispatcherQueueHelper_FuncOfTaskOfT_Null()
+ {
+ DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Func>));
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_UIThread()
+ {
+ DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () =>
+ {
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_UIThread) };
+
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_UIThread));
+
+ return Task.FromResult(1);
+ }).Wait();
+ }
+
+ [TestCategory("Helpers")]
+ [TestMethod]
+ public async Task Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_NonUIThread()
+ {
+ var taskSource = new TaskCompletionSource();
+ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
+ CoreDispatcherPriority.Normal, async () =>
+ {
+ try
+ {
+ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), async () =>
+ {
+ await Task.Yield();
+
+ var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_NonUIThread) };
+
+ Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_NonUIThread));
+
+ taskSource.SetResult(null);
+
+ return textBlock;
+ });
+ }
+ catch (Exception e)
+ {
+ taskSource.SetException(e);
+ }
+ });
+ await taskSource.Task;
+ }
+
+ [TestCategory("Helpers")]
+ [UITestMethod]
+ public void Test_DispatcherQueueHelper_FuncOfTaskOfT_Exception()
+ {
+ var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), new Func>(() =>
+ {
+ throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_FuncOfTaskOfT_Exception));
+ }));
+
+ Assert.IsNotNull(task);
+ Assert.AreEqual(task.Status, TaskStatus.Faulted);
+ Assert.IsNotNull(task.Exception);
+ Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException));
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.Notifications.Shared/.editorconfig b/UnitTests/UnitTests.Notifications.Shared/.editorconfig
new file mode 100644
index 00000000000..68caad1b9dc
--- /dev/null
+++ b/UnitTests/UnitTests.Notifications.Shared/.editorconfig
@@ -0,0 +1,7 @@
+[*.{cs,vb}]
+
+# SA1601: Partial elements should be documented
+dotnet_diagnostic.SA1601.severity = none
+dotnet_diagnostic.CS1573.severity = none
+dotnet_diagnostic.CS1591.severity = none
+dotnet_diagnostic.CS1712.severity = none
\ No newline at end of file
diff --git a/UnitTests/UnitTests.Notifications.UWP/UnitTests.Notifications.UWP.csproj b/UnitTests/UnitTests.Notifications.UWP/UnitTests.Notifications.UWP.csproj
index f1df22649e9..9de862b14da 100644
--- a/UnitTests/UnitTests.Notifications.UWP/UnitTests.Notifications.UWP.csproj
+++ b/UnitTests/UnitTests.Notifications.UWP/UnitTests.Notifications.UWP.csproj
@@ -124,7 +124,7 @@
- 6.2.9
+ 6.2.10
1.2.0
diff --git a/UnitTests/UnitTests.Notifications.WinRT/UnitTests.Notifications.WinRT.csproj b/UnitTests/UnitTests.Notifications.WinRT/UnitTests.Notifications.WinRT.csproj
index 3d76f6342fd..4c48bc07fed 100644
--- a/UnitTests/UnitTests.Notifications.WinRT/UnitTests.Notifications.WinRT.csproj
+++ b/UnitTests/UnitTests.Notifications.WinRT/UnitTests.Notifications.WinRT.csproj
@@ -124,7 +124,7 @@
- 6.2.9
+ 6.2.10
2.1.0
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Images/LockScreenLogo.scale-200.png b/UnitTests/UnitTests.XamlIslands.Package/Images/LockScreenLogo.scale-200.png
new file mode 100644
index 00000000000..735f57adb5d
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.Package/Images/LockScreenLogo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Images/SplashScreen.scale-200.png b/UnitTests/UnitTests.XamlIslands.Package/Images/SplashScreen.scale-200.png
new file mode 100644
index 00000000000..023e7f1feda
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.Package/Images/SplashScreen.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Images/Square150x150Logo.scale-200.png b/UnitTests/UnitTests.XamlIslands.Package/Images/Square150x150Logo.scale-200.png
new file mode 100644
index 00000000000..af49fec1a54
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.Package/Images/Square150x150Logo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Images/Square44x44Logo.scale-200.png b/UnitTests/UnitTests.XamlIslands.Package/Images/Square44x44Logo.scale-200.png
new file mode 100644
index 00000000000..ce342a2ec8a
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.Package/Images/Square44x44Logo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/UnitTests/UnitTests.XamlIslands.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 00000000000..f6c02ce97e0
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Images/StoreLogo.png b/UnitTests/UnitTests.XamlIslands.Package/Images/StoreLogo.png
new file mode 100644
index 00000000000..7385b56c0e4
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.Package/Images/StoreLogo.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Images/Wide310x150Logo.scale-200.png b/UnitTests/UnitTests.XamlIslands.Package/Images/Wide310x150Logo.scale-200.png
new file mode 100644
index 00000000000..288995b397f
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.Package/Images/Wide310x150Logo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.Package/Package.appxmanifest b/UnitTests/UnitTests.XamlIslands.Package/Package.appxmanifest
new file mode 100644
index 00000000000..1d1aaf29eda
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.Package/Package.appxmanifest
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+ UnitTests.XamlIslands.Package
+ Microsoft
+ Images\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UnitTests/UnitTests.XamlIslands.Package/UnitTests.XamlIslands.Package.wapproj b/UnitTests/UnitTests.XamlIslands.Package/UnitTests.XamlIslands.Package.wapproj
new file mode 100644
index 00000000000..a6903f454c6
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.Package/UnitTests.XamlIslands.Package.wapproj
@@ -0,0 +1,98 @@
+
+
+
+ 15.0
+
+
+
+ Debug
+ x86
+
+
+ Release
+ x86
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+ Debug
+ AnyCPU
+
+
+ Release
+ AnyCPU
+
+
+
+ $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\
+
+
+
+ dcfbf9f1-2bbe-498d-b6c9-8ade50c06cdc
+ 10.0.18362.0
+ 10.0.18362.0
+ en-US
+ false
+ ..\UnitTests.XamlIslands\UnitTests.XamlIslands.csproj
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+
+
+ Retail
+ Debug
+ $(PlatformShortName)
+ true
+
+
+
+
+
+ <_TemporaryFilteredWapProjOutput Include="@(_FilteredNonWapProjProjectOutput)" />
+ <_FilteredNonWapProjProjectOutput Remove="@(_TemporaryFilteredWapProjOutput)" />
+ <_FilteredNonWapProjProjectOutput Include="@(_TemporaryFilteredWapProjOutput)">
+
+
+
+
+
+
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/App.xaml b/UnitTests/UnitTests.XamlIslands.UWPApp/App.xaml
new file mode 100644
index 00000000000..0ff39e7d274
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/App.xaml
@@ -0,0 +1,7 @@
+
+
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/App.xaml.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/App.xaml.cs
new file mode 100644
index 00000000000..b62796cd941
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/App.xaml.cs
@@ -0,0 +1,23 @@
+// 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.Toolkit.Win32.UI.XamlHost;
+using Windows.System;
+using Windows.UI.Xaml;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ public sealed partial class App : XamlApplication
+ {
+ internal static DispatcherQueue Dispatcher { get; set; }
+
+ internal static XamlRoot XamlRoot { get; set; }
+
+ public App()
+ {
+ Initialize();
+ InitializeComponent();
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/LockScreenLogo.scale-200.png b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 00000000000..735f57adb5d
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/LockScreenLogo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/SplashScreen.scale-200.png b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/SplashScreen.scale-200.png
new file mode 100644
index 00000000000..023e7f1feda
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/SplashScreen.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square150x150Logo.scale-200.png b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 00000000000..af49fec1a54
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square150x150Logo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square44x44Logo.scale-200.png b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 00000000000..ce342a2ec8a
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square44x44Logo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 00000000000..f6c02ce97e0
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/StoreLogo.png b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/StoreLogo.png
new file mode 100644
index 00000000000..7385b56c0e4
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/StoreLogo.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Wide310x150Logo.scale-200.png b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 00000000000..288995b397f
Binary files /dev/null and b/UnitTests/UnitTests.XamlIslands.UWPApp/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/Assert.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/Assert.cs
new file mode 100644
index 00000000000..c192ef9bfdc
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/Assert.cs
@@ -0,0 +1,19 @@
+// 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;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting
+{
+ public static class Assert
+ {
+ internal static void AreEqual(object expected, object actual)
+ {
+ if (!expected.Equals(actual))
+ {
+ throw new Exception($"Assert.AreEqual failed. Expected:<{expected}>. Actual:<{actual}>.");
+ }
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/IgnoreAttribute.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/IgnoreAttribute.cs
new file mode 100644
index 00000000000..c3ea2a6ce70
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/IgnoreAttribute.cs
@@ -0,0 +1,12 @@
+// 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;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting
+{
+ public class IgnoreAttribute : Attribute
+ {
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestClassAttribute.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestClassAttribute.cs
new file mode 100644
index 00000000000..1370afd2190
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestClassAttribute.cs
@@ -0,0 +1,12 @@
+// 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;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting
+{
+ public class TestClassAttribute : Attribute
+ {
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestCleanupAttribute.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestCleanupAttribute.cs
new file mode 100644
index 00000000000..5892b5c26d6
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestCleanupAttribute.cs
@@ -0,0 +1,12 @@
+// 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;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting
+{
+ public class TestCleanupAttribute : Attribute
+ {
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestInitializeAttribute.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestInitializeAttribute.cs
new file mode 100644
index 00000000000..69e7f95b589
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestInitializeAttribute.cs
@@ -0,0 +1,12 @@
+// 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;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting
+{
+ public class TestInitializeAttribute : Attribute
+ {
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestMethodAttribute.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestMethodAttribute.cs
new file mode 100644
index 00000000000..db9ff5407de
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/FakeTestClasses/TestMethodAttribute.cs
@@ -0,0 +1,12 @@
+// 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;
+
+namespace Microsoft.VisualStudio.TestTools.UnitTesting
+{
+ public class TestMethodAttribute : Attribute
+ {
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Package.appxmanifest b/UnitTests/UnitTests.XamlIslands.UWPApp/Package.appxmanifest
new file mode 100644
index 00000000000..481c2c4426a
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/Package.appxmanifest
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+ UnitTests.XamlIslands.UWPApp
+ Microsoft
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Properties/AssemblyInfo.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000000..37c4bfdef0f
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/Properties/AssemblyInfo.cs
@@ -0,0 +1,30 @@
+// 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.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("UnitTests.XamlIslands.UWPApp")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("UnitTests.XamlIslands.UWPApp")]
+[assembly: AssemblyCopyright("Copyright © 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Properties/Default.rd.xml b/UnitTests/UnitTests.XamlIslands.UWPApp/Properties/Default.rd.xml
new file mode 100644
index 00000000000..af00722cdf9
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/Properties/Default.rd.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/STATestClassAttribute.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/STATestClassAttribute.cs
new file mode 100644
index 00000000000..2874de0183f
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/STATestClassAttribute.cs
@@ -0,0 +1,23 @@
+// 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.VisualStudio.TestTools.UnitTesting;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ public class STATestClassAttribute : TestClassAttribute
+ {
+ /*
+ public override TestMethodAttribute GetTestMethodAttribute(TestMethodAttribute testMethodAttribute)
+ {
+ if (testMethodAttribute is STATestMethodAttribute)
+ {
+ return testMethodAttribute;
+ }
+
+ return new STATestMethodAttribute(base.GetTestMethodAttribute(testMethodAttribute));
+ }
+ */
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/STATestMethodAttribute.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/STATestMethodAttribute.cs
new file mode 100644
index 00000000000..9114d709cdc
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/STATestMethodAttribute.cs
@@ -0,0 +1,52 @@
+// 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.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ public class STATestMethodAttribute : TestMethodAttribute
+ {
+ /*
+ private readonly TestMethodAttribute _testMethodAttribute;
+
+ public STATestMethodAttribute()
+ {
+ }
+
+ public STATestMethodAttribute(TestMethodAttribute testMethodAttribute)
+ {
+ _testMethodAttribute = testMethodAttribute;
+ }
+
+ public override TestResult[] Execute(ITestMethod testMethod)
+ {
+ if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
+ {
+ return Invoke(testMethod);
+ }
+
+ TestResult[] result = null;
+
+ var thread = new Thread(() => result = Invoke(testMethod));
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
+
+ return result;
+ }
+
+ private TestResult[] Invoke(ITestMethod testMethod)
+ {
+ if (_testMethodAttribute != null)
+ {
+ return _testMethodAttribute.Execute(testMethod);
+ }
+
+ return new[] { testMethod.Invoke(null) };
+ }
+ */
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/Strings/en-us/Resources.resw b/UnitTests/UnitTests.XamlIslands.UWPApp/Strings/en-us/Resources.resw
new file mode 100644
index 00000000000..291d768851a
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/Strings/en-us/Resources.resw
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ABCDEF
+
+
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml b/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml
new file mode 100644
index 00000000000..1af0c478ab1
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml.cs
new file mode 100644
index 00000000000..34754312ce1
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml.cs
@@ -0,0 +1,223 @@
+// 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.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Windows.System;
+using Windows.UI;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Documents;
+using Windows.UI.Xaml.Media;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ public sealed partial class TestsPage
+ {
+ internal static TestsPage Instance { get; private set; }
+
+ internal void SetMainTestContent(UIElement content)
+ {
+ MainTestContent.Child = content;
+ }
+
+ public TestsPage()
+ {
+ Instance = this;
+ InitializeComponent();
+ }
+
+ private async void Button_Click(object sender, RoutedEventArgs e)
+ {
+ await RunTestsAsync();
+ }
+
+ public async Task RunTestsAsync()
+ {
+ richTextBlock.Blocks.Clear();
+ App.Dispatcher = DispatcherQueue.GetForCurrentThread();
+ App.XamlRoot = XamlRoot;
+
+ await Task.Run(async () =>
+ {
+ TestResult testResult = default;
+
+ var sw = new Stopwatch();
+
+ await WriteLineAsync("--- Starting Tests Execution ---");
+
+ sw.Start();
+
+ foreach (var testClass in typeof(XamlIslandsTest_SystemInformation).Assembly.GetTypes())
+ {
+ Attribute[] attributes = Attribute.GetCustomAttributes(testClass);
+
+ foreach (var attribute in attributes)
+ {
+ if (attribute is STATestClassAttribute || attribute is TestClassAttribute)
+ {
+ var partialTestResult = await RunTestsAsync(testClass);
+ testResult += partialTestResult;
+ break;
+ }
+ }
+ }
+
+ sw.Stop();
+
+ var color = testResult.Failed > 0 ? Colors.Red : Colors.Green;
+ await WriteLineAsync($"--- Finished Tests Execution ---", color);
+
+ if (testResult.Ignored > 0)
+ {
+ await WriteLineAsync($"--- \tIgnored: {testResult.Ignored} ---", Colors.Orange);
+ }
+
+ await WriteLineAsync($"--- \tPassed: {testResult.Passed} ---", Colors.Green);
+ await WriteLineAsync($"--- \tFailed: {testResult.Failed} ---", Colors.Red);
+ await WriteLineAsync($"--- \tTotal: {testResult.Count} ---");
+
+ await WriteLineAsync($"--- Duration - {sw.Elapsed} ---");
+ });
+ }
+
+ private async Task RunTestsAsync(Type type)
+ {
+ int count = 0;
+ int passed = 0;
+ int ignored = 0;
+ var initMethod = GetFirstMethod(type, typeof(TestInitializeAttribute));
+ var cleanupMethod = GetFirstMethod(type, typeof(TestCleanupAttribute));
+
+ foreach (var method in type.GetMethods())
+ {
+ Attribute[] attributes = Attribute.GetCustomAttributes(method);
+
+ if (attributes.Any(a => a is STATestMethodAttribute || a is TestMethodAttribute))
+ {
+ count++;
+
+ if (attributes.Any(a => a is IgnoreAttribute))
+ {
+ ignored++;
+ continue;
+ }
+
+ try
+ {
+ await WriteLineAsync($"{type.FullName}.{method.Name}\t - \t Running...");
+
+ var instance = Activator.CreateInstance(type);
+
+ if (initMethod != null)
+ {
+ var resultInit = initMethod.Invoke(instance, null);
+ if (resultInit is Task taskInit)
+ {
+ await taskInit;
+ }
+ }
+
+ var result = method.Invoke(instance, null);
+ if (result is Task t)
+ {
+ await t;
+ }
+
+ if (cleanupMethod != null)
+ {
+ var resultCleanup = cleanupMethod.Invoke(instance, null);
+ if (resultCleanup is Task taskCleanup)
+ {
+ await taskCleanup;
+ }
+ }
+
+ await WriteLineAsync($"{type.FullName}.{method.Name}\t - \t PASS ", Colors.Green, true);
+ passed++;
+ }
+ catch (Exception ex)
+ {
+ await WriteLineAsync($"{type.FullName}.{method.Name}\t - \t FAIL :{Environment.NewLine}{ex}", Colors.Red, true);
+ }
+ finally
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ SetMainTestContent(null);
+ });
+ }
+ }
+ }
+
+ return new TestResult(count, passed, ignored);
+ }
+
+ private Task WriteLineAsync(string message, Color? color = null, bool deleteLastLine = false)
+ {
+ Debug.WriteLine(message);
+ return App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ if (deleteLastLine)
+ {
+ richTextBlock.Blocks.Remove(richTextBlock.Blocks.Last());
+ }
+
+ var paragraph = new Paragraph();
+ if (color != null)
+ {
+ paragraph.Foreground = new SolidColorBrush(color.Value);
+ }
+
+ paragraph.Inlines.Add(new Run
+ {
+ Text = message
+ });
+ richTextBlock.Blocks.Add(paragraph);
+ });
+ }
+
+ private struct TestResult
+ {
+ public int Count { get; }
+
+ public int Passed { get; }
+
+ public int Ignored { get; }
+
+ public int Failed => Count - Passed - Ignored;
+
+ public TestResult(int count, int passed, int ignored)
+ {
+ Count = count;
+ Passed = passed;
+ Ignored = ignored;
+ }
+
+ public static TestResult operator +(TestResult a, TestResult b) => new TestResult(a.Count + b.Count, a.Passed + b.Passed, a.Ignored + b.Ignored);
+ }
+
+ private MethodInfo GetFirstMethod(Type ofType, Type attributeType)
+ {
+ foreach (var method in ofType.GetMethods())
+ {
+ Attribute[] attributes = Attribute.GetCustomAttributes(method);
+
+ foreach (Attribute attribute in attributes)
+ {
+ if (attribute.GetType() == attributeType)
+ {
+ return method;
+ }
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/UnitTests.XamlIslands.UWPApp.csproj b/UnitTests/UnitTests.XamlIslands.UWPApp/UnitTests.XamlIslands.UWPApp.csproj
new file mode 100644
index 00000000000..3a3ad5d52a0
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/UnitTests.XamlIslands.UWPApp.csproj
@@ -0,0 +1,216 @@
+
+
+
+
+ Debug
+ x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}
+ AppContainerExe
+ Properties
+ UnitTests.XamlIslands.UWPApp
+ UnitTests.XamlIslands.UWPApp
+ en-US
+ UAP
+ 10.0.18362.0
+ 10.0.18362.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ true
+ false
+ false
+ false
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x86
+ false
+ prompt
+ true
+
+
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+ true
+
+
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM64
+ false
+ prompt
+ true
+ true
+
+
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM64
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x64
+ false
+ prompt
+ true
+
+
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+ true
+ true
+
+
+ PackageReference
+
+
+
+ App.xaml
+
+
+
+
+
+
+
+
+
+
+
+ TestsPage.xaml
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+ 6.2.10
+
+
+ 6.0.0
+
+
+
+
+
+ {42ca4935-54be-42ea-ac19-992378c08de6}
+ Microsoft.Toolkit.Parsers
+
+
+ {e9faabfb-d726-42c1-83c1-cb46a29fea81}
+ Microsoft.Toolkit.Uwp.UI.Controls
+
+
+ {3dd8aa7c-3569-4e51-992f-0c2257e8878e}
+ Microsoft.Toolkit.Uwp.UI
+
+
+ {805f80df-75c6-4c2f-8fd9-b47f6d0df5a3}
+ Microsoft.Toolkit.Uwp
+
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_DropShadowPanel.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_DropShadowPanel.cs
new file mode 100644
index 00000000000..be3a7438b71
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_DropShadowPanel.cs
@@ -0,0 +1,60 @@
+// 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.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.UI.Controls;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Windows.UI;
+using Windows.UI.Xaml.Controls;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ [STATestClass]
+ public partial class XamlIslandsTest_DropShadowPanel
+ {
+ private DropShadowPanel _dropShadowPanel;
+
+ [TestInitialize]
+ public async Task Init()
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ _dropShadowPanel = new DropShadowPanel
+ {
+ BlurRadius = 8,
+ ShadowOpacity = 1,
+ OffsetX = 2,
+ OffsetY = 2,
+ Color = Colors.Black,
+ VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center,
+ HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
+ IsMasked = true
+ };
+ TestsPage.Instance.SetMainTestContent(_dropShadowPanel);
+ });
+ }
+
+ [TestMethod]
+ public async Task DropShadowPanel_RendersFine()
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(async () =>
+ {
+ var textBlock = new TextBlock
+ {
+ TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap,
+ Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eget sem luctus, gravida diam cursus, rutrum ipsum." +
+"Pellentesque semper magna nec sapien ornare tincidunt. Sed pellentesque, turpis quis laoreet pellentesque, urna sapien efficitur nulla," +
+"at interdum dolor sapien ut odio. Sed ullamcorper sapien velit, id finibus risus gravida vitae. Morbi ac ultrices lectus. Aenean felis" +
+"justo, aliquet a risus ut, condimentum malesuada metus. Duis vehicula pharetra dolor vel finibus. Nunc auctor tortor nunc, in varius velit" +
+"lobortis vel. Duis viverra, ante id mollis mattis, sem mauris ullamcorper dolor, sed rhoncus est erat eget ligula. Aliquam rutrum velit et" +
+"felis sollicitudin, eget dapibus dui accumsan."
+ };
+
+ _dropShadowPanel.Content = textBlock;
+ await Task.Delay(3000);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_Eyedropper.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_Eyedropper.cs
new file mode 100644
index 00000000000..aa18eaf7b3a
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_Eyedropper.cs
@@ -0,0 +1,59 @@
+// 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.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.UI.Controls;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Windows.Devices.Input;
+using Windows.Foundation;
+using Windows.UI;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ [STATestClass]
+ public partial class XamlIslandsTest_Eyedropper
+ {
+ [TestMethod]
+ public async Task Eyedropper_DoesntCrash()
+ {
+ Eyedropper eyedropper = null;
+ Color? color = null;
+ _ = App.Dispatcher.ExecuteOnUIThreadAsync(async () =>
+ {
+ eyedropper = new Eyedropper
+ {
+ XamlRoot = App.XamlRoot
+ };
+ color = await eyedropper.Open();
+ });
+
+ await App.Dispatcher.ExecuteOnUIThreadAsync(async () =>
+ {
+ var xamlRoot = App.XamlRoot;
+
+ var pos = new Point(xamlRoot.Size.Width / 2, xamlRoot.Size.Height / 2);
+ uint id = 1;
+
+ await eyedropper.InternalPointerPressedAsync(id, pos, PointerDeviceType.Mouse);
+
+ await Task.Delay(1000);
+
+ for (int i = 0; i < 50; i++)
+ {
+ await Task.Delay(100);
+ eyedropper.InternalPointerMoved(id, pos);
+ pos.X += 5;
+ pos.Y += 5;
+ }
+
+ await eyedropper.InternalPointerReleasedAsync(id, pos);
+
+ await Task.Delay(1000);
+
+ Assert.AreEqual(Colors.CornflowerBlue, color);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ObjectStorageHelper.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ObjectStorageHelper.cs
new file mode 100644
index 00000000000..fc4a8ebe869
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ObjectStorageHelper.cs
@@ -0,0 +1,18 @@
+// 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.VisualStudio.TestTools.UnitTesting;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ [STATestClass]
+ public partial class XamlIslandsTest_ObjectStorageHelper
+ {
+ [Ignore]
+ [TestMethod]
+ public void LocalObjectStorageHelper_Writes()
+ {
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_StringExtensions.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_StringExtensions.cs
new file mode 100644
index 00000000000..fb59c2ca320
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_StringExtensions.cs
@@ -0,0 +1,44 @@
+// 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.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Extensions;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ [STATestClass]
+ public partial class XamlIslandsTest_StringExtensions
+ {
+ [TestMethod]
+ public async Task StringExtensions_GetViewLocalized()
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ var xamlRoot = App.XamlRoot;
+ var str = StringExtensions.GetViewLocalized("abc", xamlRoot.UIContext);
+ Assert.AreEqual("ABCDEF", str);
+ });
+ }
+
+ [TestMethod]
+ public async Task StringExtensions_GetLocalized()
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ var xamlRoot = App.XamlRoot;
+ var str = StringExtensions.GetLocalized("abc", xamlRoot.UIContext);
+ Assert.AreEqual("ABCDEF", str);
+ });
+ }
+
+ [TestMethod]
+ public void StringExtensions_GetLocalizedWithResourcePath()
+ {
+ var str = StringExtensions.GetLocalized("TextToolbarStrings_OkLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources");
+ Assert.AreEqual("Ok", str);
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_SystemInformation.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_SystemInformation.cs
new file mode 100644
index 00000000000..668da199a41
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_SystemInformation.cs
@@ -0,0 +1,38 @@
+// 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.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Windows.ApplicationModel.Activation;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ [STATestClass]
+ public partial class XamlIslandsTest_SystemInformation
+ {
+ [TestMethod]
+ public async Task SystemInformationTrackAppUse()
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ var e = new FakeArgs
+ {
+ PreviousExecutionState = ApplicationExecutionState.NotRunning
+ };
+ var xamlRoot = App.XamlRoot;
+ SystemInformation.Instance.TrackAppUse(e, xamlRoot);
+ });
+ }
+
+ private class FakeArgs : IActivatedEventArgs
+ {
+ public ActivationKind Kind { get; set; }
+
+ public ApplicationExecutionState PreviousExecutionState { get; set; }
+
+ public SplashScreen SplashScreen { get; set; }
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ThemeListener_Threading.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ThemeListener_Threading.cs
new file mode 100644
index 00000000000..aa3d98da9f5
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ThemeListener_Threading.cs
@@ -0,0 +1,57 @@
+// 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.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.UI.Helpers;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Windows.UI.Xaml;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ [STATestClass]
+ public partial class XamlIslandsTest_ThemeListener_Threading
+ {
+ private TaskCompletionSource _taskCompletionSource;
+ private ThemeListener _themeListener = null;
+
+ [TestInitialize]
+ public Task Init()
+ {
+ return App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ _taskCompletionSource = new TaskCompletionSource();
+
+ _themeListener = new ThemeListener
+ {
+ CurrentTheme = Application.Current.RequestedTheme
+ };
+ _themeListener.ThemeChanged += (s) =>
+ {
+ _taskCompletionSource.TrySetResult(null);
+ };
+
+ _themeListener.CurrentTheme = Application.Current.RequestedTheme == ApplicationTheme.Light ? ApplicationTheme.Dark : ApplicationTheme.Light;
+ });
+ }
+
+ [TestMethod]
+ public async Task ThemeListenerDispatcherTestAsync()
+ {
+ await _themeListener.OnColorValuesChanged();
+
+ await _taskCompletionSource.Task;
+ }
+
+ [TestMethod]
+ public async Task ThemeListenerDispatcherTestFromOtherThreadAsync()
+ {
+ await Task.Run(async () =>
+ {
+ await _themeListener.OnColorValuesChanged();
+ });
+ await _taskCompletionSource.Task;
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_WrapPanel.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_WrapPanel.cs
new file mode 100644
index 00000000000..d6e071e69e0
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_WrapPanel.cs
@@ -0,0 +1,65 @@
+// 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.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Markup;
+
+namespace UnitTests.XamlIslands.UWPApp
+{
+ [STATestClass]
+ public partial class XamlIslandsTest_WrapPanel
+ {
+ private ListView _listView;
+
+ [TestInitialize]
+ public async Task Init()
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(() =>
+ {
+ var xamlItemsPanelTemplate = @"
+
+ ";
+
+ var xamlDataTemplate = @"
+
+
+
+
+
+ ";
+ _listView = new ListView
+ {
+ ItemsPanel = XamlReader.Load(xamlItemsPanelTemplate) as ItemsPanelTemplate,
+ ItemTemplate = XamlReader.Load(xamlDataTemplate) as DataTemplate
+ };
+ TestsPage.Instance.SetMainTestContent(_listView);
+ });
+ }
+
+ [TestMethod]
+ public async Task WrapPanel_RendersFine()
+ {
+ await App.Dispatcher.ExecuteOnUIThreadAsync(async () =>
+ {
+ var item = new Uri("ms-appx:///Assets/StoreLogo.png");
+ for (int i = 0; i < 100; i++)
+ {
+ _listView.Items.Add(item);
+ }
+
+ await Task.Delay(3000);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands/Directory.Build.props b/UnitTests/UnitTests.XamlIslands/Directory.Build.props
new file mode 100644
index 00000000000..a52359c6dc7
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands/Directory.Build.props
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands/Directory.Build.targets b/UnitTests/UnitTests.XamlIslands/Directory.Build.targets
new file mode 100644
index 00000000000..4de98b5c73f
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands/Directory.Build.targets
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands/Program.cs b/UnitTests/UnitTests.XamlIslands/Program.cs
new file mode 100644
index 00000000000..9699f66f7f9
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands/Program.cs
@@ -0,0 +1,68 @@
+// 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.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.Toolkit.Forms.UI.XamlHost;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+using Windows.UI;
+using UnitTests.XamlIslands.UWPApp;
+
+namespace UnitTests.XamlIslands
+{
+ class Program
+ {
+ internal static App AppInstance;
+
+ [STAThread]
+ public static void Main()
+ {
+ using (AppInstance = new App())
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ var mainFormInstance = new MainForm();
+ Application.Run(mainFormInstance);
+ }
+ }
+
+ public class MainForm : Form
+ {
+ public WindowsXamlHost xamlHost = new WindowsXamlHost();
+
+ public MainForm()
+ {
+ SuspendLayout();
+ xamlHost.AutoSizeMode = AutoSizeMode.GrowOnly;
+ xamlHost.Location = new System.Drawing.Point(0, 0);
+ xamlHost.Name = "xamlHost";
+ xamlHost.Size = new System.Drawing.Size(800, 800);
+ xamlHost.TabIndex = 0;
+ xamlHost.Text = "xamlHost";
+ xamlHost.Dock = DockStyle.Fill;
+ xamlHost.ChildChanged += XamlHost_ChildChanged;
+ xamlHost.Child = new Frame();
+
+ AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ AutoScaleMode = AutoScaleMode.Font;
+ WindowState = FormWindowState.Maximized;
+ ClientSize = new System.Drawing.Size(800, 600);
+ Controls.Add(xamlHost);
+ Name = "MainForm";
+ Text = "Xaml Islands";
+ ResumeLayout(false);
+ }
+
+ private void XamlHost_ChildChanged(object sender, EventArgs e)
+ {
+ if(xamlHost.Child is Frame frame)
+ {
+ frame.Navigate(typeof(TestsPage));
+ }
+ }
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.XamlIslands/Properties/launchSettings.json b/UnitTests/UnitTests.XamlIslands/Properties/launchSettings.json
new file mode 100644
index 00000000000..cb3f681f5f8
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "UnitTests.XamlIslands": {
+ "commandName": "Project",
+ "nativeDebugging": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.csproj b/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.csproj
new file mode 100644
index 00000000000..ab52bd03741
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.csproj
@@ -0,0 +1,22 @@
+
+
+
+ WinExe
+ netcoreapp3.1
+ x64;x86
+ win-x64;win-x86
+ true
+ uap10.0.18362
+ app.manifest
+ UnitTests.XamlIslands.Program
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UnitTests/UnitTests.XamlIslands/app.manifest b/UnitTests/UnitTests.XamlIslands/app.manifest
new file mode 100644
index 00000000000..ada43287157
--- /dev/null
+++ b/UnitTests/UnitTests.XamlIslands/app.manifest
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj
index eb6557ce5da..4cfdabb4cc6 100644
--- a/UnitTests/UnitTests.csproj
+++ b/UnitTests/UnitTests.csproj
@@ -104,7 +104,7 @@
- 6.2.9
+ 6.2.10
2.1.0
@@ -136,6 +136,7 @@
+
diff --git a/Windows Community Toolkit.sln b/Windows Community Toolkit.sln
index 2a562708db3..4aa5ea65042 100644
--- a/Windows Community Toolkit.sln
+++ b/Windows Community Toolkit.sln
@@ -90,6 +90,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GazeInputTest", "GazeInputT
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Media", "Microsoft.Toolkit.Uwp.UI.Media\Microsoft.Toolkit.Uwp.UI.Media.csproj", "{75F9EE44-3EFA-47BC-AEDD-351B9834A0AF}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests.XamlIslands", "UnitTests\UnitTests.XamlIslands\UnitTests.XamlIslands.csproj", "{F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}"
+EndProject
+Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "UnitTests.XamlIslands.Package", "UnitTests\UnitTests.XamlIslands.Package\UnitTests.XamlIslands.Package.wapproj", "{DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XamlIslands", "XamlIslands", "{C79029AF-2E9B-4466-BAC4-1A41B281EAE6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.XamlIslands.UWPApp", "UnitTests\UnitTests.XamlIslands.UWPApp\UnitTests.XamlIslands.UWPApp.csproj", "{804D0681-52F6-4E61-864A-699F0AB44B20}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
UnitTests\UnitTests.Notifications.Shared\UnitTests.Notifications.Shared.projitems*{982cc826-aacd-4855-9075-430bb6ce40a9}*SharedItemsImports = 13
@@ -804,6 +812,81 @@ Global
{75F9EE44-3EFA-47BC-AEDD-351B9834A0AF}.Release|x64.Build.0 = Release|Any CPU
{75F9EE44-3EFA-47BC-AEDD-351B9834A0AF}.Release|x86.ActiveCfg = Release|Any CPU
{75F9EE44-3EFA-47BC-AEDD-351B9834A0AF}.Release|x86.Build.0 = Release|Any CPU
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Debug|ARM.ActiveCfg = Debug|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Debug|ARM64.ActiveCfg = Debug|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Debug|x64.ActiveCfg = Debug|x64
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Debug|x64.Build.0 = Debug|x64
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Debug|x86.ActiveCfg = Debug|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Debug|x86.Build.0 = Debug|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Native|Any CPU.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Native|ARM.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Native|ARM64.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Native|x64.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Native|x86.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Release|Any CPU.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Release|ARM.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Release|ARM64.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Release|x64.ActiveCfg = Release|x64
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Release|x64.Build.0 = Release|x64
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Release|x86.ActiveCfg = Release|x86
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4}.Release|x86.Build.0 = Release|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|ARM.ActiveCfg = Debug|ARM
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|ARM.Build.0 = Debug|ARM
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|ARM.Deploy.0 = Debug|ARM
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|ARM64.Build.0 = Debug|ARM64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|x64.ActiveCfg = Debug|x64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|x64.Build.0 = Debug|x64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|x64.Deploy.0 = Debug|x64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|x86.ActiveCfg = Debug|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|x86.Build.0 = Debug|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Debug|x86.Deploy.0 = Debug|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Native|Any CPU.ActiveCfg = Debug|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Native|ARM.ActiveCfg = Release|ARM
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Native|ARM64.ActiveCfg = Release|ARM64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Native|x64.ActiveCfg = Release|x64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Native|x86.ActiveCfg = Release|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|Any CPU.ActiveCfg = Release|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|ARM.ActiveCfg = Release|ARM
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|ARM64.ActiveCfg = Release|ARM64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|x64.ActiveCfg = Release|x64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|x64.Build.0 = Release|x64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|x64.Deploy.0 = Release|x64
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|x86.ActiveCfg = Release|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|x86.Build.0 = Release|x86
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC}.Release|x86.Deploy.0 = Release|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|ARM.ActiveCfg = Debug|ARM
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|ARM.Build.0 = Debug|ARM
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|ARM.Deploy.0 = Debug|ARM
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|ARM64.Build.0 = Debug|ARM64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|x64.ActiveCfg = Debug|x64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|x64.Build.0 = Debug|x64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|x64.Deploy.0 = Debug|x64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|x86.ActiveCfg = Debug|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|x86.Build.0 = Debug|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Debug|x86.Deploy.0 = Debug|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Native|Any CPU.ActiveCfg = Release|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Native|ARM.ActiveCfg = Release|ARM
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Native|ARM64.ActiveCfg = Release|ARM64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Native|x64.ActiveCfg = Release|x64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Native|x86.ActiveCfg = Release|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|Any CPU.ActiveCfg = Release|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|ARM.ActiveCfg = Release|ARM
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|ARM64.ActiveCfg = Release|ARM64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|x64.ActiveCfg = Release|x64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|x64.Build.0 = Release|x64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|x64.Deploy.0 = Release|x64
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|x86.ActiveCfg = Release|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|x86.Build.0 = Release|x86
+ {804D0681-52F6-4E61-864A-699F0AB44B20}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -827,6 +910,10 @@ Global
{262BB7CE-EF42-4BF7-B90C-107E6CBB57FF} = {096ECFD7-7035-4487-9C87-81DCE9389620}
{A122EA02-4DE7-413D-BFBF-AF7DFC668DD6} = {B30036C4-D514-4E5B-A323-587A061772CE}
{75F9EE44-3EFA-47BC-AEDD-351B9834A0AF} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC}
+ {F5929F8E-7BC5-4A7B-A92A-AC751F7906E4} = {C79029AF-2E9B-4466-BAC4-1A41B281EAE6}
+ {DCFBF9F1-2BBE-498D-B6C9-8ADE50C06CDC} = {C79029AF-2E9B-4466-BAC4-1A41B281EAE6}
+ {C79029AF-2E9B-4466-BAC4-1A41B281EAE6} = {B30036C4-D514-4E5B-A323-587A061772CE}
+ {804D0681-52F6-4E61-864A-699F0AB44B20} = {C79029AF-2E9B-4466-BAC4-1A41B281EAE6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5403B0C4-F244-4F73-A35C-FE664D0F4345}