From 5c50f9f74fecbe11200f8924d94031912fe8b0fa Mon Sep 17 00:00:00 2001 From: Peter Laker Date: Fri, 25 May 2018 02:33:42 +0100 Subject: [PATCH 1/9] Added Azure API best practices retry pattern helper for transient errors. The scenario fails if user tries more than 20 images, or tries to train/analyse within the same '20 per min' limit. Also added a MainWindowLogTraceWriter class, inherited from existing Newtonsoft namespace. If you like, I will check/fix in other places where service call limit errors are unhandled. --- .../Controls/FaceIdentificationPage.xaml | 2 +- .../Controls/FaceIdentificationPage.xaml.cs | 80 +++++++-- Sample-WPF/FaceAPI-WPF-Samples.csproj | 2 + .../Helpers/MainWindowLogTraceWriter.cs | 59 +++++++ Sample-WPF/Helpers/RetryHelper.cs | 164 ++++++++++++++++++ 5 files changed, 290 insertions(+), 17 deletions(-) create mode 100644 Sample-WPF/Helpers/MainWindowLogTraceWriter.cs create mode 100644 Sample-WPF/Helpers/RetryHelper.cs diff --git a/Sample-WPF/Controls/FaceIdentificationPage.xaml b/Sample-WPF/Controls/FaceIdentificationPage.xaml index 829bdb6..6c1c8a4 100644 --- a/Sample-WPF/Controls/FaceIdentificationPage.xaml +++ b/Sample-WPF/Controls/FaceIdentificationPage.xaml @@ -2,7 +2,7 @@ // // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. -// +// // Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services // // Microsoft Cognitive Services (formerly Project Oxford) GitHub: diff --git a/Sample-WPF/Controls/FaceIdentificationPage.xaml.cs b/Sample-WPF/Controls/FaceIdentificationPage.xaml.cs index a414f9f..8d23563 100644 --- a/Sample-WPF/Controls/FaceIdentificationPage.xaml.cs +++ b/Sample-WPF/Controls/FaceIdentificationPage.xaml.cs @@ -44,12 +44,32 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; - using ClientContract = Microsoft.ProjectOxford.Face.Contract; using System.Windows.Media; +using Microsoft.ProjectOxford.Face.Contract; +using Microsoft.ProjectOxford.Face; +using Newtonsoft.Json.Serialization; +using Microsoft.ProjectOxford.Face.Helpers; namespace Microsoft.ProjectOxford.Face.Controls { + //using System; + //using System.Collections.Concurrent; + //using System.Collections.Generic; + //using System.Collections.ObjectModel; + //using System.ComponentModel; + //using System.Diagnostics; + //using System.IO; + //using System.Linq; + //using System.Text; + //using System.Threading; + //using System.Threading.Tasks; + //using System.Windows; + //using System.Windows.Controls; + + //using ClientContract = Microsoft.ProjectOxford.Face.Contract; + //using System.Windows.Media; + /// /// Interaction logic for FaceDetection.xaml /// @@ -70,7 +90,7 @@ public partial class FaceIdentificationPage : Page, INotifyPropertyChanged /// /// Faces to identify /// - private ObservableCollection _faces = new ObservableCollection(); + private ObservableCollection _faces = new ObservableCollection(); /// /// Person database @@ -87,6 +107,8 @@ public partial class FaceIdentificationPage : Page, INotifyPropertyChanged /// private int _maxConcurrentProcesses; + private MainWindowLogTraceWriter _mainWindowLogTraceWriter; + #endregion Fields #region Constructors @@ -98,6 +120,8 @@ public FaceIdentificationPage() { InitializeComponent(); _maxConcurrentProcesses = 4; + + _mainWindowLogTraceWriter = new MainWindowLogTraceWriter(); } #endregion Constructors @@ -190,7 +214,7 @@ public ImageSource SelectedFile /// /// Gets faces to identify /// - public ObservableCollection TargetFaces + public ObservableCollection TargetFaces { get { @@ -215,9 +239,9 @@ private async void FolderPicker_Click(object sender, RoutedEventArgs e) MainWindow mainWindow = Window.GetWindow(this) as MainWindow; string subscriptionKey = mainWindow._scenariosControl.SubscriptionKey; - string endpoint= mainWindow._scenariosControl.SubscriptionEndpoint; + string endpoint = mainWindow._scenariosControl.SubscriptionEndpoint; - var faceServiceClient = new FaceServiceClient(subscriptionKey,endpoint); + var faceServiceClient = new FaceServiceClient(subscriptionKey, endpoint); // Test whether the group already exists try @@ -277,7 +301,7 @@ private async void FolderPicker_Click(object sender, RoutedEventArgs e) MainWindow.Log("Request: Creating group \"{0}\"", this.GroupId); try { - await faceServiceClient.CreateLargePersonGroupAsync(this.GroupId, this.GroupId); + await faceServiceClient.CreateLargePersonGroupAsync(this.GroupId, this.GroupId, dlg.SelectedPath); MainWindow.Log("Response: Success. Group \"{0}\" created", this.GroupId); } catch (FaceAPIException ex) @@ -300,12 +324,18 @@ private async void FolderPicker_Click(object sender, RoutedEventArgs e) Person p = new Person(); p.PersonName = tag; - var faces = new ObservableCollection(); + var faces = new ObservableCollection(); p.Faces = faces; // Call create person REST API, the new create person id will be returned MainWindow.Log("Request: Creating person \"{0}\"", p.PersonName); - p.PersonId = (await faceServiceClient.CreatePersonInLargePersonGroupAsync(this.GroupId, p.PersonName)).PersonId.ToString(); + + p.PersonId = (await RetryHelper.OperationWithBasicRetryAsync(async () => await + faceServiceClient.CreatePersonInLargePersonGroupAsync(this.GroupId, p.PersonName, dir), + new[] { typeof(FaceAPIException) }, + traceWriter: _mainWindowLogTraceWriter + )).PersonId.ToString(); + MainWindow.Log("Response: Success. Person \"{0}\" (PersonID:{1}) created", p.PersonName, p.PersonId); string img; @@ -314,7 +344,7 @@ private async void FolderPicker_Click(object sender, RoutedEventArgs e) new ConcurrentBag( Directory.EnumerateFiles(dir, "*.*", SearchOption.AllDirectories) .Where(s => s.ToLower().EndsWith(".jpg") || s.ToLower().EndsWith(".png") || s.ToLower().EndsWith(".bmp") || s.ToLower().EndsWith(".gif"))); - + while (imageList.TryTake(out img)) { tasks.Add(Task.Factory.StartNew( @@ -364,7 +394,7 @@ private async void FolderPicker_Click(object sender, RoutedEventArgs e) } this.Dispatcher.Invoke( - new Action, string, ClientContract.AddPersistedFaceResult>(UIHelper.UpdateFace), + new Action, string, ClientContract.AddPersistedFaceResult>(UIHelper.UpdateFace), faces, detectionResult.Item1, detectionResult.Item2); @@ -401,7 +431,13 @@ private async void FolderPicker_Click(object sender, RoutedEventArgs e) { // Start train large person group MainWindow.Log("Request: Training group \"{0}\"", this.GroupId); - await faceServiceClient.TrainLargePersonGroupAsync(this.GroupId); + + await RetryHelper.VoidOperationWithBasicRetryAsync(() => + faceServiceClient.TrainLargePersonGroupAsync(this.GroupId), + new[] { typeof(FaceAPIException) }, + traceWriter: _mainWindowLogTraceWriter); + + //await faceServiceClient.TrainLargePersonGroupAsync(this.GroupId); // Wait until train completed while (true) @@ -409,7 +445,7 @@ private async void FolderPicker_Click(object sender, RoutedEventArgs e) await Task.Delay(1000); var status = await faceServiceClient.GetLargePersonGroupTrainingStatusAsync(this.GroupId); MainWindow.Log("Response: {0}. Group \"{1}\" training process is {2}", "Success", this.GroupId, status.Status); - if (status.Status != Contract.Status.Running) + if (status.Status != Status.Running) { break; } @@ -459,7 +495,12 @@ private async void Identify_Click(object sender, RoutedEventArgs e) { try { - var faces = await faceServiceClient.DetectAsync(fStream); + var faces = await RetryHelper.OperationWithBasicRetryAsync(async () => await + faceServiceClient.DetectAsync(fStream), + new[] { typeof(FaceAPIException) }, + traceWriter: _mainWindowLogTraceWriter); + + //var faces = await faceServiceClient.DetectAsync(fStream); // Convert detection result into UI binding object for rendering foreach (var face in UIHelper.CalculateFaceRectangleForRendering(faces, MaxImageSize, imageInfo)) @@ -471,7 +512,14 @@ private async void Identify_Click(object sender, RoutedEventArgs e) // Identify each face // Call identify REST API, the result contains identified person information - var identifyResult = await faceServiceClient.IdentifyAsync(faces.Select(ff => ff.FaceId).ToArray(), largePersonGroupId: this.GroupId); + + var identifyResult = await RetryHelper.OperationWithBasicRetryAsync(async () => await + faceServiceClient.IdentifyAsync(faces.Select(ff => ff.FaceId).ToArray(), largePersonGroupId: this.GroupId), + new[] { typeof(FaceAPIException) }, + traceWriter: _mainWindowLogTraceWriter); + + //var identifyResult = await faceServiceClient.IdentifyAsync(faces.Select(ff => ff.FaceId).ToArray(), largePersonGroupId: this.GroupId); + for (int idx = 0; idx < faces.Length; idx++) { // Update identification result for rendering @@ -591,7 +639,7 @@ public class Person : INotifyPropertyChanged /// /// Person's faces from database /// - private ObservableCollection _faces = new ObservableCollection(); + private ObservableCollection _faces = new ObservableCollection(); /// /// Person's id @@ -619,7 +667,7 @@ public class Person : INotifyPropertyChanged /// /// Gets or sets person's faces from database /// - public ObservableCollection Faces + public ObservableCollection Faces { get { diff --git a/Sample-WPF/FaceAPI-WPF-Samples.csproj b/Sample-WPF/FaceAPI-WPF-Samples.csproj index bacba2f..de8e45e 100644 --- a/Sample-WPF/FaceAPI-WPF-Samples.csproj +++ b/Sample-WPF/FaceAPI-WPF-Samples.csproj @@ -140,6 +140,8 @@ FaceDetectionPage.xaml + + MainWindow.xaml Code diff --git a/Sample-WPF/Helpers/MainWindowLogTraceWriter.cs b/Sample-WPF/Helpers/MainWindowLogTraceWriter.cs new file mode 100644 index 0000000..9a5455e --- /dev/null +++ b/Sample-WPF/Helpers/MainWindowLogTraceWriter.cs @@ -0,0 +1,59 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services +// +// Microsoft Cognitive Services (formerly Project Oxford) GitHub: +// https://github.com/Microsoft/Cognitive-Face-Windows +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Microsoft.ProjectOxford.Face.Helpers +{ + using Newtonsoft.Json.Serialization; + using System; + using System.Diagnostics; + + class MainWindowLogTraceWriter : ITraceWriter + { + private TraceLevel _levelFilter; + + public MainWindowLogTraceWriter(TraceLevel levelFilter = TraceLevel.Verbose) + { + _levelFilter = levelFilter; + } + + public TraceLevel LevelFilter + { + get { return _levelFilter; } + } + + public void Trace(TraceLevel level, string message, Exception ex) + { + MainWindow.Log(message); + } + } +} diff --git a/Sample-WPF/Helpers/RetryHelper.cs b/Sample-WPF/Helpers/RetryHelper.cs new file mode 100644 index 0000000..a31adf4 --- /dev/null +++ b/Sample-WPF/Helpers/RetryHelper.cs @@ -0,0 +1,164 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services +// +// Microsoft Cognitive Services (formerly Project Oxford) GitHub: +// https://github.com/Microsoft/Cognitive-Face-Windows +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Microsoft.ProjectOxford.Face.Helpers +{ + using Newtonsoft.Json.Serialization; + using System; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + + /// + /// This class retries on transient errors + /// + public class RetryHelper + { + /// + /// The singleton + /// + static RetryHelper _singleton; + + /// + /// Prevents a default instance of the class from being created. + /// + private RetryHelper(){} + + /// + /// Gets the current. + /// + /// + /// The current. + /// + public static RetryHelper Current + { + get + { + if (_singleton == null) + { + _singleton = new RetryHelper(); + } + return _singleton; + } + } + + /// + /// Operations the with basic retry asynchronous. + /// + /// + /// The asynchronous operation. + /// The transient exception types. + /// The retry delay milliseconds. + /// The maximum retries. + /// The trace writer. + /// + public static async Task OperationWithBasicRetryAsync(Func> asyncOperation, Type[] transientExceptionTypes, int retryDelayMilliseconds = 1000, int maxRetries = 60, ITraceWriter traceWriter = null) + { + int retryCount = 0; + + while (true) + { + try + { + return await asyncOperation(); + } + catch (Exception ex) + when (IsTransientError(ex, transientExceptionTypes)) + { + if (traceWriter != null) + { + traceWriter.Trace(System.Diagnostics.TraceLevel.Error, $"Error: {ex.Message}. Retrying {retryCount}/{maxRetries}", ex); + } + + if (++retryCount >= maxRetries) + { + throw; + } + + Thread.Sleep(retryDelayMilliseconds); + } + } + } + + /// + /// Voids the operation with basic retry asynchronous. + /// + /// The asynchronous operation. + /// The transient exception types. + /// The retry delay milliseconds. + /// The maximum retries. + /// The trace writer. + /// + public static async Task VoidOperationWithBasicRetryAsync(Func asyncOperation, Type[] transientExceptionTypes, int retryDelayMilliseconds = 1000, int maxRetries = 60, ITraceWriter traceWriter = null) + { + int retryCount = 0; + + while (true) + { + try + { + await asyncOperation(); + return; + } + catch (Exception ex) + when (IsTransientError(ex, transientExceptionTypes)) + { + if (traceWriter != null) + { + traceWriter.Trace(System.Diagnostics.TraceLevel.Error, $"Error: {ex.Message}. Retrying {retryCount}/{maxRetries}", ex); + } + + if (++retryCount >= maxRetries) + { + throw; + } + + Thread.Sleep(retryDelayMilliseconds); + } + } + } + + /// + /// Determines whether [is transient error] [the specified ex]. + /// + /// The ex. + /// The transient exception types. + /// + /// true if [is transient error] [the specified ex]; otherwise, false. + /// + private static bool IsTransientError(Exception ex, Type[] transientExceptionTypes) + { + return transientExceptionTypes.Contains(ex.GetType()); + } + } +} From 7f7c40b681ae08dcc6c28bc53ae95dd6757ae02c Mon Sep 17 00:00:00 2001 From: Peter Laker Date: Fri, 25 May 2018 02:52:42 +0100 Subject: [PATCH 2/9] Added example App, for analyzing all your all your photo stores and persisting results and meta data for search, list, locate. --- .../App.config | 27 + .../App.xaml | 9 + .../App.xaml.cs | 17 + .../Assets/Microsoft-logo_rgb_c-gray.png | Bin 0 -> 1271 bytes .../Assets/default.jpg | Bin 0 -> 825 bytes .../Controls/FaceIdentificationPage.xaml | 209 ++++ .../Controls/FaceIdentificationPage.xaml.cs | 730 ++++++++++++++ .../Controls/ManageGroupsControl.xaml | 125 +++ .../Controls/ManageGroupsControl.xaml.cs | 472 +++++++++ .../Controls/PopupWindow.xaml | 11 + .../Controls/PopupWindow.xaml.cs | 51 + .../Controls/ScanFolderControl.xaml | 188 ++++ .../Controls/ScanFolderControl.xaml.cs | 922 ++++++++++++++++++ .../ShowPersonMatchedFilesControl.xaml | 42 + .../ShowPersonMatchedFilesControl.xaml.cs | 130 +++ .../Controls/SortMyPhotosPage.xaml | 14 + .../Controls/SortMyPhotosPage.xaml.cs | 59 ++ .../Controls/UIHelper.cs | 345 +++++++ .../Data/IDataProvider.cs | 64 ++ .../Data/Person.cs | 55 ++ .../Data/PhotosDatabase.cs | 60 ++ .../Data/PictureFile.cs | 61 ++ .../Data/PictureFileGroupLookup.cs | 59 ++ .../Data/PicturePerson.cs | 64 ++ .../Data/SqlDataProvider.cs | 116 +++ .../Helpers/MainWindowLogTraceWriter.cs | 59 ++ .../Helpers/RetryHelper.cs | 164 ++++ .../MainWindow.xaml | 10 + .../MainWindow.xaml.cs | 247 +++++ .../Models/Converters.cs | 124 +++ .../Models/Face.cs | 604 ++++++++++++ .../Models/LargePersonGroupExtended.cs | 83 ++ .../Models/PersonExtended.cs | 118 +++ ...oto-Detect-Catalogue-Search-WPF-App.csproj | 204 ++++ .../Properties/AssemblyInfo.cs | 55 ++ .../Properties/Resources.Designer.cs | 63 ++ .../Properties/Resources.resx | 117 +++ .../Properties/Settings.Designer.cs | 26 + .../Properties/Settings.settings | 7 + .../packages.config | 10 + Sample-WPF/FaceAPI-WPF-Samples.sln | 13 +- 41 files changed, 5732 insertions(+), 2 deletions(-) create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/App.config create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/App.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/App.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Assets/Microsoft-logo_rgb_c-gray.png create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Assets/default.jpg create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/FaceIdentificationPage.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/FaceIdentificationPage.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/ManageGroupsControl.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/ManageGroupsControl.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/PopupWindow.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/PopupWindow.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/ScanFolderControl.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/ScanFolderControl.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/ShowPersonMatchedFilesControl.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/ShowPersonMatchedFilesControl.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/SortMyPhotosPage.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/SortMyPhotosPage.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Controls/UIHelper.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Data/IDataProvider.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Data/Person.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Data/PhotosDatabase.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Data/PictureFile.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Data/PictureFileGroupLookup.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Data/PicturePerson.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Data/SqlDataProvider.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Helpers/MainWindowLogTraceWriter.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Helpers/RetryHelper.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/MainWindow.xaml create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/MainWindow.xaml.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Models/Converters.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Models/Face.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Models/LargePersonGroupExtended.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Models/PersonExtended.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Photo-Detect-Catalogue-Search-WPF-App.csproj create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Properties/AssemblyInfo.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Properties/Resources.Designer.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Properties/Resources.resx create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Properties/Settings.Designer.cs create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/Properties/Settings.settings create mode 100644 Photo-Detect-Catalogue-Search-WPF-App/packages.config diff --git a/Photo-Detect-Catalogue-Search-WPF-App/App.config b/Photo-Detect-Catalogue-Search-WPF-App/App.config new file mode 100644 index 0000000..42f4173 --- /dev/null +++ b/Photo-Detect-Catalogue-Search-WPF-App/App.config @@ -0,0 +1,27 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Photo-Detect-Catalogue-Search-WPF-App/App.xaml b/Photo-Detect-Catalogue-Search-WPF-App/App.xaml new file mode 100644 index 0000000..eedf5a8 --- /dev/null +++ b/Photo-Detect-Catalogue-Search-WPF-App/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/Photo-Detect-Catalogue-Search-WPF-App/App.xaml.cs b/Photo-Detect-Catalogue-Search-WPF-App/App.xaml.cs new file mode 100644 index 0000000..e5b1ae2 --- /dev/null +++ b/Photo-Detect-Catalogue-Search-WPF-App/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace Photo_Detect_Catalogue_Search_WPF_App +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/Photo-Detect-Catalogue-Search-WPF-App/Assets/Microsoft-logo_rgb_c-gray.png b/Photo-Detect-Catalogue-Search-WPF-App/Assets/Microsoft-logo_rgb_c-gray.png new file mode 100644 index 0000000000000000000000000000000000000000..7846308a5386121946e25c1e695d6e13b109fc33 GIT binary patch literal 1271 zcmeAS@N?(olHy`uVBq!ia0y~yVAKU+4mO}j>|?WcK#HZ<$uool2x>S|I)Hr60*}aI z1_s^VAk6ru-Rn6}P^QE+q9iy!t)x7$D3!r6B|j-u!7Z~WwLHHlyI8?F*zCogO+7%f z3O!vMLn`LHy?!uLI#8tTqP5%YhO7eC%Z;&4-}01Hm#~;lEdBQF&<m=Ht2FH!!#V6kqdwZTo~T zhQ{a3@6Ahl_OdScMtA#Kc7~eP3`WgGtV=q?CMZQYbd7R`Xc(MIOw%*|yz#5Rq;t}D zHzl9`T6MRI`9S?=Tb3XfZVy3S1=lSNA{UwPaQIHIKW$~a9GFT<_U)6Yzf K&t;ucLK6V-U8>yx literal 0 HcmV?d00001 diff --git a/Photo-Detect-Catalogue-Search-WPF-App/Assets/default.jpg b/Photo-Detect-Catalogue-Search-WPF-App/Assets/default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00e1df84b3601451bcf46c5922662f441855644b GIT binary patch literal 825 zcmex= zRY=j$kxe)-kzJ`!#HexNLJno8jR!@8E`CrkPAY2R|V^&07y2J$~}^+4C1KUw!=a z`ODXD-+%o41@ado12e>1aG#<1OAzQUCSV+}u!H=?$W#u*%z`YeiiT`Lj)Clng~Cck zjT|CQ6Blkg$f;}`^g%SK=pvVxipfLOk07sseMX$en#l4Q++zrT-D2QjW&}navmk># W!`}moy0kYu=F(WyFqE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
public partial class App : Application { + private App() + { + this.DispatcherUnhandledException += App_DispatcherUnhandledException; + } + + private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) + { + FileTraceWriter.LogError(e.Exception, $"UnhandledException, {e.Exception.Message}"); + } } } diff --git a/Photo-App/Controls/FaceIdentificationPage.xaml b/Photo-App/Controls/FaceIdentificationPage.xaml index 04c9bc3..93de7a7 100644 --- a/Photo-App/Controls/FaceIdentificationPage.xaml +++ b/Photo-App/Controls/FaceIdentificationPage.xaml @@ -46,13 +46,11 @@ - + - - - + - - - - - - - - - - - - - - + + - + + - -