Skip to content

Commit a203f9c

Browse files
authored
Feature: Improve profile list performance (BornToBeRoot#2014)
* Feature: Remove SortDescriptions & Use virtualizing * Feature: Use Virtualizing * Chore: Code cleanup * Fix: Reduce profile refresh calls & re-set binding instead of refresh * Chore: Refactoring... * Chore: Improve code * Feature: Re-bind instead of refresh, reselect item * Fix: Reduce calls to refresh profiles (only if view is active) * Fix: Update image & color for error & warning rectangle * Fix: Make group compare case sensitive * Feature: Re-bind instead of refresh, reselect item * Feature: Re-bind instead of refresh, reselect item
1 parent 67fd937 commit a203f9c

39 files changed

Lines changed: 1153 additions & 973 deletions

Source/NETworkManager.Profiles/GroupViewInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class GroupViewInfo
1111

1212
public GroupViewInfo()
1313
{
14+
1415
}
1516

1617
public GroupViewInfo(GroupViewName name, Canvas icon)

Source/NETworkManager/MainWindow.xaml.cs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,7 @@ public string Search
198198
var sourceInfos = sourceCollection as ApplicationInfo[] ?? sourceCollection.ToArray();
199199
var filteredInfos = filteredCollection as ApplicationInfo[] ?? filteredCollection.ToArray();
200200

201-
if (_filterLastCount == null)
202-
_filterLastCount = sourceInfos.Length;
201+
_filterLastCount ??= sourceInfos.Length;
203202

204203
SelectedApplication = _filterLastCount > filteredInfos.Length ? filteredInfos.FirstOrDefault() : sourceInfos.FirstOrDefault(x => x.Name == _filterLastViewName);
205204

@@ -1016,21 +1015,23 @@ private void EventSystem_RedirectDataToApplicationEvent(object sender, EventArgs
10161015
}
10171016
#endregion
10181017

1019-
#region Settings
1018+
#region Settings
10201019
private void OpenSettings()
1021-
{
1022-
// Init settings view
1020+
{
1021+
OnApplicationViewHide(SelectedApplication.Name);
1022+
10231023
if (_settingsView == null)
10241024
{
1025-
_settingsView = new SettingsView(SelectedApplication.Name);
1025+
_settingsView = new SettingsView();
10261026
ContentControlSettings.Content = _settingsView;
10271027
}
1028-
else // Change view
1028+
else
10291029
{
1030-
_settingsView.ChangeSettingsView(SelectedApplication.Name);
1031-
_settingsView.Refresh();
1030+
_settingsView.OnViewVisible();
10321031
}
10331032

1033+
_settingsView.ChangeSettingsView(SelectedApplication.Name);
1034+
10341035
// Show the view (this will hide other content)
10351036
ShowSettingsView = true;
10361037
}
@@ -1044,6 +1045,8 @@ private void CloseSettings()
10441045
{
10451046
ShowSettingsView = false;
10461047

1048+
_settingsView.OnViewHide();
1049+
10471050
// Change HotKeys
10481051
if (SettingsManager.HotKeysChanged)
10491052
{
@@ -1072,9 +1075,9 @@ private void LoadProfiles()
10721075
SelectedProfileFile = ProfileFiles.SourceCollection.Cast<ProfileFileInfo>().FirstOrDefault(x => x.Name == SettingsManager.Current.Profiles_LastSelected);
10731076
SelectedProfileFile ??= ProfileFiles.SourceCollection.Cast<ProfileFileInfo>().FirstOrDefault();
10741077
}
1075-
1078+
10761079
private async Task LoadProfile(ProfileFileInfo info, bool showWrongPassword = false)
1077-
{
1080+
{
10781081
if (info.IsEncrypted && !info.IsPasswordValid)
10791082
{
10801083
IsProfileFileLocked = true;
@@ -1129,7 +1132,7 @@ private async Task SwitchProfile(ProfileFileInfo info)
11291132
catch (System.Security.Cryptography.CryptographicException)
11301133
{
11311134
// Wrong password, try again...
1132-
LoadProfile(info, true);
1135+
LoadProfile(info, true);
11331136
}
11341137
catch
11351138
{
@@ -1527,8 +1530,8 @@ private void ConfigureDNS()
15271530

15281531
foreach (var dnsServer in SettingsManager.Current.Network_CustomDNSServer.Split(";"))
15291532
{
1530-
dnsServers.Add((dnsServer, 53));
1531-
}
1533+
dnsServers.Add((dnsServer, 53));
1534+
}
15321535

15331536
dnsSettings.UseCustomDNSServers = true;
15341537
dnsSettings.DNSServers = dnsServers;

Source/NETworkManager/Resources/Styles/ListBoxStyle.xaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111

1212
<Style x:Key="ProfileListBox" TargetType="{x:Type ListBox}" BasedOn="{StaticResource DefaultListBox}">
1313
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
14+
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
15+
<!-- Performance problem with large ListBox/view?
1416
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
1517
<Style.Triggers>
1618
<Trigger Property="IsMouseOver" Value="True">
1719
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
1820
</Trigger>
1921
</Style.Triggers>
22+
-->
2023
</Style>
2124

2225
</ResourceDictionary>

Source/NETworkManager/Resources/Styles/RectangleStyles.xaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<Setter Property="Fill" Value="{DynamicResource MahApps.Brushes.Gray3}" />
2323
<Setter Property="OpacityMask">
2424
<Setter.Value>
25-
<VisualBrush Stretch="Uniform" Visual="{iconPacks:Material Kind=InformationVariant}"/>
25+
<VisualBrush Stretch="Uniform" Visual="{iconPacks:Material Kind=InformationOutline}"/>
2626
</Setter.Value>
2727
</Setter>
2828
<Setter Property="ToolTipService.InitialShowDelay" Value="0" />
@@ -33,10 +33,10 @@
3333
<Style.Resources>
3434
<Style TargetType="{x:Type ToolTip}" BasedOn="{StaticResource DefaultToolTip}" />
3535
</Style.Resources>
36-
<Setter Property="Fill" Value="{DynamicResource MahApps.Brushes.Gray3}" />
36+
<Setter Property="Fill" Value="Orange" />
3737
<Setter Property="OpacityMask">
3838
<Setter.Value>
39-
<VisualBrush Stretch="Uniform" Visual="{iconPacks:Material Kind=Alert}"/>
39+
<VisualBrush Stretch="Uniform" Visual="{iconPacks:Material Kind=AlertOutline}"/>
4040
</Setter.Value>
4141
</Setter>
4242
<Setter Property="ToolTipService.InitialShowDelay" Value="0" />
@@ -47,10 +47,10 @@
4747
<Style.Resources>
4848
<Style TargetType="{x:Type ToolTip}" BasedOn="{StaticResource DefaultToolTip}" />
4949
</Style.Resources>
50-
<Setter Property="Fill" Value="{DynamicResource MahApps.Brushes.Gray3}" />
50+
<Setter Property="Fill" Value="Red" />
5151
<Setter Property="OpacityMask">
5252
<Setter.Value>
53-
<VisualBrush Stretch="Uniform" Visual="{iconPacks:Material Kind=AlertCircle}"/>
53+
<VisualBrush Stretch="Uniform" Visual="{iconPacks:Material Kind=AlertOctagonOutline}"/>
5454
</Setter.Value>
5555
</Setter>
5656
<Setter Property="ToolTipService.InitialShowDelay" Value="0" />

Source/NETworkManager/ViewModels/AWSSessionManagerHostViewModel.cs

Lines changed: 62 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,21 @@ public bool HeaderContextMenuIsOpen
151151
}
152152
#region Profiles
153153

154-
public ICollectionView Profiles { get; }
154+
public ICollectionView _profiles;
155+
public ICollectionView Profiles
156+
{
157+
get => _profiles;
158+
set
159+
{
160+
if (value == _profiles)
161+
return;
162+
163+
_profiles = value;
164+
OnPropertyChanged();
165+
}
166+
}
155167

156-
private ProfileInfo _selectedProfile = new ProfileInfo();
168+
private ProfileInfo _selectedProfile = new();
157169
public ProfileInfo SelectedProfile
158170
{
159171
get => _selectedProfile;
@@ -178,7 +190,9 @@ public string Search
178190

179191
_search = value;
180192

181-
StartDelayedSearch();
193+
// Start searching...
194+
IsSearching = true;
195+
_searchDispatcherTimer.Start();
182196

183197
OnPropertyChanged();
184198
}
@@ -287,32 +301,8 @@ public AWSSessionManagerHostViewModel(IDialogCoordinator instance)
287301

288302
TabItems = new ObservableCollection<DragablzTabItem>();
289303

290-
Profiles = new CollectionViewSource { Source = ProfileManager.Groups.SelectMany(x => x.Profiles) }.View;
291-
Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
292-
Profiles.SortDescriptions.Add(new SortDescription(nameof(ProfileInfo.Group), ListSortDirection.Ascending));
293-
Profiles.SortDescriptions.Add(new SortDescription(nameof(ProfileInfo.Name), ListSortDirection.Ascending));
294-
Profiles.Filter = o =>
295-
{
296-
if (o is not ProfileInfo info)
297-
return false;
298-
299-
if (string.IsNullOrEmpty(Search))
300-
return info.AWSSessionManager_Enabled;
301-
302-
var search = Search.Trim();
303-
304-
// Search by: Tag=xxx (exact match, ignore case)
305-
306-
//if (search.StartsWith(ProfileManager.TagIdentifier, StringComparison.OrdinalIgnoreCase))
307-
// return !string.IsNullOrEmpty(info.Tags) && info.AWSSessionManager_Enabled && info.Tags.Replace(" ", "").Split(';').Any(str => search.Substring(ProfileManager.TagIdentifier.Length, search.Length - ProfileManager.TagIdentifier.Length).Equals(str, StringComparison.OrdinalIgnoreCase));
308-
//
309-
310-
// Search by: Name, AWSSessionManager_Host
311-
return info.AWSSessionManager_Enabled && (info.Name.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1 || info.AWSSessionManager_InstanceID.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1);
312-
};
313-
314-
// This will select the first entry as selected item...
315-
SelectedProfile = Profiles.SourceCollection.Cast<ProfileInfo>().Where(x => x.AWSSessionManager_Enabled).OrderBy(x => x.Group).ThenBy(x => x.Name).FirstOrDefault();
304+
// Profiles
305+
SetProfilesView();
316306

317307
ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
318308

@@ -833,31 +823,7 @@ private static void AddRegionToHistory(string region)
833823

834824
SettingsManager.Current.AWSSessionManager_RegionHistory = new ObservableCollection<string>(ListHelper.Modify(SettingsManager.Current.AWSSessionManager_RegionHistory.ToList(), region, SettingsManager.Current.General_HistoryListEntries));
835825
}
836-
837-
private void StartDelayedSearch()
838-
{
839-
if (!IsSearching)
840-
{
841-
IsSearching = true;
842-
843-
_searchDispatcherTimer.Start();
844-
}
845-
else
846-
{
847-
_searchDispatcherTimer.Stop();
848-
_searchDispatcherTimer.Start();
849-
}
850-
}
851-
852-
private void StopDelayedSearch()
853-
{
854-
_searchDispatcherTimer.Stop();
855-
856-
RefreshProfiles();
857-
858-
IsSearching = false;
859-
}
860-
826+
861827
private void ResizeProfile(bool dueToChangedSize)
862828
{
863829
_canProfileWidthChange = false;
@@ -917,15 +883,48 @@ public void OnProfileLoaded()
917883
SyncAllInstanceIDsFromAWS();
918884
}
919885

886+
private void SetProfilesView(ProfileInfo profile = null)
887+
{
888+
Profiles = new CollectionViewSource { Source = ProfileManager.Groups.SelectMany(x => x.Profiles).Where(x => x.AWSSessionManager_Enabled).OrderBy(x => x.Group).ThenBy(x => x.Name) }.View;
889+
890+
Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
891+
892+
Profiles.Filter = o =>
893+
{
894+
if (o is not ProfileInfo info)
895+
return false;
896+
897+
if (string.IsNullOrEmpty(Search))
898+
return true;
899+
900+
var search = Search.Trim();
901+
902+
// Search by: Tag=xxx (exact match, ignore case)
903+
/*
904+
if (search.StartsWith(ProfileManager.TagIdentifier, StringComparison.OrdinalIgnoreCase))
905+
return !string.IsNullOrEmpty(info.Tags) && info.PingMonitor_Enabled && info.Tags.Replace(" ", "").Split(';').Any(str => search.Substring(ProfileManager.TagIdentifier.Length, search.Length - ProfileManager.TagIdentifier.Length).Equals(str, StringComparison.OrdinalIgnoreCase));
906+
*/
907+
908+
// Search by: Name, AWSSessionManager_InstanceID
909+
return info.Name.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1 || info.AWSSessionManager_InstanceID.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1;
910+
};
911+
912+
// Set specific profile or first if null
913+
SelectedProfile = null;
914+
915+
if (profile != null)
916+
SelectedProfile = Profiles.Cast<ProfileInfo>().FirstOrDefault(x => x.Equals(profile)) ??
917+
Profiles.Cast<ProfileInfo>().FirstOrDefault();
918+
else
919+
SelectedProfile = Profiles.Cast<ProfileInfo>().FirstOrDefault();
920+
}
921+
920922
public void RefreshProfiles()
921923
{
922924
if (!_isViewActive)
923925
return;
924926

925-
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate
926-
{
927-
Profiles.Refresh();
928-
}));
927+
SetProfilesView(SelectedProfile);
929928
}
930929

931930
public void OnProfileDialogOpen()
@@ -988,7 +987,11 @@ private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
988987

989988
private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
990989
{
991-
StopDelayedSearch();
990+
_searchDispatcherTimer.Stop();
991+
992+
RefreshProfiles();
993+
994+
IsSearching = false;
992995
}
993996
#endregion
994997
}

0 commit comments

Comments
 (0)