From 6f04022ebfec3e9bab22c6f685bda89d245d11b7 Mon Sep 17 00:00:00 2001 From: Sergey M Date: Sat, 29 Aug 2020 17:29:44 -0400 Subject: [PATCH 1/5] Fixed keyboard shortcut assignment exceptions. --- DPackRx/Package/CommandBindings.cs | 2 -- DPackRx/Services/ShellService.cs | 26 ++++++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/DPackRx/Package/CommandBindings.cs b/DPackRx/Package/CommandBindings.cs index 159203b..111b8bf 100644 --- a/DPackRx/Package/CommandBindings.cs +++ b/DPackRx/Package/CommandBindings.cs @@ -25,10 +25,8 @@ public static ICollection Commands { _commands = new List { - new CommandNameAttribute("View.ViewCode", "F7", ContextGuids.vsContextGuidWindowsFormsDesigner), new CommandNameAttribute("View.ViewCode", "F7", ContextGuids.vsContextGuidHTMLSourceView), new CommandNameAttribute("View.ViewCode", "F7", ContextGuids.vsContextGuidTextEditor), - new CommandNameAttribute("View.ViewDesigner", "F7", ContextGuids.vsContextGuidWindowsFormsDesigner), new CommandNameAttribute("View.ViewDesigner", "F7", ContextGuids.vsContextGuidHTMLSourceView), new CommandNameAttribute("View.ViewDesigner", "F7", ContextGuids.vsContextGuidTextEditor), new CommandNameAttribute("EditorContextMenus.CodeWindow.RemoveAndSort", "Ctrl+Shift+Alt+U"), diff --git a/DPackRx/Services/ShellService.cs b/DPackRx/Services/ShellService.cs index 36fe525..5f59299 100644 --- a/DPackRx/Services/ShellService.cs +++ b/DPackRx/Services/ShellService.cs @@ -378,40 +378,46 @@ public bool AssignShortcuts() var binding = attrib.Binding; // Resolve optional scope binding - if (!string.IsNullOrEmpty(attrib.Scope)) + if (string.IsNullOrEmpty(attrib.Scope)) { - var resolvedBinding = string.Empty; + binding = $"{scope}::{binding}"; + } + else + { + var resolvedScope = string.Empty; if (scopes.ContainsKey(attrib.Scope)) - resolvedBinding = scopes[attrib.Scope]; + resolvedScope = scopes[attrib.Scope]; else { var bindingGuide = new Guid(attrib.Scope); - resolvedBinding = shell.GetKeyBindingScope(ref bindingGuide); - if (!string.IsNullOrEmpty(resolvedBinding)) + resolvedScope = shell.GetKeyBindingScope(ref bindingGuide); + if (!string.IsNullOrEmpty(resolvedScope)) { - scopes.Add(attrib.Scope, resolvedBinding); - _log.LogMessage($"VS command {attrib.Name} - resolved {attrib.Scope} scope to {resolvedBinding}", LOG_CATEGORY); + scopes.Add(attrib.Scope, resolvedScope); + _log.LogMessage($"VS command {attrib.Name} - resolved {attrib.Scope} scope to {resolvedScope}", LOG_CATEGORY); } } - if (string.IsNullOrEmpty(resolvedBinding)) + if (string.IsNullOrEmpty(resolvedScope)) { _log.LogMessage($"VS command {attrib.Name} - could not resolve {attrib.Scope} scope", LOG_CATEGORY); continue; } - binding = $"{resolvedBinding}::{binding}"; + binding = $"{resolvedScope}::{binding}"; } command.Bindings = binding; } else + { _log.LogMessage($"VS command {attrib.Name} is not available", LOG_CATEGORY); + } } catch (Exception ex) { - _log.LogMessage($"Error assigning shortcut for VS {attrib.Name} command and {attrib.Binding} binding", ex, LOG_CATEGORY); + _log.LogMessage($"Error assigning shortcut for VS {attrib.Name} command and {attrib.Binding} binding with {attrib.Scope} scope", ex, LOG_CATEGORY); } } From 701475c7b074f0b97905107f5f44176f7ff8918d Mon Sep 17 00:00:00 2001 From: Sergey M Date: Sat, 29 Aug 2020 17:30:19 -0400 Subject: [PATCH 2/5] Memory footprint improvements. --- .../Features/CodeBrowserViewModelTests.cs | 20 ++++++++ .../CodeBrowser/CodeBrowserControl.xaml | 29 ++++++++--- .../CodeBrowser/CodeBrowserViewModel.cs | 29 +++++++++++ .../CodeBrowser/CodeBrowserWindow.xaml | 6 +-- .../FileBrowser/FileBrowserControl.xaml | 13 ++--- .../Options/OptionsFileBrowserControl.xaml | 9 ++-- DPackRx/Options/OptionsGeneralControl.xaml | 3 +- DPackRx/Properties/DesignTimeResources.xaml | 7 +++ DPackRx/UI/SharedResourceDictionary.cs | 50 +++++++++++++++++++ 9 files changed, 144 insertions(+), 22 deletions(-) create mode 100644 DPackRx/Properties/DesignTimeResources.xaml create mode 100644 DPackRx/UI/SharedResourceDictionary.cs diff --git a/DPackRx.Tests/Features/CodeBrowserViewModelTests.cs b/DPackRx.Tests/Features/CodeBrowserViewModelTests.cs index 9c9935b..0d9c8fc 100644 --- a/DPackRx.Tests/Features/CodeBrowserViewModelTests.cs +++ b/DPackRx.Tests/Features/CodeBrowserViewModelTests.cs @@ -137,6 +137,10 @@ public void OnInitialize(string search, CodeModelFilterFlags flags, int expected Assert.That(viewModel.FilteredMembers.Count, Is.EqualTo(expectedCount)); Assert.That(viewModel.Search, Is.EqualTo(search)); Assert.That(viewModel.Filter, Is.EqualTo(flags)); + Assert.That(viewModel.SameType, Is.True); + Assert.That(viewModel.FileName, Is.EqualTo("test")); + Assert.That(viewModel.Title, Is.Not.Null.And.Not.Empty); + Assert.That(viewModel.Title, Contains.Substring(" - test")); _fileProcessorMock.Verify(p => p.GetMembers(ProcessorFlags.IncludeFileCodeModel, It.IsAny())); _optionsServiceMock.Verify(o => o.GetStringOption(viewModel.Feature, "File", string.Empty)); _optionsServiceMock.Verify(o => o.GetStringOption(viewModel.Feature, "Search", string.Empty)); @@ -145,6 +149,22 @@ public void OnInitialize(string search, CodeModelFilterFlags flags, int expected _searchMatchServiceMock.Verify(s => s.MatchItems(search, It.IsAny>()), Times.Once); } + [Test] + public void OnInitialize_NotSameType() + { + _members.Clear(); + _members.AddRange(new[] + { + new MemberCodeModel { Name = "Test1", FullName = "Test1", ElementKind = Kind.Class, Rank = 0, Matched = false }, + new MemberCodeModel { Name = "Test2", FullName = "Test2", ElementKind = Kind.Class, Rank = 0, Matched = false }, + }); + var viewModel = GetViewModel(); + + viewModel.OnInitialize(CodeModelFilterFlags.All); + + Assert.That(viewModel.SameType, Is.False); + } + [Test] public void OnInitialize_ResetSearch() { diff --git a/DPackRx/Features/CodeBrowser/CodeBrowserControl.xaml b/DPackRx/Features/CodeBrowser/CodeBrowserControl.xaml index 6985ee0..95bfd8e 100644 --- a/DPackRx/Features/CodeBrowser/CodeBrowserControl.xaml +++ b/DPackRx/Features/CodeBrowser/CodeBrowserControl.xaml @@ -1,13 +1,14 @@  @@ -15,9 +16,9 @@ - + - + @@ -104,8 +105,20 @@ - + + + + + diff --git a/DPackRx/Features/CodeBrowser/CodeBrowserViewModel.cs b/DPackRx/Features/CodeBrowser/CodeBrowserViewModel.cs index d302a59..0bf97e8 100644 --- a/DPackRx/Features/CodeBrowser/CodeBrowserViewModel.cs +++ b/DPackRx/Features/CodeBrowser/CodeBrowserViewModel.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.Design; +using System.IO; using System.Linq; using System.Windows; using System.Windows.Data; @@ -35,7 +36,9 @@ public class CodeBrowserViewModel : FeatureViewModelBase private readonly IShellImageService _shellImageService; private readonly ObservableCollection _sourceMembers; private readonly CollectionViewSource _members; + private string _title; private string _search = string.Empty; + private bool _sameType; #endregion @@ -79,6 +82,7 @@ public override void OnInitialize(object argument) throw new ArgumentException("Invalid initialization argument", nameof(argument)); this.FileName = _optionsService.GetStringOption(this.Feature, "File", this.FileName); + this.Title = $"USysWare Code Browser - {Path.GetFileName(this.FileName)}"; _search = _optionsService.GetStringOption(this.Feature, "Search", _search); this.Filter = (CodeModelFilterFlags)argument; var filter = (CodeModelFilterFlags)_optionsService.GetIntOption(this.Feature, "Filter", (int)this.Filter); @@ -138,6 +142,16 @@ public override void OnClose(bool apply) #region Properties + public string Title + { + get { return _title; } + set + { + _title = value; + RaisePropertyChanged(nameof(this.Title)); + } + } + /// /// Search text. /// @@ -167,6 +181,19 @@ public ICollectionView Members get { return _members?.View; } } + /// + /// Whether all code model members are from the same type declaration. + /// + public bool SameType + { + get { return _sameType; } + set + { + _sameType = value; + RaisePropertyChanged(nameof(this.SameType)); + } + } + /// /// Filtered members. /// @@ -227,6 +254,8 @@ private void ApplyMembers() var model = _fileProcessor.GetMembers(flags, this.Filter); var members = model.Members; var fileName = model.FileName; + this.SameType = model.Members.Count( + m => (m.ElementKind == Kind.Class) || (m.ElementKind == Kind.Interface) || (m.ElementKind == Kind.Struct) || (m.ElementKind == Kind.Enum)) <= 1; // Reset search on new file if (!string.IsNullOrEmpty(this.FileName) && !string.IsNullOrEmpty(fileName) && !fileName.Equals(this.FileName, StringComparison.OrdinalIgnoreCase)) diff --git a/DPackRx/Features/CodeBrowser/CodeBrowserWindow.xaml b/DPackRx/Features/CodeBrowser/CodeBrowserWindow.xaml index 43d04bb..4ea92dc 100644 --- a/DPackRx/Features/CodeBrowser/CodeBrowserWindow.xaml +++ b/DPackRx/Features/CodeBrowser/CodeBrowserWindow.xaml @@ -1,17 +1,17 @@  diff --git a/DPackRx/Features/FileBrowser/FileBrowserControl.xaml b/DPackRx/Features/FileBrowser/FileBrowserControl.xaml index 6c59473..2fedc4b 100644 --- a/DPackRx/Features/FileBrowser/FileBrowserControl.xaml +++ b/DPackRx/Features/FileBrowser/FileBrowserControl.xaml @@ -1,13 +1,14 @@  @@ -15,9 +16,9 @@ - + - + diff --git a/DPackRx/Options/OptionsFileBrowserControl.xaml b/DPackRx/Options/OptionsFileBrowserControl.xaml index 32d0e6c..f0ec128 100644 --- a/DPackRx/Options/OptionsFileBrowserControl.xaml +++ b/DPackRx/Options/OptionsFileBrowserControl.xaml @@ -1,18 +1,19 @@  - + diff --git a/DPackRx/Options/OptionsGeneralControl.xaml b/DPackRx/Options/OptionsGeneralControl.xaml index 07d57f2..4b659bf 100644 --- a/DPackRx/Options/OptionsGeneralControl.xaml +++ b/DPackRx/Options/OptionsGeneralControl.xaml @@ -4,6 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DPackRx.Options" + xmlns:ui="clr-namespace:DPackRx.UI" mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="400"> @@ -11,7 +12,7 @@ - + diff --git a/DPackRx/Properties/DesignTimeResources.xaml b/DPackRx/Properties/DesignTimeResources.xaml new file mode 100644 index 0000000..c3697c4 --- /dev/null +++ b/DPackRx/Properties/DesignTimeResources.xaml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/DPackRx/UI/SharedResourceDictionary.cs b/DPackRx/UI/SharedResourceDictionary.cs new file mode 100644 index 0000000..41d4ab1 --- /dev/null +++ b/DPackRx/UI/SharedResourceDictionary.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Windows; + +namespace DPackRx.UI +{ + /// + /// Provides cached hash table / dictionary implementation that contains WPF resources used by components and other elements of a WPF application. + /// + public class SharedResourceDictionary : ResourceDictionary + { + #region Fields + + private Uri _sourceUri; + private static readonly Dictionary _sharedDictionaries = new Dictionary(10); + + #endregion + + #region Properties + + /// + /// Uniform resource identifier (URI) to load resources from. + /// + public new Uri Source + { + get { return _sourceUri; } + set + { + _sourceUri = value; + + if (value != null) + { + if (_sharedDictionaries.ContainsKey(value)) + { + this.MergedDictionaries.Add(_sharedDictionaries[value]); + } + else + { + // Load the dictionary by setting the source of the base class + base.Source = value; + + _sharedDictionaries.Add(value, this); + } + } + } + } + + #endregion + } +} \ No newline at end of file From dd1a7248d7c7edefe3f8d0967994334a02ff52d3 Mon Sep 17 00:00:00 2001 From: Sergey M Date: Sat, 29 Aug 2020 17:30:55 -0400 Subject: [PATCH 3/5] Build .vsix generation adjustments. --- DPackRx/DPackRx.targets | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/DPackRx/DPackRx.targets b/DPackRx/DPackRx.targets index 04761d8..30d3ade 100644 --- a/DPackRx/DPackRx.targets +++ b/DPackRx/DPackRx.targets @@ -25,11 +25,14 @@ <_AssemblyInfoEx>$(MSBuildProjectDirectory)\$(IntermediateOutputPath)AssemblyInfoEx.cs <_AssemblyFileVersion Condition=" '$(_AssemblyFileVersion)'=='' ">true + <_CreateVsix>true + <_CreateVsix Condition=" '$(Configuration)' == 'Debug' AND '$(BuildingInsideVisualStudio)' == 'true' ">false - + @@ -48,6 +51,7 @@ - + <_GeneratedVSIXPackage Include="$(TargetVsixContainerName)" /> <_SourceVSIXPackage Include="@(_GeneratedVSIXPackage->'$(TargetDir)%(Filename)%(Extension)')" /> From ac1d56ba68b7fc60231cdd2ab762d85120b8a9ba Mon Sep 17 00:00:00 2001 From: Sergey M Date: Sat, 29 Aug 2020 17:31:25 -0400 Subject: [PATCH 4/5] Implemented browsers search results Pg Up/Down navigation. --- DPackRx/Extensions/UIExtensions.cs | 31 +++++++++++++ .../TextBoxInputRedirectToListView.cs | 43 ++++++++++++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 DPackRx/Extensions/UIExtensions.cs diff --git a/DPackRx/Extensions/UIExtensions.cs b/DPackRx/Extensions/UIExtensions.cs new file mode 100644 index 0000000..5fa7955 --- /dev/null +++ b/DPackRx/Extensions/UIExtensions.cs @@ -0,0 +1,31 @@ +using System.Windows.Media; + +namespace DPackRx.Extensions +{ + public static class UIExtensions + { + /// + /// Custom: returns child element of a given type. + /// + public static T GetChild(this Visual element) where T : Visual + { + if (element == null) + return default; + + if (element.GetType() == typeof(T)) + return element as T; + + T result = null; + + for (var index = 0; index < VisualTreeHelper.GetChildrenCount(element); index++) + { + var visualElement = VisualTreeHelper.GetChild(element, index) as Visual; + result = visualElement.GetChild(); + if (result != null) + break; + } + + return result; + } + } +} \ No newline at end of file diff --git a/DPackRx/UI/Behaviors/TextBoxInputRedirectToListView.cs b/DPackRx/UI/Behaviors/TextBoxInputRedirectToListView.cs index 3135414..443c753 100644 --- a/DPackRx/UI/Behaviors/TextBoxInputRedirectToListView.cs +++ b/DPackRx/UI/Behaviors/TextBoxInputRedirectToListView.cs @@ -236,10 +236,40 @@ private static void PreviewKeyDown(object sender, KeyEventArgs e) viewItemIndex = control.SelectedIndex; } break; - // TODO: would like to Page Up/Down via ScrollViewer but couldn't figure out how to change the selection accordingly - // case Key.PageUp: - // case Key.PageDown: - } + case Key.PageUp: + case Key.PageDown: + var scrollViewer = control.GetChild(); + if (scrollViewer != null) + { + redirected = true; + if (e.Key == Key.PageUp) + scrollViewer.PageUp(); + else + scrollViewer.PageDown(); + control.UpdateLayout(); // the only way I could figure out for page up/down to register + + var panel = control.GetChild(); + if (panel != null) + { + viewItemIndex = (int)panel.VerticalOffset; + + if (e.Key == Key.PageUp) + { + if (viewItemIndex == control.SelectedIndex) + viewItemIndex = 0; + } + else + { + if (viewItemIndex <= control.SelectedIndex) + viewItemIndex = control.Items.Count - 1; + } + + if ((viewItemIndex >= 0) && (viewItemIndex <= control.Items.Count - 1)) + control.SelectedIndex = viewItemIndex; + } + } + break; + } // switch if (redirected && (viewItemIndex >= 0) && (viewItemIndex <= control.Items.Count - 1)) control.ScrollIntoView(control.Items[viewItemIndex]); @@ -263,8 +293,9 @@ private static void PreviewKeyDown(object sender, KeyEventArgs e) if ((utilsService != null) && (shellStatusBarService != null)) { - utilsService.SetClipboardData(item.Name); - shellStatusBarService.SetStatusBarText($"{Path.GetFileName(item.Name)} name copied to the clipboard"); + var name = Path.GetFileName(item.Name); + utilsService.SetClipboardData(name); + shellStatusBarService.SetStatusBarText($"'{name}' copied to the clipboard"); redirected = true; e.Handled = redirected; From a5d5f561a2d68ee061a14dc26d342e80a7e47fec Mon Sep 17 00:00:00 2001 From: Sergey M Date: Sat, 29 Aug 2020 17:31:35 -0400 Subject: [PATCH 5/5] Beta version bump. --- DPackRx/DPackRx.csproj | 6 ++++++ DPackRx/source.extension.vsixmanifest | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/DPackRx/DPackRx.csproj b/DPackRx/DPackRx.csproj index 9946905..a99ac2b 100644 --- a/DPackRx/DPackRx.csproj +++ b/DPackRx/DPackRx.csproj @@ -65,6 +65,7 @@ + @@ -206,6 +207,7 @@ + @@ -502,6 +504,10 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + MSBuild:Compile Designer diff --git a/DPackRx/source.extension.vsixmanifest b/DPackRx/source.extension.vsixmanifest index 0767695..6ed4561 100644 --- a/DPackRx/source.extension.vsixmanifest +++ b/DPackRx/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + DPack Rx FREE tools collection designed to greatly increase developer's productivity, automate repetitive processes and expand upon some of Microsoft Visual Studio features. Visual Studio 2017 and 2019 are supported. https://github.com/usysware/dpack