diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs index 65027e5cc..97e20f13a 100644 --- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs +++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs @@ -59,14 +59,18 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// private BluetoothAdapter _adapter; - private DispatcherQueue _dispatcherQueue; + /// + /// 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.GetForCurrentThread(); + 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(); @@ -205,7 +209,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// The advertisement. private async void AdvertisementWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args) { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( () => { if (_readerWriterLockSlim.TryEnterReadLock(TimeSpan.FromSeconds(1))) @@ -289,7 +293,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity // Protect against race condition if the task runs after the app stopped the deviceWatcher. if (sender == _deviceWatcher) { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( () => { if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1))) @@ -331,7 +335,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity // Make sure device name isn't blank or already present in the list. if (!string.IsNullOrEmpty(deviceInfo?.Name)) { - var device = new ObservableBluetoothLEDevice(deviceInfo, _dispatcherQueue); + 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") && @@ -339,7 +343,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity if (connectable) { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( () => { if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1))) diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs index 1888093d9..e54d84f4e 100644 --- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs +++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs @@ -135,7 +135,10 @@ namespace Microsoft.Toolkit.Uwp.Connectivity private ObservableCollection _services = new ObservableCollection(); - private DispatcherQueue _dispatcherQueue; + /// + /// Gets or sets which DispatcherQueue is used to dispatch UI updates. + /// + public DispatcherQueue DispatcherQueue { get; set; } /// /// Initializes a new instance of the class. @@ -149,7 +152,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity IsPaired = DeviceInfo.Pairing.IsPaired; - _dispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); + DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); LoadGlyph(); @@ -401,7 +404,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// Thorws Exception when no permission to access device public async Task ConnectAsync() { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( async () => { if (BluetoothLEDevice == null) @@ -475,7 +478,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// The task of the update. public async Task UpdateAsync(DeviceInformationUpdate deviceUpdate) { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( () => { DeviceInfo.Update(deviceUpdate); @@ -518,7 +521,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// The arguments. private async void BluetoothLEDevice_NameChanged(BluetoothLEDevice sender, object args) { - await _dispatcherQueue.ExecuteOnUIThreadAsync(() => { Name = BluetoothLEDevice.Name; }, DispatcherQueuePriority.Normal); + await DispatcherQueue.ExecuteOnUIThreadAsync(() => { Name = BluetoothLEDevice.Name; }, DispatcherQueuePriority.Normal); } /// @@ -528,7 +531,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// The arguments. private async void BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args) { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( () => { IsPaired = DeviceInfo.Pairing.IsPaired; @@ -541,7 +544,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// private async void LoadGlyph() { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( async () => { var deviceThumbnail = await DeviceInfo.GetGlyphThumbnailAsync(); diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs index 17aefb1f0..c1ab661c9 100644 --- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs +++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs @@ -112,16 +112,20 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// private string _value; - private DispatcherQueue _dispatcherQueue; + /// + /// 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.GetForCurrentThread(); + DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); Characteristic = characteristic; Parent = parent; @@ -465,7 +469,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity /// The instance containing the event data. private async void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) { - await _dispatcherQueue.ExecuteOnUIThreadAsync(() => { SetValue(args.CharacteristicValue); }, DispatcherQueuePriority.Normal); + await DispatcherQueue.ExecuteOnUIThreadAsync(() => { SetValue(args.CharacteristicValue); }, DispatcherQueuePriority.Normal); } /// diff --git a/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs b/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs index 7048fb8ea..ece261b30 100644 --- a/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs +++ b/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs @@ -35,14 +35,18 @@ namespace Microsoft.Toolkit.Uwp.UI /// public static ImageCache Instance => _instance ?? (_instance = new ImageCache()); - private DispatcherQueue _dispatcherQueue; + /// + /// 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.GetForCurrentThread(); + DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); _extendedPropertyNames.Add(DateAccessedProperty); } @@ -59,7 +63,7 @@ namespace Microsoft.Toolkit.Uwp.UI throw new FileNotFoundException(); } - return await _dispatcherQueue.ExecuteOnUIThreadAsync(async () => + return await DispatcherQueue.ExecuteOnUIThreadAsync(async () => { BitmapImage image = new BitmapImage(); diff --git a/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs b/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs index 46d36aca2..595308dd1 100644 --- a/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs +++ b/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs @@ -47,7 +47,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Helpers /// public bool IsHighContrast { get; set; } - private DispatcherQueue _dispatcherQueue; + /// + /// Gets or sets which DispatcherQueue is used to dispatch UI updates. + /// + public DispatcherQueue DispatcherQueue { get; set; } /// /// An event that fires if the Theme changes. @@ -60,12 +63,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Helpers /// /// 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.GetForCurrentThread(); + DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); _accessible.HighContrastChanged += Accessible_HighContrastChanged; _settings.ColorValuesChanged += Settings_ColorValuesChanged; @@ -90,9 +94,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Helpers await OnColorValuesChanged(); } - internal async Task OnColorValuesChanged() + internal Task OnColorValuesChanged() { - await _dispatcherQueue.ExecuteOnUIThreadAsync( + return DispatcherQueue.ExecuteOnUIThreadAsync( () => { // TODO: This doesn't stop the multiple calls if we're in our faked 'White' HighContrast Mode below. diff --git a/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs index b9757c6cd..95d6bf7f2 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs @@ -102,7 +102,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers var taskCompletionSource = new TaskCompletionSource(); - _ = dispatcher.TryEnqueue(priority, () => + bool ok = dispatcher.TryEnqueue(priority, () => { try { @@ -159,7 +159,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers var taskCompletionSource = new TaskCompletionSource(); - _ = dispatcher.TryEnqueue(priority, async () => + bool ok = dispatcher.TryEnqueue(priority, async () => { try { @@ -222,7 +222,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers var taskCompletionSource = new TaskCompletionSource(); - _ = dispatcher.TryEnqueue(priority, async () => + bool ok = dispatcher.TryEnqueue(priority, async () => { try { diff --git a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs index e10156624..3e4894333 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs @@ -96,16 +96,20 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// private PrintHelperOptions _defaultPrintHelperOptions; - private DispatcherQueue _dispatcherQueue; + /// + /// 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.GetForCurrentThread(); + DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); if (canvasContainer == null) { @@ -201,7 +205,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers } _printCanvas = null; - _dispatcherQueue.ExecuteOnUIThreadAsync(() => + DispatcherQueue.ExecuteOnUIThreadAsync(() => { _printDocument.Paginate -= CreatePrintPreviewPages; _printDocument.GetPreviewPage -= GetPrintPreviewPage; @@ -225,7 +229,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers { if (!_directPrint) { - await _dispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.ExecuteOnUIThreadAsync(() => { _canvasContainer.Children.Remove(_printCanvas); _printCanvas.Children.Clear(); @@ -258,7 +262,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers printTask.Completed += async (s, args) => { // Notify the user when the print operation fails. - await _dispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.ExecuteOnUIThreadAsync( async () => { foreach (var element in _stateBags.Keys) @@ -476,7 +480,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers // Save state if (!_stateBags.ContainsKey(element)) { - var stateBag = new PrintHelperStateBag(_dispatcherQueue); + var stateBag = new PrintHelperStateBag(DispatcherQueue); stateBag.Capture(element); _stateBags.Add(element, stateBag); } @@ -511,7 +515,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers element.Margin = new Thickness(marginWidth / 2, marginHeight / 2, marginWidth / 2, marginHeight / 2); page.Content = element; - return _dispatcherQueue.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 @@ -527,7 +531,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers private Task ClearPageCache() { - return _dispatcherQueue.ExecuteOnUIThreadAsync(() => + return DispatcherQueue.ExecuteOnUIThreadAsync(() => { if (!_directPrint) { diff --git a/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs index cfafc7ff0..1601ef903 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs @@ -25,15 +25,18 @@ namespace Microsoft.Toolkit.Uwp.Helpers private RemoteSystemWatcher _remoteSystemWatcher; - private DispatcherQueue _dispatcherQueue; + /// + /// Gets or sets which DispatcherQueue is used to dispatch UI updates. + /// + public DispatcherQueue DispatcherQueue { get; set; } /// /// Initializes a new instance of the class. /// - /// 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. + /// 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(); + DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); RemoteSystems = new ObservableCollection(); GenerateSystems(); } @@ -42,10 +45,10 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// Initializes a new instance of the class. /// /// Initiate Enumeration with specific RemoteSysemKind with Filters - /// 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. + /// 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(); + DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); RemoteSystems = new ObservableCollection(); GenerateSystemsWithFilterAsync(filter); } @@ -94,7 +97,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers private async void RemoteSystemWatcher_RemoteSystemUpdated(RemoteSystemWatcher sender, RemoteSystemUpdatedEventArgs args) { - await _dispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.ExecuteOnUIThreadAsync(() => { RemoteSystems.Remove(RemoteSystems.First(a => a.Id == args.RemoteSystem.Id)); RemoteSystems.Add(args.RemoteSystem); @@ -103,7 +106,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers private async void RemoteSystemWatcher_RemoteSystemRemoved(RemoteSystemWatcher sender, RemoteSystemRemovedEventArgs args) { - await _dispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.ExecuteOnUIThreadAsync(() => { RemoteSystems.Remove(RemoteSystems.First(a => a.Id == args.RemoteSystemId)); }); @@ -111,7 +114,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers private async void RemoteSystemWatcher_RemoteSystemAdded(RemoteSystemWatcher sender, RemoteSystemAddedEventArgs args) { - await _dispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.ExecuteOnUIThreadAsync(() => { RemoteSystems.Add(args.RemoteSystem); }); diff --git a/UnitTests/UnitTests.XamlIslands/Program.cs b/UnitTests/UnitTests.XamlIslands/Program.cs index 05fb3dead..e46bd61e8 100644 --- a/UnitTests/UnitTests.XamlIslands/Program.cs +++ b/UnitTests/UnitTests.XamlIslands/Program.cs @@ -7,17 +7,17 @@ using Windows.UI.Xaml.Hosting; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.Toolkit.Win32.UI.XamlHost; using System.Threading.Tasks; -using Windows.UI.Core; using Windows.UI.Xaml; using System.Reflection; +using Windows.System; +using System.Diagnostics; namespace UnitTests.XamlIslands { class Program { private static IXamlMetadataContainer _metadataContainer; - internal static CoreDispatcher _dispatcher; - private static Task _task; + internal static DispatcherQueue _dispatcher; [STAThread] public static void Main() @@ -29,36 +29,54 @@ namespace UnitTests.XamlIslands var frame = UWPTypeFactory.CreateXamlContentByType("Windows.UI.Xaml.Controls.Frame"); xamlSource.Content = frame; - _dispatcher = xamlSource.Content.XamlRoot.Content.Dispatcher; + _dispatcher = DispatcherQueue.GetForCurrentThread(); - _task = Task.Run(async () => + _dispatcher.TryEnqueue(DispatcherQueuePriority.Normal, async () => { - await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => - { - foreach (var testClass in typeof(XamlIslandsTest_ThemeListener_Threading).Assembly.GetTypes()) - { - Attribute[] attributes = Attribute.GetCustomAttributes(testClass); + TestResult testResult = default; - foreach (Attribute attribute in attributes) + Stopwatch sw = new Stopwatch(); + + ConsoleWriteLineColor("--- Starting Tests Execution ---"); + + sw.Start(); + + foreach (var testClass in typeof(XamlIslandsTest_ThemeListener_Threading).Assembly.GetTypes()) + { + Attribute[] attributes = Attribute.GetCustomAttributes(testClass); + + foreach (Attribute attribute in attributes) + { + if (attribute is STATestClassAttribute || attribute is TestClassAttribute) { - if (attribute is STATestClassAttribute || attribute is TestClassAttribute) - { - await RunTestsAsync(testClass); - break; - } + var partialTestResult = await RunTestsAsync(testClass); + testResult += partialTestResult; + break; } } - _dispatcher.StopProcessEvents(); - Window.Current.CoreWindow.Close(); - }); + } + + sw.Stop(); + + var color = testResult.Failed == 0 ? ConsoleColor.Green : ConsoleColor.Red; + + ConsoleWriteLineColor($"--- Finished Tests Execution ({testResult.Passed}/{testResult.Count}) ---", color); + ConsoleWriteLineColor($"--- Duration - {sw.Elapsed} ---"); + + Window.Current.CoreWindow.Close(); + System.Windows.Application.Current.Shutdown(); }); - _dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit); + // This is just to have a Win32 message loop so the dispatcher processes it's events. This is not WPF or WinForms specific. + var app = new System.Windows.Application(); + app.Run(); } } - private static async Task RunTestsAsync(Type type) + private static async Task RunTestsAsync(Type type) { + int count = 0; + int passed = 0; var initMethod = GetFirstMethod(type, typeof(TestInitializeAttribute)); var cleanupMethod = GetFirstMethod(type, typeof(TestCleanupAttribute)); @@ -70,6 +88,7 @@ namespace UnitTests.XamlIslands { if (attribute is STATestMethodAttribute || attribute is TestMethodAttribute) { + count++; try { var instance = Activator.CreateInstance(type); @@ -99,6 +118,7 @@ namespace UnitTests.XamlIslands } TestPass(type, method); + passed++; } catch (Exception ex) { @@ -108,19 +128,38 @@ namespace UnitTests.XamlIslands } } } + + return new TestResult(count, passed); + } + + struct TestResult + { + public int Count { get; } + public int Passed { get; } + public int Failed => Count - Passed; + public TestResult(int count, int passed) + { + Count = count; + Passed = passed; + } + + public static TestResult operator +(TestResult a, TestResult b) => new TestResult(a.Count + b.Count, a.Passed + b.Passed); } private static void TestPass(Type type, MethodInfo method) { - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"{type.FullName}.{method.Name}\t - \tPASS"); - Console.ResetColor(); + ConsoleWriteLineColor($"{type.FullName}.{method.Name}\t - \tPASS", ConsoleColor.Green); } private static void TestFail(Type type, MethodInfo method, Exception ex) { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine($"{type.FullName}.{method.Name}\t - \tFAIL:{Environment.NewLine}{ex}"); + ConsoleWriteLineColor($"{type.FullName}.{method.Name}\t - \tFAIL:{Environment.NewLine}{ex}", ConsoleColor.Red); + } + + private static void ConsoleWriteLineColor(string message, ConsoleColor color = ConsoleColor.White) + { + Console.ForegroundColor = color; + Console.WriteLine(message); Console.ResetColor(); } diff --git a/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.csproj b/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.csproj index fa3f2cc3c..d58942e11 100644 --- a/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.csproj +++ b/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.csproj @@ -8,7 +8,7 @@ true win-x86 uap10.0.18362 - UnitTests.XamlIslands.dll.manifest + app.manifest UnitTests.XamlIslands.Program @@ -27,11 +27,5 @@ - - - - PreserveNewest - - diff --git a/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.dll.manifest b/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.dll.manifest deleted file mode 100644 index 278557d94..000000000 --- a/UnitTests/UnitTests.XamlIslands/UnitTests.XamlIslands.dll.manifest +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/UnitTests/UnitTests.XamlIslands/XamlIslandsTest_ThemeListener_Threading.cs b/UnitTests/UnitTests.XamlIslands/XamlIslandsTest_ThemeListener_Threading.cs index 5ef40cec2..ea42a11a3 100644 --- a/UnitTests/UnitTests.XamlIslands/XamlIslandsTest_ThemeListener_Threading.cs +++ b/UnitTests/UnitTests.XamlIslands/XamlIslandsTest_ThemeListener_Threading.cs @@ -25,7 +25,7 @@ namespace UnitTests.XamlIslands _themeListener = new ThemeListener(); _themeListener.ThemeChanged += (s) => { - _taskCompletionSource.SetResult(null); + _taskCompletionSource.TrySetResult(null); }; Application.Current.RequestedTheme = ApplicationTheme.Dark; diff --git a/UnitTests/UnitTests.XamlIslands/app.manifest b/UnitTests/UnitTests.XamlIslands/app.manifest index 278557d94..95fe07093 100644 --- a/UnitTests/UnitTests.XamlIslands/app.manifest +++ b/UnitTests/UnitTests.XamlIslands/app.manifest @@ -4,18 +4,6 @@ - @@ -23,55 +11,7 @@ - - - - - - - - - - - - - - - - - - - - - - - -