From 2511f213eb1c11f530fb9b571f0585f502271599 Mon Sep 17 00:00:00 2001 From: Nils Andresen Date: Wed, 7 Jul 2021 09:26:21 +0200 Subject: [PATCH] small fixes * hide "empty" projects in tool window * Refresh-Button as Icon * a bit more theming --- .gitignore | 2 + src/MediatR-vs/MediatR-vs.csproj | 1 + src/MediatR-vs/MediatrToolWindow.cs | 2 +- src/MediatR-vs/MediatrToolWindowControl.xaml | 75 ++++++++++++------ .../MediatrToolWindowControl.xaml.cs | 67 +--------------- src/MediatR-vs/MediatrToolWindowViewModel.cs | 77 +++++++++++++++++++ src/MediatR-vs/Models/MediatrProject.cs | 7 +- src/MediatR-vs/MouseDoubleClick.cs | 15 ++-- src/MediatR-vs/ProjectContentAdapter.cs | 60 +++++++++++++-- todo.md | 10 +-- 10 files changed, 205 insertions(+), 111 deletions(-) create mode 100644 src/MediatR-vs/MediatrToolWindowViewModel.cs diff --git a/.gitignore b/.gitignore index ce8da54..8e5f417 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,5 @@ docs/input/tasks/* # Wyam related config.wyam.* +.vshistory/ +.history/ diff --git a/src/MediatR-vs/MediatR-vs.csproj b/src/MediatR-vs/MediatR-vs.csproj index 47f4a1b..a71f1f8 100644 --- a/src/MediatR-vs/MediatR-vs.csproj +++ b/src/MediatR-vs/MediatR-vs.csproj @@ -52,6 +52,7 @@ + diff --git a/src/MediatR-vs/MediatrToolWindow.cs b/src/MediatR-vs/MediatrToolWindow.cs index bda4a15..8cf8ae6 100644 --- a/src/MediatR-vs/MediatrToolWindow.cs +++ b/src/MediatR-vs/MediatrToolWindow.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell; using System; using System.Runtime.InteropServices; diff --git a/src/MediatR-vs/MediatrToolWindowControl.xaml b/src/MediatR-vs/MediatrToolWindowControl.xaml index 04fcc0e..0932ef1 100644 --- a/src/MediatR-vs/MediatrToolWindowControl.xaml +++ b/src/MediatR-vs/MediatrToolWindowControl.xaml @@ -1,4 +1,4 @@ - - - - + + + + + - + + + + - - diff --git a/src/MediatR-vs/MediatrToolWindowControl.xaml.cs b/src/MediatR-vs/MediatrToolWindowControl.xaml.cs index 200c5a8..b6f8729 100644 --- a/src/MediatR-vs/MediatrToolWindowControl.xaml.cs +++ b/src/MediatR-vs/MediatrToolWindowControl.xaml.cs @@ -1,84 +1,21 @@ using System; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; using System.Windows.Controls; -using System.Windows.Input; -using MediatRvs.Models; -using Microsoft.VisualStudio.PlatformUI; -using Microsoft.VisualStudio.Shell; -using Task = System.Threading.Tasks.Task; namespace MediatRvs { /// /// Interaction logic for MediatrToolWindowControl. /// - public partial class MediatrToolWindowControl : UserControl, INotifyPropertyChanged + public partial class MediatrToolWindowControl : UserControl { - private MediatrProject[] _projects; - private ICommand _refreshCommand; - /// /// Initializes a new instance of the class. /// public MediatrToolWindowControl() { InitializeComponent(); - DataContext = this; - RefreshCommand = new DelegateCommand(LoadProjects); - ThreadHelper.JoinableTaskFactory.Run(async () => await InitLoadProjectsAsync()); - } - - public MediatrProject[] Projects - { - get => _projects; - set - { - _projects = value; - OnPropertyChanged(); - } - } - - public ICommand RefreshCommand - { - get => _refreshCommand; - set - { - _refreshCommand = value; - OnPropertyChanged(); - } - } - - private async Task InitLoadProjectsAsync() - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - LoadProjects(); - } - - private void LoadProjects() - { - ThreadHelper.JoinableTaskFactory.Run(async () => - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - var adapter = new ProjectContentAdapter(); - try - { - var projects = adapter.GetMessages().ToArray(); - Projects = projects; - } - catch (Exception e) - { - Logger.Log(e); - } - }); + DataContext = new MediatrToolWindowViewModel(); } - public event PropertyChangedEventHandler PropertyChanged; - - private void OnPropertyChanged([CallerMemberName] string property = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); - } } } diff --git a/src/MediatR-vs/MediatrToolWindowViewModel.cs b/src/MediatR-vs/MediatrToolWindowViewModel.cs new file mode 100644 index 0000000..3865c4d --- /dev/null +++ b/src/MediatR-vs/MediatrToolWindowViewModel.cs @@ -0,0 +1,77 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Windows.Input; +using MediatRvs.Models; +using Microsoft.VisualStudio.PlatformUI; +using Microsoft.VisualStudio.Shell; +using Task = System.Threading.Tasks.Task; + +namespace MediatRvs +{ + public class MediatrToolWindowViewModel: INotifyPropertyChanged + { + private MediatrProject[] _projects; + private ICommand _refreshCommand; + + public MediatrToolWindowViewModel() + { + RefreshCommand = new DelegateCommand(LoadProjects); + ThreadHelper.JoinableTaskFactory.Run(async () => await InitLoadProjectsAsync()); + + } + + public MediatrProject[] Projects + { + get => _projects; + set + { + _projects = value; + OnPropertyChanged(); + } + } + + public ICommand RefreshCommand + { + get => _refreshCommand; + set + { + _refreshCommand = value; + OnPropertyChanged(); + } + } + + private async Task InitLoadProjectsAsync() + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + LoadProjects(); + } + + private void LoadProjects() + { + ThreadHelper.JoinableTaskFactory.Run(async () => + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + var adapter = new ProjectContentAdapter(); + try + { + var elements = adapter.GetMediatRContent(); + Projects = elements.ToArray(); + } + catch (Exception e) + { + Logger.Log(e); + } + }); + } + + public event PropertyChangedEventHandler PropertyChanged; + + private void OnPropertyChanged([CallerMemberName] string property = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); + } + + } +} diff --git a/src/MediatR-vs/Models/MediatrProject.cs b/src/MediatR-vs/Models/MediatrProject.cs index f5efdab..a25e721 100644 --- a/src/MediatR-vs/Models/MediatrProject.cs +++ b/src/MediatR-vs/Models/MediatrProject.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace MediatRvs.Models { @@ -6,7 +6,8 @@ public class MediatrProject { public string Name { get; set; } - public IEnumerable Elements { get; set; } public string Path { get; set; } + + public IEnumerable Elements { get; set; } } -} \ No newline at end of file +} diff --git a/src/MediatR-vs/MouseDoubleClick.cs b/src/MediatR-vs/MouseDoubleClick.cs index 3a16bd5..eac460b 100644 --- a/src/MediatR-vs/MouseDoubleClick.cs +++ b/src/MediatR-vs/MouseDoubleClick.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Windows; using System.Windows.Input; namespace MediatRvs { - // https://stackoverflow.com/a/4498006/180156 + // inspired by https://stackoverflow.com/a/4498006/180156 public class MouseDoubleClick { @@ -91,14 +91,13 @@ private static void OnMouseSingleClick(object sender, RoutedEventArgs e) var timeBetweenClicks = DateTime.Now - lastClick; var timeout = GetDoubleClickTimeout((DependencyObject)sender); - if (timeBetweenClicks < timeout) + if (timeBetweenClicks >= timeout) { - // this is it! - lastSender = null; - OnMouseDoubleClick(sender, e); + return; } - return; + lastSender = null; + OnMouseDoubleClick(sender, e); } // this is the first click @@ -114,4 +113,4 @@ private static void OnMouseDoubleClick(object sender, RoutedEventArgs e) command?.Execute(commandParameter); } } -} \ No newline at end of file +} diff --git a/src/MediatR-vs/ProjectContentAdapter.cs b/src/MediatR-vs/ProjectContentAdapter.cs index 746793f..1b589db 100644 --- a/src/MediatR-vs/ProjectContentAdapter.cs +++ b/src/MediatR-vs/ProjectContentAdapter.cs @@ -1,30 +1,31 @@ using EnvDTE; using MediatRvs.Extensions; +using MediatRvs.Models; + using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Linq; -using MediatRvs.Models; + using CodeClass = EnvDTE.CodeClass; namespace MediatRvs { public class ProjectContentAdapter { - public IEnumerable GetMessages() + public IEnumerable GetMediatRContent() { ThreadHelper.ThrowIfNotOnUIThread(); - var service = (DTE)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SDTE)); - var projects = service.Solution.Projects.Cast(); + var projects = GetAllProjects(); foreach (var project in projects) { Logger.Log("Crawling Project: " + project.FullName); var projectItems = GetAllProjectItems(project).ToList(); - var elements = new List(); + foreach (var item in projectItems) { try @@ -40,7 +41,7 @@ public IEnumerable GetMessages() FullName = e.FullName, ElementType = GetElementType(e), ProjectItem = item, - CodeElement = e + CodeElement = e, }; }) .Where(x => x.ElementType != MediatrElementType.Unknown) @@ -52,15 +53,22 @@ public IEnumerable GetMessages() catch (Exception e) { Logger.Log(e); + e.Log(); } } + if (elements.Count == 0) + { + continue; + } + yield return new MediatrProject { Name = project.Name, Path = project.FullName, Elements = elements }; + } } @@ -126,7 +134,6 @@ private MediatrElementType GetElementType(CodeElement initialElement) return MediatrElementType.Unknown; } - private IEnumerable GetAllElements(ProjectItem item) { ThreadHelper.ThrowIfNotOnUIThread(); @@ -196,5 +203,44 @@ private IEnumerable GetAllProjectItems(Project project) return result; } + + private IEnumerable GetAllProjects() + { + ThreadHelper.ThrowIfNotOnUIThread(); + var stack = new Stack(); + var service = (DTE)Package.GetGlobalService(typeof(SDTE)); + service.Solution.Projects.EnsureNotNull().ToList().ForEach(x => stack.Push(x)); + + var result = new List(); + while (stack.Count > 0) + { + try + { + var item = stack.Pop(); + if (!string.IsNullOrEmpty(item.FileName)) + { + // it's only a project if it has a filename... + result.Add(item); + } + + item.ProjectItems + .EnsureNotNull() + .Select(x => + { + ThreadHelper.ThrowIfNotOnUIThread(); + return x.Object; + }) + .OfType() + .ToList() + .ForEach(p => stack.Push(p)); + } + catch (Exception e) + { + Logger.Log(e); + } + } + + return result; + } } } diff --git a/todo.md b/todo.md index 3ade2d5..bf656e0 100644 --- a/todo.md +++ b/todo.md @@ -1,25 +1,25 @@ # TODO ## Needed for release 0.1.0 -* Solution Folders are not searched... * UI more like VS * Current selection in tree (esp. in dark mode) * "menu stripe" in tool window - * Refresh-Button as Icon + ## New Features/Improvements * searching in tool window -* hide "empty" projects in tool window (plus show all in menu stripe?) +* add a sho-all button in menu stripe to un-hide "empty" projects in tool window? * Icon for vsix * Icons in tree * Remove the logger nupkg and implement/search a better one (i.e. one with "verbose") * Different groupings in tree * by project * by type -* Auto-Refresh on project-load / VS load +* Auto-Refresh on project-load / VS load (compare https://www.visualstudiogeeks.com/blog/visual%20studio%20extensibility/how-to-monitor-solution-events-in-vs-extensions) +* Try removing the DTE ## New Stories * Jump from Request/Notification to "Search all handlers" window -* Support VS 2022 \ No newline at end of file +* Support VS 2022