From d7abae1ab22166eabf940d3983400aadd9ba93d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 19 Jan 2021 10:08:37 +0800 Subject: [PATCH 01/23] Add Cancellation token for file system enumeration --- .../DirectoryInfo/DirectoryInfoSearch.cs | 42 +++++++++++-------- .../Search/SearchManager.cs | 20 ++++----- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs index 88d7d6927..efdb5a6fe 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo { @@ -16,14 +17,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo resultManager = new ResultManager(context); } - internal List TopLevelDirectorySearch(Query query, string search) + internal List TopLevelDirectorySearch(Query query, string search, CancellationToken token) { var criteria = ConstructSearchCriteria(search); - if (search.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > search.LastIndexOf(Constants.DirectorySeperator)) - return DirectorySearch(SearchOption.AllDirectories, query, search, criteria); + if (search.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > + search.LastIndexOf(Constants.DirectorySeperator)) + return DirectorySearch(new EnumerationOptions + { + RecurseSubdirectories = true + }, query, search, criteria, token); - return DirectorySearch(SearchOption.TopDirectoryOnly, query, search, criteria); + return DirectorySearch(null, query, search, criteria, token); // null will be passed as default } public string ConstructSearchCriteria(string search) @@ -45,7 +50,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo return incompleteName; } - private List DirectorySearch(SearchOption searchOption, Query query, string search, string searchCriteria) + private List DirectorySearch(EnumerationOptions enumerationOption, Query query, string search, + string searchCriteria, CancellationToken token) { var results = new List(); @@ -58,38 +64,38 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo { var directoryInfo = new System.IO.DirectoryInfo(path); - foreach (var fileSystemInfo in directoryInfo.EnumerateFileSystemInfos(searchCriteria, searchOption)) + foreach (var fileSystemInfo in directoryInfo.EnumerateFileSystemInfos(searchCriteria, enumerationOption)) { - if ((fileSystemInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) continue; - if (fileSystemInfo is System.IO.DirectoryInfo) { - folderList.Add(resultManager.CreateFolderResult(fileSystemInfo.Name, fileSystemInfo.FullName, fileSystemInfo.FullName, query, true, false)); + folderList.Add(resultManager.CreateFolderResult(fileSystemInfo.Name, fileSystemInfo.FullName, + fileSystemInfo.FullName, query, true, false)); } else { fileList.Add(resultManager.CreateFileResult(fileSystemInfo.FullName, query, true, false)); } + + if (token.IsCancellationRequested) + return null; } } catch (Exception e) { - if (e is UnauthorizedAccessException || e is ArgumentException) - { - results.Add(new Result { Title = e.Message, Score = 501 }); + if (!(e is ArgumentException)) throw e; + + results.Add(new Result {Title = e.Message, Score = 501}); - return results; - } + return results; #if DEBUG // Please investigate and handle error from DirectoryInfo search - throw e; #else Log.Exception($"|Flow.Launcher.Plugin.Explorer.DirectoryInfoSearch|Error from performing DirectoryInfoSearch", e); -#endif +#endif } - // Intial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection. + // Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection. return results.Concat(folderList.OrderBy(x => x.Title)).Concat(fileList.OrderBy(x => x.Title)).ToList(); } } -} +} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 6b3a96912..d51833a6f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -81,12 +81,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search return null; results.AddRange(await TopLevelDirectorySearchBehaviourAsync(WindowsIndexTopLevelFolderSearchAsync, - DirectoryInfoClassSearch, - useIndexSearch, - query, - locationPath, - token).ConfigureAwait(false)); - + DirectoryInfoClassSearch, + useIndexSearch, + query, + locationPath, + token).ConfigureAwait(false)); + return results; } @@ -109,23 +109,23 @@ namespace Flow.Launcher.Plugin.Explorer.Search return actionKeyword == settings.FileContentSearchActionKeyword; } - private List DirectoryInfoClassSearch(Query query, string querySearch) + private List DirectoryInfoClassSearch(Query query, string querySearch, CancellationToken token) { var directoryInfoSearch = new DirectoryInfoSearch(context); - return directoryInfoSearch.TopLevelDirectorySearch(query, querySearch); + return directoryInfoSearch.TopLevelDirectorySearch(query, querySearch, token); } public async Task> TopLevelDirectorySearchBehaviourAsync( Func>> windowsIndexSearch, - Func> directoryInfoClassSearch, + Func> directoryInfoClassSearch, bool useIndexSearch, Query query, string querySearchString, CancellationToken token) { if (!useIndexSearch) - return directoryInfoClassSearch(query, querySearchString); + return directoryInfoClassSearch(query, querySearchString, token); return await windowsIndexSearch(query, querySearchString, token); } From 4f12b80603fabea748fa1c0baf2f08d901656995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 19 Jan 2021 22:46:18 +0800 Subject: [PATCH 02/23] fix testing --- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index 09c7d9a30..e7f96fc87 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -24,7 +24,7 @@ namespace Flow.Launcher.Test.Plugins return new List(); } - private List MethodDirectoryInfoClassSearchReturnsTwoResults(Query dummyQuery, string dummyString) + private List MethodDirectoryInfoClassSearchReturnsTwoResults(Query dummyQuery, string dummyString, CancellationToken token) { return new List { From cd92512fe5b1cd6ff58b691077283164f82613c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 20 Jan 2021 13:47:25 +0800 Subject: [PATCH 03/23] Optimize code --- .../Search/DirectoryInfo/DirectoryInfoSearch.cs | 2 +- .../Search/SearchManager.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs index efdb5a6fe..d15069981 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -28,7 +28,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo RecurseSubdirectories = true }, query, search, criteria, token); - return DirectorySearch(null, query, search, criteria, token); // null will be passed as default + return DirectorySearch(new EnumerationOptions(), query, search, criteria, token); // null will be passed as default } public string ConstructSearchCriteria(string search) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index d51833a6f..6c9b81c88 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -80,12 +80,17 @@ namespace Flow.Launcher.Plugin.Explorer.Search if (token.IsCancellationRequested) return null; - results.AddRange(await TopLevelDirectorySearchBehaviourAsync(WindowsIndexTopLevelFolderSearchAsync, + var directoryResult = await TopLevelDirectorySearchBehaviourAsync(WindowsIndexTopLevelFolderSearchAsync, DirectoryInfoClassSearch, useIndexSearch, query, locationPath, - token).ConfigureAwait(false)); + token).ConfigureAwait(false); + + if (token.IsCancellationRequested) + return null; + + results.AddRange(directoryResult); return results; } From 1aa119d672af4ee1c13250902a8936bd5c02bccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 20 Jan 2021 13:49:50 +0800 Subject: [PATCH 04/23] fix some legacy code from #195 --- Flow.Launcher/PublicAPIInstance.cs | 1 + Flow.Launcher/ViewModel/ResultsViewModel.cs | 49 +++++---------------- 2 files changed, 12 insertions(+), 38 deletions(-) diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 17673a62a..89e4fab3b 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -92,6 +92,7 @@ namespace Flow.Launcher { Application.Current.Dispatcher.Invoke(() => { + useMainWindowAsOwner = false; var msg = useMainWindowAsOwner ? new Msg { Owner = Application.Current.MainWindow } : new Msg(); msg.Show(title, subTitle, iconPath); }); diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 1b8dd602d..f04304267 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -139,39 +139,9 @@ namespace Flow.Launcher.ViewModel /// public void AddResults(List newRawResults, string resultId) { - lock (_collectionLock) - { - var newResults = NewResults(newRawResults, resultId); + var newResults = NewResults(newRawResults, resultId); - // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf - // fix selected index flow - var updateTask = Task.Run(() => - { - // update UI in one run, so it can avoid UI flickering - - Results.Update(newResults); - if (Results.Any()) - SelectedItem = Results[0]; - }); - if (!updateTask.Wait(300)) - { - updateTask.Dispose(); - throw new TimeoutException("Update result use too much time."); - } - - } - - if (Visbility != Visibility.Visible && Results.Count > 0) - { - Margin = new Thickness { Top = 8 }; - SelectedIndex = 0; - Visbility = Visibility.Visible; - } - else - { - Margin = new Thickness { Top = 0 }; - Visbility = Visibility.Collapsed; - } + UpdateResults(newResults); } /// /// To avoid deadlock, this method should not called from main thread @@ -181,10 +151,15 @@ namespace Flow.Launcher.ViewModel var newResults = NewResults(resultsForUpdates); if (token.IsCancellationRequested) return; + UpdateResults(newResults, token); + + } + + private void UpdateResults(List newResults, CancellationToken token = default) + { lock (_collectionLock) { // update UI in one run, so it can avoid UI flickering - Results.Update(newResults, token); if (Results.Any()) SelectedItem = Results[0]; @@ -202,7 +177,6 @@ namespace Flow.Launcher.ViewModel Visbility = Visibility.Collapsed; break; } - } private List NewResults(List newRawResults, string resultId) @@ -212,10 +186,10 @@ namespace Flow.Launcher.ViewModel var results = Results as IEnumerable; - var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings)).ToList(); + var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings)); return results.Where(r => r.Result.PluginID != resultId) - .Concat(results.Intersect(newResults).Union(newResults)) + .Concat(newResults) .OrderByDescending(r => r.Result.Score) .ToList(); } @@ -228,8 +202,7 @@ namespace Flow.Launcher.ViewModel var results = Results as IEnumerable; return results.Where(r => r != null && !resultsForUpdates.Any(u => u.Metadata.ID == r.Result.PluginID)) - .Concat( - resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings))) + .Concat(resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings))) .OrderByDescending(rv => rv.Result.Score) .ToList(); } From 9d126df225222f41f6e23d9aa4b0601ce470f920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 20 Jan 2021 17:49:39 +0800 Subject: [PATCH 05/23] Use List replace ObservableCollection to have control toward Capacity --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 53 +++++++++++---------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index f04304267..55dea7440 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -239,49 +239,50 @@ namespace Flow.Launcher.ViewModel } #endregion - public class ResultCollection : ObservableCollection + public class ResultCollection : List, INotifyCollectionChanged { private long editTime = 0; - private bool _suppressNotifying = false; - private CancellationToken _token; - protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + public event NotifyCollectionChangedEventHandler CollectionChanged; + + protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - if (!_suppressNotifying) - { - base.OnCollectionChanged(e); - } + CollectionChanged(this, e); } - public void BulkAddRange(IEnumerable resultViews) + public void BulkAddAll(List resultViews) { - // suppress notifying before adding all element - _suppressNotifying = true; - foreach (var item in resultViews) - { - Add(item); - } - _suppressNotifying = false; - // manually update event - // wpf use directx / double buffered already, so just reset all won't cause ui flickering + AddRange(resultViews); + + // can return because the list will be cleared next time updated, which include a reset event if (_token.IsCancellationRequested) return; + + // manually update event + // wpf use directx / double buffered already, so just reset all won't cause ui flickering OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } - public void AddRange(IEnumerable Items) + private void AddAll(List Items) { foreach (var item in Items) { if (_token.IsCancellationRequested) return; Add(item); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } } - public void RemoveAll() + public void RemoveAll(int Capacity = 512) { - ClearItems(); + Clear(); + if (this.Capacity > 8000) + { + this.Capacity = Capacity; + + } + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } /// @@ -296,15 +297,19 @@ namespace Flow.Launcher.ViewModel if (editTime < 10 || newItems.Count < 30) { - if (Count != 0) ClearItems(); - AddRange(newItems); + if (Count != 0) RemoveAll(newItems.Count); + AddAll(newItems); editTime++; return; } else { Clear(); - BulkAddRange(newItems); + BulkAddAll(newItems); + if (Capacity > 8000 && newItems.Count < 3000) + { + Capacity = newItems.Count; + } editTime++; } } From e0c345ae130be3010c4627aed3f133004f44fcd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 21 Jan 2021 12:18:23 +0800 Subject: [PATCH 06/23] removing legacy code for testing --- Flow.Launcher/PublicAPIInstance.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 89e4fab3b..17673a62a 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -92,7 +92,6 @@ namespace Flow.Launcher { Application.Current.Dispatcher.Invoke(() => { - useMainWindowAsOwner = false; var msg = useMainWindowAsOwner ? new Msg { Owner = Application.Current.MainWindow } : new Msg(); msg.Show(title, subTitle, iconPath); }); From 8311b39ddc034f73ac11e2c7185067cbaebe00f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 21 Jan 2021 18:35:24 +0800 Subject: [PATCH 07/23] Add null check for OnCollectionChanged --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 55dea7440..2a0818b7d 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -249,7 +249,7 @@ namespace Flow.Launcher.ViewModel protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - CollectionChanged(this, e); + CollectionChanged?.Invoke(this, e); } public void BulkAddAll(List resultViews) From 5389763f5801c989b68d7ec1df7f1a826ebc3389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 21 Jan 2021 18:38:02 +0800 Subject: [PATCH 08/23] Add another check to avoid some corner case --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 2a0818b7d..4a4a45f11 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -247,6 +247,7 @@ namespace Flow.Launcher.ViewModel public event NotifyCollectionChangedEventHandler CollectionChanged; + protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { CollectionChanged?.Invoke(this, e); @@ -277,7 +278,7 @@ namespace Flow.Launcher.ViewModel public void RemoveAll(int Capacity = 512) { Clear(); - if (this.Capacity > 8000) + if (this.Capacity > 8000 && Capacity < this.Capacity) { this.Capacity = Capacity; From 1a758c391922b70259538848d9a646e195c2a396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 21 Jan 2021 19:39:18 +0800 Subject: [PATCH 09/23] Use Token.throwifCancellationRequested --- .../Search/DirectoryInfo/DirectoryInfoSearch.cs | 3 +-- .../Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 8 +++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs index d15069981..779827b6d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -76,8 +76,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo fileList.Add(resultManager.CreateFileResult(fileSystemInfo.FullName, query, true, false)); } - if (token.IsCancellationRequested) - return null; + token.ThrowIfCancellationRequested(); } } catch (Exception e) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 6c9b81c88..7e3bf7776 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -77,8 +77,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search results.Add(resultManager.CreateOpenCurrentFolderResult(locationPath, useIndexSearch)); - if (token.IsCancellationRequested) - return null; + token.ThrowIfCancellationRequested(); var directoryResult = await TopLevelDirectorySearchBehaviourAsync(WindowsIndexTopLevelFolderSearchAsync, DirectoryInfoClassSearch, @@ -87,11 +86,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search locationPath, token).ConfigureAwait(false); - if (token.IsCancellationRequested) - return null; + token.ThrowIfCancellationRequested(); results.AddRange(directoryResult); - + return results; } From f388b75d2610c92e1128edfba55667a80e53f6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 21 Jan 2021 19:51:22 +0800 Subject: [PATCH 10/23] Add index when calling NotifyCollectionChangeAction.Add --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 4a4a45f11..4808e0ee0 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -267,12 +267,13 @@ namespace Flow.Launcher.ViewModel } private void AddAll(List Items) { - foreach (var item in Items) + for (int i = 0; i < Items.Count; i++) { + var item = Items[i]; if (_token.IsCancellationRequested) return; Add(item); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, i)); } } public void RemoveAll(int Capacity = 512) From e74a0c99b68160be83c4e897195c8f6daaeae6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 23 Jan 2021 12:05:23 +0800 Subject: [PATCH 11/23] fix most untranslated string in Setting window --- Flow.Launcher/CustomQueryHotkeySetting.xaml | 19 ++++++++++--------- Flow.Launcher/Languages/en.xaml | 3 +++ Flow.Launcher/SettingWindow.xaml | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml b/Flow.Launcher/CustomQueryHotkeySetting.xaml index 5f4cdff19..bf6a35dff 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml @@ -5,7 +5,7 @@ Icon="Images\app.png" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" - Title="Custom Plugin Hotkey" Height="200" Width="674.766"> + Title="{DynamicResource customeQueryHotkeyTitle}" Height="200" Width="674.766"> @@ -19,22 +19,23 @@ - + + - - + + - - + +