Skip to content

Commit 8a4ec95

Browse files
authored
DYN-8564: run autocomplete search in background thread (#16265)
1 parent afe368c commit 8a4ec95

4 files changed

Lines changed: 73 additions & 10 deletions

File tree

src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
xmlns:p="clr-namespace:Dynamo.Wpf.Properties"
88
xmlns:uicontrols="clr-namespace:Dynamo.UI.Controls"
99
xmlns:resx="clr-namespace:Dynamo.Properties;assembly=DynamoCore"
10+
xmlns:local="clr-namespace:Dynamo.PackageManager.UI"
11+
xmlns:dynconverters="clr-namespace:Dynamo.Controls"
1012
mc:Ignorable="d"
1113
WindowStyle="None"
1214
AllowsTransparency="True"
@@ -43,6 +45,7 @@
4345
Value="{StaticResource LibraryScrollViewerControlTemplate}" />
4446
</Style>
4547
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
48+
<dynconverters:InverseBoolToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
4649
</ResourceDictionary>
4750
</Window.Resources>
4851

@@ -256,7 +259,17 @@
256259
<ColumnDefinition Width="Auto" />
257260
<ColumnDefinition Width="*" />
258261
</Grid.ColumnDefinitions>
262+
<local:LoadingAnimationStripeControl
263+
Grid.Column="0"
264+
VerticalAlignment="Center"
265+
Height="35"
266+
MinWidth="240"
267+
AnimationSpeed="10"
268+
Visibility="{Binding ResultsLoaded, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBooleanToVisibilityConverter}}"
269+
Margin="8,8,0,8"
270+
/>
259271
<Border BorderThickness="1"
272+
Visibility="{Binding ResultsLoaded, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityConverter}}"
260273
Background="{StaticResource WorkspaceBackgroundHomeBrush}"
261274
CornerRadius="5"
262275
Padding="5"
@@ -311,6 +324,7 @@
311324
</Border>
312325

313326
<Button x:Name="btnSuggestions"
327+
IsEnabled="{Binding ResultsLoaded}"
314328
Click="DisplaySuggestions"
315329
Grid.Column="1">
316330
<Button.ToolTip>

src/DynamoCoreWpf/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2468,6 +2468,8 @@ Dynamo.ViewModels.NodeAutoCompleteSearchViewModel.DisplayLowConfidence.set -> vo
24682468
Dynamo.ViewModels.NodeAutoCompleteSearchViewModel.HideAutocompleteMethodOptions.get -> bool
24692469
Dynamo.ViewModels.NodeAutoCompleteSearchViewModel.IsDisplayingMLRecommendation.get -> bool
24702470
Dynamo.ViewModels.NodeAutoCompleteSearchViewModel.IsMLAutocompleteTOUApproved.get -> bool
2471+
Dynamo.ViewModels.NodeAutoCompleteSearchViewModel.ResultsLoaded.get -> bool
2472+
Dynamo.ViewModels.NodeAutoCompleteSearchViewModel.ResultsLoaded.set -> void
24712473
Dynamo.ViewModels.NodeDialogEventArgs
24722474
Dynamo.ViewModels.NodeDialogEventArgs.Handled.get -> bool
24732475
Dynamo.ViewModels.NodeDialogEventArgs.Handled.set -> void

src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.IO;
55
using System.Linq;
66
using System.Text.RegularExpressions;
7+
using System.Threading.Tasks;
78
using Dynamo.Configuration;
89
using Dynamo.Engine;
910
using Dynamo.Graph.Connectors;
@@ -47,6 +48,23 @@ public class NodeAutoCompleteSearchViewModel : SearchViewModel
4748
private const string nodeClusterAutocompleteMLEndpoint = "MLNodeClusterAutocomplete";
4849
internal bool IsOpen { get; set; }
4950

51+
private bool resultsLoaded;
52+
53+
/// <summary>
54+
/// Flag that indicates whether results are loading (false) or they have loaded (true).
55+
/// This is set as true for both succesfully and unsuccessfully loading the results.
56+
/// </summary>
57+
[Obsolete("This method will be removed in a future version of Dynamo")]
58+
public bool ResultsLoaded
59+
{
60+
get { return resultsLoaded; }
61+
set
62+
{
63+
resultsLoaded = value;
64+
RaisePropertyChanged(nameof(ResultsLoaded));
65+
}
66+
}
67+
5068
// Lucene search utility to perform indexing operations just for NodeAutocomplete.
5169
internal LuceneSearchUtility LuceneUtility
5270
{
@@ -161,6 +179,7 @@ public bool DisplayLowConfidence
161179
}
162180

163181
internal event Action<NodeModel> ParentNodeRemoved;
182+
private Guid LastRequestGuid;
164183

165184
/// <summary>
166185
/// Constructor
@@ -290,27 +309,55 @@ internal MLNodeAutoCompletionRequest GenerateRequestForMLAutocomplete()
290309

291310
internal void ShowNodeAutocompleMLResults()
292311
{
312+
//this should run on the UI thread, so thread safety is not a concern
313+
LastRequestGuid = Guid.NewGuid();
314+
var myRequest = LastRequestGuid;
315+
293316
MLNodeAutoCompletionResponse MLresults = null;
294317

295318
var request = GenerateRequestForMLAutocomplete();
296319

297320
string jsonRequest = JsonConvert.SerializeObject(request);
298321

299322
// Get results from the ML API.
300-
try
323+
ResultsLoaded = false;
324+
Task.Run(() =>
301325
{
302-
MLresults = GetMLNodeAutocompleteResults(jsonRequest);
326+
try
327+
{
328+
MLresults = GetMLNodeAutocompleteResults(jsonRequest);
329+
this.dynamoViewModel.UIDispatcher.BeginInvoke(() => UpdateUIWithRresults(MLresults, myRequest));
330+
}
331+
catch (Exception ex)
332+
{
333+
this.dynamoViewModel.UIDispatcher.BeginInvoke(() =>
334+
{
335+
ResultsLoaded = true; //fail gracefully
336+
dynamoViewModel.Model.Logger.Log("Unable to fetch ML Node autocomplete results: " + ex.Message);
337+
DisplayAutocompleteMLStaticPage = true;
338+
AutocompleteMLTitle = Resources.LoginNeededTitle;
339+
AutocompleteMLMessage = Resources.LoginNeededMessage;
340+
Analytics.TrackEvent(Actions.View, Categories.NodeAutoCompleteOperations, "UnabletoFetch");
341+
return;
342+
});
343+
}
344+
});
345+
}
346+
private void UpdateUIWithRresults(MLNodeAutoCompletionResponse MLresults, Guid myRequest)
347+
{
348+
if (LastRequestGuid != myRequest)
349+
{
350+
//a newer request came, we're no longer interested in the results of this one
351+
//only latest request has the right to be committed to the UI and internal data structures
352+
return;
303353
}
304-
catch (Exception ex)
354+
if (!IsOpen)
305355
{
306-
dynamoViewModel.Model.Logger.Log("Unable to fetch ML Node autocomplete results: " + ex.Message);
307-
DisplayAutocompleteMLStaticPage = true;
308-
AutocompleteMLTitle = Resources.LoginNeededTitle;
309-
AutocompleteMLMessage = Resources.LoginNeededMessage;
310-
Analytics.TrackEvent(Actions.View, Categories.NodeAutoCompleteOperations, "UnabletoFetch");
356+
// view disappeared while the background thread was waiting for the server response.
357+
// Ignore the results as we're no longer interested.
311358
return;
312359
}
313-
360+
ResultsLoaded = true;
314361
// no results
315362
if (MLresults == null || MLresults.Results.Count() == 0)
316363
{

src/NodeAutoCompleteViewExtension/ViewModels/NodeAutoCompleteBarViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,7 @@ internal void PopulateAutoComplete()
994994
if (!IsOpen)
995995
{
996996
// view disappeared while the background thread was waiting for the server response.
997-
// Ignore the results are we're no longer interested.
997+
// Ignore the results as we're no longer interested.
998998
return;
999999
}
10001000

0 commit comments

Comments
 (0)