From 37b5616138ccbf892e39798755e68e8e72a7f968 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Wed, 13 Nov 2024 22:47:04 +0100 Subject: [PATCH 01/57] prj: Refactor project structure Overhaul `ExplorerBrowser`, and add second Browser pane --- src/electrifier/App.xaml.cs | 6 +- .../ExplorerBrowser.NavigationService.cs | 192 ------------------ .../Controls/Vanara/ExplorerBrowser.xaml | 1 + .../Controls/Vanara/ExplorerBrowser.xaml.cs | 2 +- .../Vanara/Services/IShellNamespaceService.cs | 3 + .../Controls/Vanara/Services/NavigationLog.cs | 174 ++++++++++++++++ .../Vanara/Services/NavigationLogEventArgs.cs | 23 +++ .../Vanara/Services/ShellNamespaceService.cs | 95 +++++---- .../Controls/Vanara/ShellListView.xaml | 3 +- .../ViewModels/FileManagerViewModel.cs | 1 - src/electrifier/Views/FileManagerPage.xaml | 65 ++++-- 11 files changed, 304 insertions(+), 261 deletions(-) delete mode 100644 src/electrifier/Controls/Vanara/ExplorerBrowser.NavigationService.cs create mode 100644 src/electrifier/Controls/Vanara/Services/IShellNamespaceService.cs create mode 100644 src/electrifier/Controls/Vanara/Services/NavigationLog.cs create mode 100644 src/electrifier/Controls/Vanara/Services/NavigationLogEventArgs.cs diff --git a/src/electrifier/App.xaml.cs b/src/electrifier/App.xaml.cs index 8eb6221..9338af0 100644 --- a/src/electrifier/App.xaml.cs +++ b/src/electrifier/App.xaml.cs @@ -1,5 +1,6 @@ using electrifier.Activation; using electrifier.Contracts.Services; +using electrifier.Controls.Vanara.Services; using electrifier.Helpers; using electrifier.Models; using electrifier.Notifications; @@ -10,7 +11,6 @@ using Microsoft.Extensions.Hosting; using Microsoft.UI.Xaml; using System.Diagnostics; -using electrifier.Controls.Vanara.Services; using WinUIEx; using static Microsoft.Extensions.Hosting.Host; using UnhandledExceptionEventArgs = Microsoft.UI.Xaml.UnhandledExceptionEventArgs; @@ -42,7 +42,9 @@ public IHost Host public static ShellNamespaceService NamespaceService { get; - } = new() { }; + } = new() + { + }; public App() { diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.NavigationService.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.NavigationService.cs deleted file mode 100644 index 8027001..0000000 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.NavigationService.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using static Vanara.PInvoke.Shell32; -using Vanara.Windows.Shell; - -namespace electrifier.Controls.Vanara; - -public sealed partial class ExplorerBrowser -{ - - /* - /// The navigation log is a history of the locations visited by the explorer browser. - public class NavigationLog - { - private readonly ExplorerBrowser? parent = null; - - /// The pending navigation log action. null if the user is not navigating via the navigation log. - private PendingNavigation? pendingNavigation; - - internal NavigationLog(ExplorerBrowser parent) - { - // Hook navigation events from the parent to distinguish between navigation log induced navigation, and other navigations. - this.parent = parent ?? throw new ArgumentNullException(nameof(parent)); - this.parent.Navigated += OnNavigated; - this.parent.NavigationFailed += OnNavigationFailed; - } - - /// Fires when the navigation log changes or the current navigation position changes - public event EventHandler? NavigationLogChanged; - - /// Indicates the presence of locations in the log that can be reached by calling Navigate(Backward) - public bool CanNavigateBackward => CurrentLocationIndex > 0; - - /// Indicates the presence of locations in the log that can be reached by calling Navigate(Forward) - public bool CanNavigateForward => CurrentLocationIndex < Locations.Count - 1; - - /// Gets the shell object in the Locations collection pointed to by CurrentLocationIndex. - public ShellItem? CurrentLocation => CurrentLocationIndex < 0 ? null : Locations[CurrentLocationIndex]; - - /// - /// An index into the Locations collection. The ShellItem pointed to by this index is the current location of the ExplorerBrowser. - /// - public int CurrentLocationIndex { get; set; } = -1; - - /// The navigation log - public List Locations { get; } = new List(); - - /// Clears the contents of the navigation log. - public void Clear() - { - if (Locations.Count == 0) return; - - var oldCanNavigateBackward = CanNavigateBackward; - var oldCanNavigateForward = CanNavigateForward; - - Locations.Clear(); - CurrentLocationIndex = -1; - - var args = new NavigationLogEventArgs - { - LocationsChanged = true, - CanNavigateBackwardChanged = oldCanNavigateBackward != CanNavigateBackward, - CanNavigateForwardChanged = oldCanNavigateForward != CanNavigateForward - }; - NavigationLogChanged?.Invoke(this, args); - } - - internal bool NavigateLog(NavigationLogDirection direction) - { - // determine proper index to navigate to - int locationIndex; - switch (direction) - { - case NavigationLogDirection.Backward when CanNavigateBackward: - locationIndex = CurrentLocationIndex - 1; - break; - - case NavigationLogDirection.Forward when CanNavigateForward: - locationIndex = CurrentLocationIndex + 1; - break; - - default: - return false; - } - - // initiate traversal request - var location = Locations[locationIndex]; - pendingNavigation = new PendingNavigation(location, locationIndex); - parent?.Navigate(location); - return true; - } - - internal bool NavigateLog(int index) - { - // can't go anywhere - if (index >= Locations.Count || index < 0) return false; - - // no need to re navigate to the same location - if (index == CurrentLocationIndex) return false; - - // initiate traversal request - var location = Locations[index]; - pendingNavigation = new PendingNavigation(location, index); - parent?.Navigate(location); - return true; - } - - private void OnNavigated(object? sender, NavigatedEventArgs args) - { - var eventArgs = new NavigationLogEventArgs(); - var oldCanNavigateBackward = CanNavigateBackward; - var oldCanNavigateForward = CanNavigateForward; - - if (pendingNavigation != null) - { - // navigation log traversal in progress - - // determine if new location is the same as the traversal request - var shellItemsEqual = pendingNavigation.Location.IShellItem.Compare(args.NewLocation?.IShellItem, SICHINTF.SICHINT_ALLFIELDS, out var i).Succeeded && i == 0; - if (!shellItemsEqual) - { - // new location is different than traversal request, behave is if it never happened! remove history following - // currentLocationIndex, append new item - if (CurrentLocationIndex < Locations.Count - 1) - { - Locations.RemoveRange(CurrentLocationIndex + 1, Locations.Count - (CurrentLocationIndex + 1)); - } - if (args.NewLocation is not null) Locations.Add(args.NewLocation); - CurrentLocationIndex = Locations.Count - 1; - eventArgs.LocationsChanged = true; - } - else - { - // log traversal successful, update index - CurrentLocationIndex = pendingNavigation.Index; - eventArgs.LocationsChanged = false; - } - pendingNavigation = null; - } - else - { - // remove history following currentLocationIndex, append new item - if (CurrentLocationIndex < Locations.Count - 1) - { - Locations.RemoveRange(CurrentLocationIndex + 1, Locations.Count - (CurrentLocationIndex + 1)); - } - if (args.NewLocation is not null) Locations.Add(args.NewLocation); - CurrentLocationIndex = Locations.Count - 1; - eventArgs.LocationsChanged = true; - } - - // update event args - eventArgs.CanNavigateBackwardChanged = oldCanNavigateBackward != CanNavigateBackward; - eventArgs.CanNavigateForwardChanged = oldCanNavigateForward != CanNavigateForward; - - NavigationLogChanged?.Invoke(this, eventArgs); - } - - private void OnNavigationFailed(object? sender, NavigationFailedEventArgs args) => pendingNavigation = null; - - /// A navigation traversal request - private class PendingNavigation - { - internal PendingNavigation(ShellItem location, int index) - { - Location = location; - Index = index; - } - - internal int Index { get; set; } - - internal ShellItem Location { get; set; } - } - } - - /// The event argument for NavigationLogChangedEvent - public class NavigationLogEventArgs : EventArgs - { - /// Indicates CanNavigateBackward has changed - public bool CanNavigateBackwardChanged { get; set; } - - /// Indicates CanNavigateForward has changed - public bool CanNavigateForwardChanged { get; set; } - - /// Indicates the Locations collection has changed - public bool LocationsChanged { get; set; } - } - */ -} diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml index ad43167..e1286f9 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml @@ -4,6 +4,7 @@ xmlns:local="using:electrifier.Controls.Vanara" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:services="using:electrifier.Controls.Vanara.Services" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" d:DataContext="{d:DesignInstance Type=local:ExplorerBrowser}" mc:Ignorable="d"> diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs index 1e5e755..4c1adde 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs @@ -137,7 +137,7 @@ public class BrowserItem(Shell32.PIDL pidl, bool isFolder) public readonly Shell32.PIDL PIDL = new(pidl); public string DisplayName => ShellItem.GetDisplayName(ShellItemDisplayString.NormalDisplay) ?? ShellItem.ToString(); public ShellItem ShellItem = new(pidl); - public SoftwareBitmapSource SoftwareBitmapSource = isFolder ? ShellNamespaceService.DefaultFolderImageBitmapSource : ShellNamespaceService.DefaultDocumentAssocImageBitmapSource; + public SoftwareBitmapSource SoftwareBitmapSource = isFolder ? ShellNamespaceService.FolderBitmapSource : ShellNamespaceService.DocumentBitmapSource; public new ObservableCollection ChildItems = []; public static BrowserItem FromPIDL(Shell32.PIDL pidl) => new(pidl, false); public static BrowserItem FromShellFolder(ShellFolder shellFolder) => new(shellFolder.PIDL, true); diff --git a/src/electrifier/Controls/Vanara/Services/IShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/IShellNamespaceService.cs new file mode 100644 index 0000000..b1a3ec9 --- /dev/null +++ b/src/electrifier/Controls/Vanara/Services/IShellNamespaceService.cs @@ -0,0 +1,3 @@ +namespace electrifier.Controls.Vanara.Services; + +public interface IShellNamespaceService; \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/Services/NavigationLog.cs b/src/electrifier/Controls/Vanara/Services/NavigationLog.cs new file mode 100644 index 0000000..446810a --- /dev/null +++ b/src/electrifier/Controls/Vanara/Services/NavigationLog.cs @@ -0,0 +1,174 @@ +using Vanara.PInvoke; +using Vanara.Windows.Shell; + +namespace electrifier.Controls.Vanara.Services; + +/// The navigation log is a history of the locations visited by the explorer browser. +public class NavigationLog +{ + private readonly ExplorerBrowser? parent = null; + + /// The pending navigation log action. null if the user is not navigating via the navigation log. + private PendingNavigation? pendingNavigation; + + internal NavigationLog(ExplorerBrowser parent) + { + // Hook navigation events from the parent to distinguish between navigation log induced navigation, and other navigations. + this.parent = parent ?? throw new ArgumentNullException(nameof(parent)); + this.parent.Navigated += OnNavigated; + this.parent.NavigationFailed += OnNavigationFailed; + } + + /// Fires when the navigation log changes or the current navigation position changes + public event EventHandler? NavigationLogChanged; + + /// Indicates the presence of locations in the log that can be reached by calling Navigate(Backward) + public bool CanNavigateBackward => CurrentLocationIndex > 0; + + /// Indicates the presence of locations in the log that can be reached by calling Navigate(Forward) + public bool CanNavigateForward => CurrentLocationIndex < Locations.Count - 1; + + /// Gets the shell object in the Locations collection pointed to by CurrentLocationIndex. + public ShellItem? CurrentLocation => CurrentLocationIndex < 0 ? null : Locations[CurrentLocationIndex]; + + /// + /// An index into the Locations collection. The ShellItem pointed to by this index is the current location of the ExplorerBrowser. + /// + public int CurrentLocationIndex { get; set; } = -1; + + /// The navigation log + public List Locations { get; } = new List(); + + /// Clears the contents of the navigation log. + public void Clear() + { + if (Locations.Count == 0) return; + + var oldCanNavigateBackward = CanNavigateBackward; + var oldCanNavigateForward = CanNavigateForward; + + Locations.Clear(); + CurrentLocationIndex = -1; + + var args = new NavigationLogEventArgs + { + LocationsChanged = true, + CanNavigateBackwardChanged = oldCanNavigateBackward != CanNavigateBackward, + CanNavigateForwardChanged = oldCanNavigateForward != CanNavigateForward + }; + NavigationLogChanged?.Invoke(this, args); + } + + internal bool NavigateLog(NavigationLogDirection direction) + { + // determine proper index to navigate to + int locationIndex; + switch (direction) + { + case NavigationLogDirection.Backward when CanNavigateBackward: + locationIndex = CurrentLocationIndex - 1; + break; + + case NavigationLogDirection.Forward when CanNavigateForward: + locationIndex = CurrentLocationIndex + 1; + break; + + default: + return false; + } + + // initiate traversal request + var location = Locations[locationIndex]; + pendingNavigation = new PendingNavigation(location, locationIndex); + parent?.Navigate(location); + return true; + } + + internal bool NavigateLog(int index) + { + // can't go anywhere + if (index >= Locations.Count || index < 0) return false; + + // no need to re navigate to the same location + if (index == CurrentLocationIndex) return false; + + // initiate traversal request + var location = Locations[index]; + pendingNavigation = new PendingNavigation(location, index); + parent?.Navigate(location); + return true; + } + + private void OnNavigated(object? sender, NavigatedEventArgs args) + { + var eventArgs = new NavigationLogEventArgs(); + var oldCanNavigateBackward = CanNavigateBackward; + var oldCanNavigateForward = CanNavigateForward; + + if (pendingNavigation != null) + { + // navigation log traversal in progress + + // determine if new location is the same as the traversal request + var shellItemsEqual = pendingNavigation.Location.IShellItem.Compare(args.NewLocation?.IShellItem, Shell32.SICHINTF.SICHINT_ALLFIELDS, out var i).Succeeded && i == 0; + if (!shellItemsEqual) + { + // new location is different than traversal request, behave is if it never happened! remove history following + // currentLocationIndex, append new item + if (CurrentLocationIndex < Locations.Count - 1) + { + Locations.RemoveRange(CurrentLocationIndex + 1, Locations.Count - (CurrentLocationIndex + 1)); + } + if (args.NewLocation is not null) Locations.Add(args.NewLocation); + CurrentLocationIndex = Locations.Count - 1; + eventArgs.LocationsChanged = true; + } + else + { + // log traversal successful, update index + CurrentLocationIndex = pendingNavigation.Index; + eventArgs.LocationsChanged = false; + } + pendingNavigation = null; + } + else + { + // remove history following currentLocationIndex, append new item + if (CurrentLocationIndex < Locations.Count - 1) + { + Locations.RemoveRange(CurrentLocationIndex + 1, Locations.Count - (CurrentLocationIndex + 1)); + } + if (args.NewLocation is not null) Locations.Add(args.NewLocation); + CurrentLocationIndex = Locations.Count - 1; + eventArgs.LocationsChanged = true; + } + + // update event args + eventArgs.CanNavigateBackwardChanged = oldCanNavigateBackward != CanNavigateBackward; + eventArgs.CanNavigateForwardChanged = oldCanNavigateForward != CanNavigateForward; + + NavigationLogChanged?.Invoke(this, eventArgs); + } + + private void OnNavigationFailed(object? sender, NavigationFailedEventArgs args) => pendingNavigation = null; + + /// A navigation traversal request + private class PendingNavigation + { + internal PendingNavigation(ShellItem location, int index) + { + Location = location; + Index = index; + } + + internal int Index + { + get; set; + } + + internal ShellItem Location + { + get; set; + } + } +} \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/Services/NavigationLogEventArgs.cs b/src/electrifier/Controls/Vanara/Services/NavigationLogEventArgs.cs new file mode 100644 index 0000000..7370a39 --- /dev/null +++ b/src/electrifier/Controls/Vanara/Services/NavigationLogEventArgs.cs @@ -0,0 +1,23 @@ +namespace electrifier.Controls.Vanara.Services; + +/// The event argument for NavigationLogChangedEvent +public class NavigationLogEventArgs : EventArgs +{ + /// Indicates CanNavigateBackward has changed + public bool CanNavigateBackwardChanged + { + get; set; + } + + /// Indicates CanNavigateForward has changed + public bool CanNavigateForwardChanged + { + get; set; + } + + /// Indicates the Locations collection has changed + public bool LocationsChanged + { + get; set; + } +} \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs index c3b9eb0..5ffee39 100644 --- a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs @@ -1,19 +1,17 @@ -using static Vanara.PInvoke.Shell32.ShellUtil; -using static Vanara.PInvoke.Shell32; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using Vanara.PInvoke; using Vanara.Windows.Shell; using Microsoft.UI.Xaml.Media.Imaging; using System.Runtime.InteropServices.WindowsRuntime; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Drawing; using System.Diagnostics; -using static Vanara.PInvoke.Ole32; +using static Vanara.PInvoke.Shell32; +using Microsoft.UI.Xaml.Media.Imaging; +using JetBrains.Annotations; namespace electrifier.Controls.Vanara.Services; -public partial class ShellNamespaceService +public partial class ShellNamespaceService : IShellNamespaceService { /// /// HResult code of ('0x80070490'); @@ -24,12 +22,10 @@ public partial class ShellNamespaceService /// of virtual `Home` directory. /// This equals Shell 32 URI: shell:::{679f85cb-0220-4080-b29b-5540cc05aab6} /// - public static readonly ShellFolder HomeShellFolder = new("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}"); - internal readonly TempShellIconExtractor IconExtractor; - public IReadOnlyList IconExtractorBitmaps; + public static ShellFolder HomeShellFolder => new("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}"); + internal static readonly TempShellIconExtractor IconExtractor = new(ShellFolder.Desktop); + public static IReadOnlyList IconExtractorBitmaps => IconExtractor.ImageList; public int IconSize => IconExtractor.ImageSize; - internal static SoftwareBitmapSource DefaultFolderImageBitmapSource; - internal static SoftwareBitmapSource DefaultDocumentAssocImageBitmapSource; /// /// todo: die ganzen StockIcons in ein struct packen. /// Indexer ist `Shell32.SHSTOCKICONID` @@ -47,43 +43,30 @@ public partial class ShellNamespaceService internal static StockIcon SiLinkOverlay = new(SHSTOCKICONID.SIID_LINK); protected Task? StockIconTask; - /// ShellNamespaceService() Warn: Does not really conform Service Models actually. + /// + /// When used as service, this static might be unnecessary. + /// However, this makes sure the Stock Icon cache gets initialized as soon as possible. + /// + [UsedImplicitly] + public static readonly ShellNamespaceService Instance = new(); + + /// ShellNamespaceService() Warn: Actually does not really conform Service Models. public ShellNamespaceService() { - StockIconTask = InitializeStockIcons(); - IconExtractor = new(ShellFolder.Desktop); - IconExtractorBitmaps = IconExtractor.ImageList; - } - - // TODO: Add await event handler to every ebItem, so Icon Extractor can call back the item - public static async Task RequestChildItemsAsync(ShellFolder shFolder, - FolderItemFilter itemFilter = (FolderItemFilter.Folders | FolderItemFilter.NonFolders), - EventHandler? allFastRowsAddedHandler = null, EventHandler? tableLoadedHandler = null) - { - Debug.Print($".RequestChildItemsAsync(<{shFolder}>) extracting..."); - var ct = new CancellationToken(); - - var propKeys = new List() - { - Ole32.PROPERTYKEY.System.FileFRN, /* This is the unique file ID, also known as the File Reference Number. */ - }; - - var shDataTable = new ShellDataTable(shFolder, itemFilter); - shDataTable.AllFastRowsAdded += allFastRowsAddedHandler; - shDataTable.TableLoaded += tableLoadedHandler; - await shDataTable.PopulateTableAsync(propKeys, ct); - - Debug.Print($".RequestChildItemsAsync(<{shFolder}>): {shDataTable.Rows.Count}"); - - return shDataTable; + StockIconTask = InitializeStockIconsAsync(); + return; } /// Initialize default Stock Icons. /// TODO: INFO: Investigate /// - public static async Task InitializeStockIcons() + private static async Task InitializeStockIconsAsync() { /* Todo: inspect `SHGetStockIconInfo()` */ + //var siFlags = SHGSI.SHGSI_LARGEICON | SHGSI.SHGSI_ICON; + //var siStockIconInfo = new SHSTOCKICONINFO(); + //SHGetStockIconInfo(Shell32.SHSTOCKICONID.SIID_APPLICATION, siFlags, ref siStockIconInfo).ThrowIfFailed(); + try { using var siFolder = new StockIcon(Shell32.SHSTOCKICONID.SIID_FOLDER); @@ -91,15 +74,15 @@ public static async Task InitializeStockIcons() var idx = siFolder.SystemImageIndex; var icnHandle = siFolder.IconHandle.ToIcon(); var bmpSource = GetWinUi3BitmapSourceFromIcon(icnHandle); - DefaultFolderImageBitmapSource = await bmpSource; + ShellNamespaceService.FolderBitmapSource = await bmpSource; } - using var siDocument = new StockIcon(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC); + using var siDocument = new StockIcon(Shell32.SHSTOCKICONID.SIID_DOCASSOC); { var idx = siDocument.SystemImageIndex; var icnHandle = siDocument.IconHandle.ToIcon(); var bmpSource = GetWinUi3BitmapSourceFromIcon(icnHandle); - DefaultDocumentAssocImageBitmapSource = await bmpSource; + ShellNamespaceService.DocumentBitmapSource = await bmpSource; } } catch (Exception e) @@ -109,6 +92,30 @@ public static async Task InitializeStockIcons() } } + + // TODO: Add await event handler to every ebItem, so Icon Extractor can call back the item + public static async Task RequestChildItemsAsync(ShellFolder shFolder, + FolderItemFilter itemFilter = (FolderItemFilter.Folders | FolderItemFilter.NonFolders), + EventHandler? allFastRowsAddedHandler = null, EventHandler? tableLoadedHandler = null) + { + Debug.Print($".RequestChildItemsAsync(<{shFolder}>) extracting..."); + var ct = new CancellationToken(); + + var propKeys = new List() + { + Ole32.PROPERTYKEY.System.FileFRN, /* This is the unique file ID, also known as the File Reference Number. */ + }; + + var shDataTable = new ShellDataTable(shFolder, itemFilter); + shDataTable.AllFastRowsAdded += allFastRowsAddedHandler; + shDataTable.TableLoaded += tableLoadedHandler; + await shDataTable.PopulateTableAsync(propKeys, ct); + + Debug.Print($".RequestChildItemsAsync(<{shFolder}>): {shDataTable.Rows.Count}"); + + return shDataTable; + } + /// Get associated for given Icon /// TODO: INFO: Investigate uwp/api/windows.ui.xaml.media.imaging.WriteableBitmap (WARN: Links to UWP) /// The Icon. diff --git a/src/electrifier/Controls/Vanara/ShellListView.xaml b/src/electrifier/Controls/Vanara/ShellListView.xaml index e24b0be..84d2648 100644 --- a/src/electrifier/Controls/Vanara/ShellListView.xaml +++ b/src/electrifier/Controls/Vanara/ShellListView.xaml @@ -5,7 +5,8 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:electrifier.Controls.Vanara" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - d:DataContext="{d:DesignInstance Type=local:ExplorerBrowser}" + xmlns:services="using:electrifier.Controls.Vanara.Services" + d:DataContext="{d:DesignInstance Type=services:ExplorerBrowser}" mc:Ignorable="d"> diff --git a/src/electrifier/ViewModels/FileManagerViewModel.cs b/src/electrifier/ViewModels/FileManagerViewModel.cs index 29478aa..d49b5dd 100644 --- a/src/electrifier/ViewModels/FileManagerViewModel.cs +++ b/src/electrifier/ViewModels/FileManagerViewModel.cs @@ -10,6 +10,5 @@ public partial class FileManagerViewModel : ObservableRecipient /// FileManagerViewModel public FileManagerViewModel() { - var tsk = ShellNamespaceService.InitializeStockIcons(); } } diff --git a/src/electrifier/Views/FileManagerPage.xaml b/src/electrifier/Views/FileManagerPage.xaml index d5cd14f..07398e7 100644 --- a/src/electrifier/Views/FileManagerPage.xaml +++ b/src/electrifier/Views/FileManagerPage.xaml @@ -6,20 +6,26 @@ xmlns:viewmodels="using:electrifier.ViewModels" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:services="using:electrifier.Controls.Vanara.Services" behaviors:NavigationViewHeaderBehavior.HeaderMode="Minimal" d:DataContext="{d:DesignInstance Type=viewmodels:FileManagerViewModel}" mc:Ignorable="d"> + + * + * + Auto * Auto @@ -135,20 +141,32 @@ + + + - + + + + + + + + + From c8d4e45e2cba92c01edc092033ccb89b43f405c9 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sat, 16 Nov 2024 11:19:37 +0100 Subject: [PATCH 17/57] gui: Do some Refactoring, add dummy Drives Selector Bar --- .../Vanara/Contracts/AbstractBrowserItem.cs | 2 ++ .../Controls/Vanara/ExplorerBrowser.xaml | 1 - src/electrifier/Views/ShellPage.xaml | 25 +++++++++++-------- src/electrifier/Views/WorkbenchPage.xaml | 9 +++++-- src/electrifier/Views/WorkbenchPage.xaml.cs | 20 ++++++++++++++- src/electrifier/electrifier.csproj | 3 +++ 6 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs index 120b154..25fdf08 100644 --- a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs +++ b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs @@ -24,6 +24,8 @@ public abstract class AbstractBrowserItem(bool isFolder, List $"AbstractBrowserItem(<{typeof(T)}>(isFolder {isFolder}, childItems {childItems})"; } diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml index 4c0bd72..f4b0cc4 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml @@ -2,7 +2,6 @@ @@ -39,20 +39,23 @@ - - + Orientation="Horizontal" + BorderBrush="DarkGray" + BorderThickness="3"> + + VerticalAlignment="Center" + HorizontalAlignment="Stretch" /> + diff --git a/src/electrifier/Views/WorkbenchPage.xaml b/src/electrifier/Views/WorkbenchPage.xaml index 2fec16b..8cb824e 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml +++ b/src/electrifier/Views/WorkbenchPage.xaml @@ -22,12 +22,16 @@ Description="Your new Workbench is your personal workspace and data warehouse. You can have as many workbenches as you wish and can customize them here. It is your choice, what Page gets navigated to when electrifier starts the next time. Let This be my preferred choice for the future [x], as I know I can change this always in its ''Settings Page::startup behaviour''." Header="Tip of the day"> + + + + Icon="Clock" /> + - + + Always launch selection when I start this Workbench. diff --git a/src/electrifier/Views/WorkbenchPage.xaml.cs b/src/electrifier/Views/WorkbenchPage.xaml.cs index 7aed89d..f9a5e0c 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml.cs +++ b/src/electrifier/Views/WorkbenchPage.xaml.cs @@ -1,14 +1,32 @@ -using electrifier.ViewModels; +using electrifier.Controls.Vanara.Services; +using electrifier.Controls.Vanara; +using electrifier.ViewModels; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; namespace electrifier.Views; public sealed partial class WorkbenchPage : Page { + //public IAsyncEnumerable DriveItems = RequestDriveItemsAsync(); + public WorkbenchPage() { App.GetService(); InitializeComponent(); + + //var drives = Awaiter(RequestDrivesAsync()); + //foreach (var drive in RequestDrivesAsync()) + //{ + //} + } + + public static async IAsyncEnumerable RequestDriveItemsAsync() + { + yield return (BrowserItem.FromShellFolder(new(@"c:\"))); + //yield return (BrowserItem.FromShellFolder(new(@"d:\"))); + //yield return (BrowserItem.FromShellFolder(new(@"f:\"))); + } + private void ArenaGrid_OnDropCompleted(UIElement sender, DropCompletedEventArgs args) { throw new NotImplementedException(); diff --git a/src/electrifier/electrifier.csproj b/src/electrifier/electrifier.csproj index aa400b1..2e57578 100644 --- a/src/electrifier/electrifier.csproj +++ b/src/electrifier/electrifier.csproj @@ -161,6 +161,9 @@ Resources.Designer.cs + + + true From 8de65c2e424878650e7b76dec2eb3555e3de8ea1 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sat, 16 Nov 2024 13:45:36 +0100 Subject: [PATCH 18/57] Some Prototyping --- .../Controls/Vanara/Contracts/AbstractBrowserItem.cs | 3 +++ .../Vanara/Contracts/IShellNamespaceService.cs | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs index 25fdf08..c1e0a30 100644 --- a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs +++ b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs @@ -24,7 +24,10 @@ public abstract class AbstractBrowserItem(bool isFolder, List $"AbstractBrowserItem(<{typeof(T)}>(isFolder {isFolder}, childItems {childItems})"; } diff --git a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs index 99aa22f..7decd69 100644 --- a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +using electrifier.Controls.Vanara.Services; using Microsoft.UI.Xaml.Media.Imaging; using Vanara.PInvoke; using Vanara.Windows.Shell; @@ -26,10 +27,18 @@ public interface IShellNamespaceService internal static SoftwareBitmapSource DocumentWithAssociationBitmapSource = new(); internal static StockIcon SiFolder = new(Shell32.SHSTOCKICONID.SIID_FOLDER); internal static SoftwareBitmapSource FolderBitmapSource = new(); + //internal static StockIcon SiLibrary = new(Shell32.SHSTOCKICONID.SIID_LINK); + internal static SoftwareBitmapSource LibraryFrontBitmapSource = new(); internal static StockIcon SiFolderBack = new(Shell32.SHSTOCKICONID.SIID_FOLDERBACK); + internal static SoftwareBitmapSource FolderBackBitmapSource = new(); internal static StockIcon SiFolderFront = new(Shell32.SHSTOCKICONID.SIID_FOLDERFRONT); + internal static SoftwareBitmapSource FolderFrontBitmapSource = new(); internal static StockIcon SiFolderOpen = new(Shell32.SHSTOCKICONID.SIID_FOLDEROPEN); + internal static SoftwareBitmapSource FolderOpenBitmapSource = new(); internal static StockIcon SiLinkOverlay = new(Shell32.SHSTOCKICONID.SIID_LINK); + internal static SoftwareBitmapSource LinkBitmapSource = new(); + internal static StockIcon SiError = new(Shell32.SHSTOCKICONID.SIID_ERROR); + internal static SoftwareBitmapSource ErrorBitmapSource = new(); -// public List StockIcons { get; init; } + public List StockIcons { get; init; } } \ No newline at end of file From 1bbc9d078c656dbaa813b8aa36731e007c89a37a Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sat, 16 Nov 2024 13:58:02 +0100 Subject: [PATCH 19/57] Refactor gui: Add some Prototypes --- src/electrifier/Views/WorkbenchPage.xaml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/electrifier/Views/WorkbenchPage.xaml b/src/electrifier/Views/WorkbenchPage.xaml index 8cb824e..670bb41 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml +++ b/src/electrifier/Views/WorkbenchPage.xaml @@ -22,30 +22,33 @@ Description="Your new Workbench is your personal workspace and data warehouse. You can have as many workbenches as you wish and can customize them here. It is your choice, what Page gets navigated to when electrifier starts the next time. Let This be my preferred choice for the future [x], as I know I can change this always in its ''Settings Page::startup behaviour''." Header="Tip of the day"> - - - + - - - + - + + + + + Always launch selection when I start this Workbench. + From a900c11db0e559037eddfed19caf4e531c2f07fa Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sat, 16 Nov 2024 15:06:51 +0100 Subject: [PATCH 20/57] Refactor `StockIcons` --- .../Controls/Vanara/Services/ShellNamespaceService.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs index 30246dd..7da8c6b 100644 --- a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs @@ -32,6 +32,7 @@ public List StockIcons init => new List(); } + protected ArrayWithOffset newStockIcons=new ArrayWithOffset(); /// A static reference of our own. /// When used as service, this static might be unnecessary. However, this @@ -49,8 +50,13 @@ public ShellNamespaceService() new(SHSTOCKICONID.SIID_DOCNOASSOC), new(SHSTOCKICONID.SIID_FOLDER), new(SHSTOCKICONID.SIID_FOLDERBACK), - new(SHSTOCKICONID.SIID_FOLDERFRONT) + new(SHSTOCKICONID.SIID_FOLDERFRONT), + new(SHSTOCKICONID.SIID_APPLICATION), + new(SHSTOCKICONID.SIID_AUDIOFILES), + new(SHSTOCKICONID.SIID_LINK), ]; + + newStockIcons = new(StockIcons, 1); } ///// Initialize default Stock Icons. From 95ce96fb1353db56fcdc01224550e24ef6584989 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sat, 16 Nov 2024 16:01:08 +0100 Subject: [PATCH 21/57] gui: Workbench --- .../Vanara/Services/ShellNamespaceService.cs | 3 ++- src/electrifier/Views/WorkbenchPage.xaml | 25 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs index 7da8c6b..6bab70f 100644 --- a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs @@ -56,7 +56,8 @@ public ShellNamespaceService() new(SHSTOCKICONID.SIID_LINK), ]; - newStockIcons = new(StockIcons, 1); + //newStockIcons = new(StockIcons, 1); + //StockIcons.Add(new(SHSTOCKICONID.SIID_LINK)); } ///// Initialize default Stock Icons. diff --git a/src/electrifier/Views/WorkbenchPage.xaml b/src/electrifier/Views/WorkbenchPage.xaml index 670bb41..bafd9c9 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml +++ b/src/electrifier/Views/WorkbenchPage.xaml @@ -23,14 +23,17 @@ Header="Tip of the day"> + + - + - - + + + - Always launch selection when I start this Workbench. - + + + + + + + + + Always launch last used Pages when I start this Workbench. From 7ed6008c65e2c38d10e22d69ca7770abc61ffff8 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sun, 17 Nov 2024 10:51:37 +0100 Subject: [PATCH 22/57] gui: Workbench --- src/electrifier/Views/WorkbenchPage.xaml | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/electrifier/Views/WorkbenchPage.xaml b/src/electrifier/Views/WorkbenchPage.xaml index bafd9c9..200e38d 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml +++ b/src/electrifier/Views/WorkbenchPage.xaml @@ -31,25 +31,23 @@ BorderThickness="3"> - - - - - - - + + Icon="Tag" /> + + - - + Icon="XboxOneConsole" /> + + From 4ca0ca14627eb352178aa8f45a6d02b9ef660837 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sun, 17 Nov 2024 13:17:33 +0100 Subject: [PATCH 23/57] Remove old, obsolete Stock Icons from Source --- .../Controls/Vanara/Contracts/AbstractBrowserItem.cs | 3 --- src/electrifier/Controls/Vanara/ShellListView.xaml | 2 +- src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs index c1e0a30..3a9e7f9 100644 --- a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs +++ b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs @@ -21,9 +21,6 @@ public abstract class AbstractBrowserItem(bool isFolder, List> ChildItems = childItems ?? []; - public SoftwareBitmapSource SoftwareBitmapSource = isFolder - ? IShellNamespaceService.FolderBitmapSource - : IShellNamespaceService.DocumentBitmapSource; // ShellNamespace.RequestStockIcon() // StockIcon = new(int ArrayIndex, BitmapSource) //internal void async IconUpdate(int Index, SoftwareBitmapSource bmpSrc); diff --git a/src/electrifier/Controls/Vanara/ShellListView.xaml b/src/electrifier/Controls/Vanara/ShellListView.xaml index 135719c..1fa0b61 100644 --- a/src/electrifier/Controls/Vanara/ShellListView.xaml +++ b/src/electrifier/Controls/Vanara/ShellListView.xaml @@ -16,7 +16,7 @@ - diff --git a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml index 1ec50a7..ac18cc2 100644 --- a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml +++ b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml @@ -18,7 +18,7 @@ Orientation="Horizontal"> Date: Sun, 17 Nov 2024 13:30:01 +0100 Subject: [PATCH 24/57] Remove `Expander` Controls --- .../Controls/Vanara/ExplorerBrowser.xaml | 30 ------------------- .../Vanara/Services/ShellNamespaceService.cs | 1 + 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml index f4b0cc4..7ec9b30 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml @@ -34,36 +34,6 @@ - - - - - - - - - - - - - - - - - - - - - - .KeyCollection //newStockIcons = new(StockIcons, 1); //StockIcons.Add(new(SHSTOCKICONID.SIID_LINK)); } From 779b8ae0cec6abcc2908990917a00bf4157a025a Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sun, 17 Nov 2024 15:04:09 +0100 Subject: [PATCH 25/57] gui: Workbench --- src/electrifier/Views/WorkbenchPage.xaml | 49 +++++++++++++++++------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/electrifier/Views/WorkbenchPage.xaml b/src/electrifier/Views/WorkbenchPage.xaml index 200e38d..6a95d5a 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml +++ b/src/electrifier/Views/WorkbenchPage.xaml @@ -31,17 +31,18 @@ BorderThickness="3"> - - + + Icon="GoToStart"> + + - - + - - - - - + HorizontalAlignment="Stretch"> + + + + + Shell + + + + + + Browser + + + + + + Editor + + + + + + Shell + + Always restore my Pages. - Always launch last used Pages when I start this Workbench. From eaed4c0afb01d594c0e683d6eb2aefac734dd890 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Mon, 18 Nov 2024 08:43:36 +0100 Subject: [PATCH 26/57] Refactor gui, especially AppBar and artifacts --- .../Controls/Vanara/ExplorerBrowser.xaml | 4 +- src/electrifier/Views/ShellPage.xaml | 38 +++++++++---------- src/electrifier/Views/WorkbenchPage.xaml | 5 --- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml index 7ec9b30..55af514 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml @@ -17,9 +17,7 @@ - - + diff --git a/src/electrifier/Views/ShellPage.xaml b/src/electrifier/Views/ShellPage.xaml index acf4b10..be4d416 100644 --- a/src/electrifier/Views/ShellPage.xaml +++ b/src/electrifier/Views/ShellPage.xaml @@ -2,11 +2,11 @@ todo: IsPaneToggleButtonVisible = True -> PaneToggle-Style and overlap todo: See WinUI3 gallery://item/AnimatedIcon --> @@ -41,31 +41,29 @@ - + BorderThickness="7" + Opacity="0.25"> - - - d'Oh! - - + + + d'oh diff --git a/src/electrifier/Views/WorkbenchPage.xaml b/src/electrifier/Views/WorkbenchPage.xaml index 6a95d5a..bdeebf5 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml +++ b/src/electrifier/Views/WorkbenchPage.xaml @@ -22,11 +22,6 @@ Description="Your new Workbench is your personal workspace and data warehouse. You can have as many workbenches as you wish and can customize them here. It is your choice, what Page gets navigated to when electrifier starts the next time. Let This be my preferred choice for the future [x], as I know I can change this always in its ''Settings Page::startup behaviour''." Header="Tip of the day"> - - - From fe2c82aafc3ef3c4ca8741bec0a9ccc77c353f10 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Tue, 19 Nov 2024 18:27:55 +0100 Subject: [PATCH 27/57] Add StockIconImages to `ShellListView` --- .../Contracts/IShellNamespaceService.cs | 24 ------- .../Controls/Vanara/ExplorerBrowser.xaml.cs | 63 +++++++++++++++---- .../Vanara/Services/ShellNamespaceService.cs | 28 --------- .../Controls/Vanara/ShellListView.xaml | 4 +- .../Vanara/ShellNamespaceTreeControl.xaml | 2 +- 5 files changed, 55 insertions(+), 66 deletions(-) diff --git a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs index 7decd69..bf61f8d 100644 --- a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs @@ -16,29 +16,5 @@ public interface IShellNamespaceService /// This equals Shell 32 URI: shell:::{679f85cb-0220-4080-b29b-5540cc05aab6} public static ShellFolder HomeShellFolder => new("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}"); - /// - /// todo: die ganzen StockIcons in ein struct packen. - /// Indexer ist `Shell32.SHSTOCKICONID` - /// get-Methode, die erst die Icons holt wenn danach gefragt wird. - /// - internal static StockIcon SiDocument = new(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC); - internal static SoftwareBitmapSource DocumentBitmapSource = new(); - internal static StockIcon SiDocumentWithAssociation = new(Shell32.SHSTOCKICONID.SIID_DOCASSOC); - internal static SoftwareBitmapSource DocumentWithAssociationBitmapSource = new(); - internal static StockIcon SiFolder = new(Shell32.SHSTOCKICONID.SIID_FOLDER); - internal static SoftwareBitmapSource FolderBitmapSource = new(); - //internal static StockIcon SiLibrary = new(Shell32.SHSTOCKICONID.SIID_LINK); - internal static SoftwareBitmapSource LibraryFrontBitmapSource = new(); - internal static StockIcon SiFolderBack = new(Shell32.SHSTOCKICONID.SIID_FOLDERBACK); - internal static SoftwareBitmapSource FolderBackBitmapSource = new(); - internal static StockIcon SiFolderFront = new(Shell32.SHSTOCKICONID.SIID_FOLDERFRONT); - internal static SoftwareBitmapSource FolderFrontBitmapSource = new(); - internal static StockIcon SiFolderOpen = new(Shell32.SHSTOCKICONID.SIID_FOLDEROPEN); - internal static SoftwareBitmapSource FolderOpenBitmapSource = new(); - internal static StockIcon SiLinkOverlay = new(Shell32.SHSTOCKICONID.SIID_LINK); - internal static SoftwareBitmapSource LinkBitmapSource = new(); - internal static StockIcon SiError = new(Shell32.SHSTOCKICONID.SIID_ERROR); - internal static SoftwareBitmapSource ErrorBitmapSource = new(); - public List StockIcons { get; init; } } \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs index 4e20d94..8d3bfcd 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs @@ -20,6 +20,9 @@ using electrifier.Controls.Vanara.Contracts; using Vanara.PInvoke; using Vanara.Windows.Shell; + +using static Vanara.PInvoke.Shell32; + namespace electrifier.Controls.Vanara; using Visibility = Microsoft.UI.Xaml.Visibility; // https://github.com/dahall/Vanara/blob/master/Windows.Forms/Controls/ExplorerBrowser.cs @@ -46,12 +49,15 @@ public bool IsLoading public static ShellNamespaceService ShellNamespaceService => App.GetService(); + protected static Dictionary StockIconDictionary; + /// ExplorerBrowser Implementation for WinUI3. public ExplorerBrowser() { InitializeComponent(); DataContext = this; + StockIconDictionary = new(); ShellTreeView.NativeTreeView.SelectionChanged += NativeTreeView_SelectionChanged; using var shHome = ShellNamespaceService.HomeShellFolder; @@ -70,11 +76,19 @@ public async void Navigate(BrowserItem target) ShellListView.Items.Clear(); foreach (var child in shFolder) { + var ebItem = new BrowserItem(child.PIDL, child.IsFolder); + if (child.IsFolder) - target.ChildItems.Add(new BrowserItem(child.PIDL, true)); - ShellListView.Items.Add(new BrowserItem(child.PIDL, child.IsFolder)); + { + ebItem.SoftwareBitmap = await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER); + } + else + { + ebItem.SoftwareBitmap = await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC); + } + + ShellListView.Items.Add(ebItem); } - } catch (COMException comEx) { @@ -93,6 +107,40 @@ public async void Navigate(BrowserItem target) } } + public async Task GetStockIconBitmapSource(Shell32.SHSTOCKICONID shStockIconId) + { + try + { + if (StockIconDictionary.TryGetValue(shStockIconId, out var source)) + { + return source; + } + + var siFlags = Shell32.SHGSI.SHGSI_LARGEICON | Shell32.SHGSI.SHGSI_ICON; + var icninfo = Shell32.SHSTOCKICONINFO.Default; + SHGetStockIconInfo(shStockIconId, siFlags, ref icninfo).ThrowIfFailed($"SHGetStockIconInfo({shStockIconId})"); + + var hIcon = icninfo.hIcon; + var icnHandle = hIcon.ToIcon(); + var bmpSource = ShellNamespaceService.GetWinUi3BitmapSourceFromIcon(icnHandle); + await bmpSource; + var softBitmap = bmpSource.Result; + + if (softBitmap != null) + { + _ = StockIconDictionary.TryAdd(shStockIconId, softBitmap); + return softBitmap; + } + + throw new ArgumentOutOfRangeException($"Can't get StockIcon for SHSTOCKICONID: {shStockIconId.ToString()}"); + } + catch (Exception e) + { + throw; // TODO handle exception + } + } + + public async void Navigate(ShellItem target, TreeViewNode? treeViewNode = null) { // TODO: Search for best matching RootItem in the tree hierarchy @@ -149,20 +197,13 @@ public class BrowserItem(Shell32.PIDL pidl, bool isFolder, List new(shellFolder.PIDL, true); public static BrowserItem FromKnownFolderId(Shell32.KNOWNFOLDERID knownItemId) => new(new ShellFolder(knownItemId).PIDL, true); + public SoftwareBitmapSource? SoftwareBitmap ; - //public Task Enumerate() - //{ - // ChildItems.Add(BrowserItem.FromKnownItemId(Shell32.KNOWNFOLDERID.FOLDERID_AddNewPrograms)); - // ChildItems.Add(BrowserItem.FromKnownItemId(Shell32.KNOWNFOLDERID.FOLDERID_AddNewPrograms)); - // return Task.CompletedTask as Task; - //} public event PropertyChangedEventHandler? PropertyChanged; - protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; diff --git a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs index f09c893..2e9ad18 100644 --- a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs @@ -9,7 +9,6 @@ using JetBrains.Annotations; using electrifier.Controls.Vanara.Contracts; using System.Collections; -using CommunityToolkit.Mvvm.ComponentModel.__Internals; using Microsoft.UI.Xaml.Controls; namespace electrifier.Controls.Vanara.Services; @@ -26,39 +25,12 @@ public partial class ShellNamespaceService : IShellNamespaceService public static IReadOnlyList IconExtractorBitmaps => IconExtractor.ImageList; public int IconSize => IconExtractor.ImageSize; - public List StockIcons - { - get => []; - init => new List(); - } - - protected ArrayWithOffset newStockIcons=new ArrayWithOffset(); - /// A static reference of our own. - /// When used as service, this static might be unnecessary. However, this - /// makes sure the Stock Icon cache gets initialized as soon as possible. - /// TODO: This is a currently unresolved race condition - /// - [UsedImplicitly] public static ShellNamespaceService Instance = new(); /// ShellNamespaceService() Warn: Actually does not really conform Service Models. public ShellNamespaceService() { - StockIcons = - [ - new(SHSTOCKICONID.SIID_DOCASSOC), - new(SHSTOCKICONID.SIID_DOCNOASSOC), - new(SHSTOCKICONID.SIID_FOLDER), - new(SHSTOCKICONID.SIID_FOLDERBACK), - new(SHSTOCKICONID.SIID_FOLDERFRONT), - new(SHSTOCKICONID.SIID_APPLICATION), - new(SHSTOCKICONID.SIID_AUDIOFILES), - new(SHSTOCKICONID.SIID_LINK), - ]; -// var dict = new Dictionary.KeyCollection - //newStockIcons = new(StockIcons, 1); - //StockIcons.Add(new(SHSTOCKICONID.SIID_LINK)); } ///// Initialize default Stock Icons. diff --git a/src/electrifier/Controls/Vanara/ShellListView.xaml b/src/electrifier/Controls/Vanara/ShellListView.xaml index 1fa0b61..679f1ed 100644 --- a/src/electrifier/Controls/Vanara/ShellListView.xaml +++ b/src/electrifier/Controls/Vanara/ShellListView.xaml @@ -16,9 +16,9 @@ - diff --git a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml index ac18cc2..d489848 100644 --- a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml +++ b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml @@ -18,7 +18,7 @@ Orientation="Horizontal"> Date: Wed, 20 Nov 2024 22:16:02 +0100 Subject: [PATCH 28/57] Fix Navigation via `ShellNamespaceTreeControl` --- .../Controls/Vanara/ExplorerBrowser.xaml.cs | 48 ++++++++++--------- .../Vanara/ShellNamespaceTreeControl.xaml.cs | 2 +- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs index 8d3bfcd..bb277fa 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs @@ -49,7 +49,7 @@ public bool IsLoading public static ShellNamespaceService ShellNamespaceService => App.GetService(); - protected static Dictionary StockIconDictionary; + private readonly Dictionary _stockIconDictionary = []; /// ExplorerBrowser Implementation for WinUI3. public ExplorerBrowser() @@ -57,42 +57,40 @@ public ExplorerBrowser() InitializeComponent(); DataContext = this; - StockIconDictionary = new(); ShellTreeView.NativeTreeView.SelectionChanged += NativeTreeView_SelectionChanged; using var shHome = ShellNamespaceService.HomeShellFolder; - Navigate(new BrowserItem(shHome.PIDL, true)); + //Navigate(new BrowserItem(shHome.PIDL, true)); // TODO: Navigate to TreeViewItem! } + // TODO: @dahall: Maybe we should throw HRESULT-COM-Errors at least here? Your HRESULT.ThrowIfFailed() - Pattern? public async void Navigate(BrowserItem target) { - Debug.WriteLineIf(!target.IsFolder, $"Navigate({target.DisplayName}) => `{{target.DisplayName}}` is not a folder!"); + Debug.WriteLineIf(!target.IsFolder, $"Navigate({target.DisplayName}) => is not a folder!"); try { IsLoading = true; using var shFolder = new ShellFolder(target.ShellItem); + target.ChildItems.Clear(); ShellListView.Items.Clear(); foreach (var child in shFolder) { - var ebItem = new BrowserItem(child.PIDL, child.IsFolder); - - if (child.IsFolder) - { - ebItem.SoftwareBitmap = await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER); - } - else + var ebItem = new BrowserItem(child.PIDL, child.IsFolder) { - ebItem.SoftwareBitmap = await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC); - } + SoftwareBitmap = child.IsFolder + ? await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER) + : await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC) + }; + target.ChildItems.Add(ebItem); ShellListView.Items.Add(ebItem); } } catch (COMException comEx) { - Debug.Fail($"[Error] Navigate(<{target}>) failed. COMException: : `{comEx.Message}`"); + Debug.Fail($"[Error] Navigate(<{target}>) failed. COMException: : `{comEx.Message}`"); throw; } catch (Exception ex) @@ -103,7 +101,6 @@ public async void Navigate(BrowserItem target) finally { IsLoading = false; - //_ = UpdateGridView(); } } @@ -111,7 +108,7 @@ public async Task GetStockIconBitmapSource(Shell32.SHSTOCK { try { - if (StockIconDictionary.TryGetValue(shStockIconId, out var source)) + if (_stockIconDictionary.TryGetValue(shStockIconId, out var source)) { return source; } @@ -128,7 +125,7 @@ public async Task GetStockIconBitmapSource(Shell32.SHSTOCK if (softBitmap != null) { - _ = StockIconDictionary.TryAdd(shStockIconId, softBitmap); + _ = _stockIconDictionary.TryAdd(shStockIconId, softBitmap); return softBitmap; } @@ -150,19 +147,24 @@ private void NativeTreeView_SelectionChanged(TreeView sender, TreeViewSelectionC { Debug.Print($".NativeTreeView_SelectionChanged(): Updating `ShellListView` items..."); - ShellListView.Items.Clear(); - var addedItems = args.AddedItems; if (addedItems.Count > 0) { + Debug.Assert(addedItems.Count == 1); + var folder = addedItems[0] as BrowserItem; + var currentTreeNode = ShellTreeView.NativeTreeView.SelectedItem; - foreach (var childItem in folder.ChildItems) + if (currentTreeNode is BrowserItem browserItem) { - ShellListView.Items.Add(BrowserItem.FromPIDL(childItem.PIDL)); + Debug.Print("Ätsch! TreeItem already selected"); } - Navigate(folder); + Debug.Print($".NativeTreeView_SelectionChanged(): {folder?.ToString()} - {currentTreeNode?.ToString()}"); + if (folder != null) + { + Navigate(folder); + } } } #region Property stuff @@ -197,7 +199,7 @@ public class BrowserItem(Shell32.PIDL pidl, bool isFolder, List new(shellFolder.PIDL, true); public static BrowserItem FromKnownFolderId(Shell32.KNOWNFOLDERID knownItemId) => new(new ShellFolder(knownItemId).PIDL, true); - public SoftwareBitmapSource? SoftwareBitmap ; + public SoftwareBitmapSource? SoftwareBitmap; public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) diff --git a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs index eff9c67..ad57304 100644 --- a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs +++ b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs @@ -29,9 +29,9 @@ public ShellNamespaceTreeControl() DataContext = this; TreeItems = new ObservableCollection(); AdvancedCollectionView = new AdvancedCollectionView(TreeItems, true); + NativeTreeView.ItemsSource = AdvancedCollectionView; Loading += ShellNamespaceTreeControl_Loading; - NativeTreeView.ItemsSource = AdvancedCollectionView; } private void ShellNamespaceTreeControl_Loading(FrameworkElement sender, object args) From 7cec48d76b486b82ff02d19cb8c6eeb0f7c83fb8 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Fri, 22 Nov 2024 14:06:39 +0100 Subject: [PATCH 29/57] Refactor debug stuff of `NativeTreeView_SelectionChanged()` --- .../Controls/Vanara/ExplorerBrowser.xaml.cs | 33 +++++++++++-------- .../Controls/Vanara/ShellListView.xaml | 7 ++++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs index bb277fa..5727c08 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs @@ -131,7 +131,7 @@ public async Task GetStockIconBitmapSource(Shell32.SHSTOCK throw new ArgumentOutOfRangeException($"Can't get StockIcon for SHSTOCKICONID: {shStockIconId.ToString()}"); } - catch (Exception e) + catch (Exception) { throw; // TODO handle exception } @@ -145,25 +145,31 @@ public async void Navigate(ShellItem target, TreeViewNode? treeViewNode = null) private void NativeTreeView_SelectionChanged(TreeView sender, TreeViewSelectionChangedEventArgs args) { - Debug.Print($".NativeTreeView_SelectionChanged(): Updating `ShellListView` items..."); - var addedItems = args.AddedItems; if (addedItems.Count > 0) { Debug.Assert(addedItems.Count == 1); - - var folder = addedItems[0] as BrowserItem; + var selectedFolder = addedItems[0] as BrowserItem; var currentTreeNode = ShellTreeView.NativeTreeView.SelectedItem; + Debug.Print($".NativeTreeView_SelectionChanged(`{selectedFolder?.DisplayName}`, treeNode: {currentTreeNode?.ToString()}"); - if (currentTreeNode is BrowserItem browserItem) + if (currentTreeNode is BrowserItem browserItem && browserItem.PIDL.Equals(selectedFolder?.PIDL)) { - Debug.Print("Ätsch! TreeItem already selected"); + Debug.Print(".NativeTreeView_SelectionChanged(): CurrentTreeNode already equals selected /added Item."); } - - Debug.Print($".NativeTreeView_SelectionChanged(): {folder?.ToString()} - {currentTreeNode?.ToString()}"); - if (folder != null) + else { - Navigate(folder); + // TODO: ShellTreeView.NativeTreeView.SelectedItem = newTreeNode(find TreeNode + + if (selectedFolder?.PIDL is null) + { + Debug.Print(".NativeTreeView_SelectionChanged(): selectedFolder is null!"); + + return; + } + + Navigate(selectedFolder); + //Navigate(selectedFolder.ShellItem, currentTreeNode as TreeViewNode); } } } @@ -187,7 +193,7 @@ private bool SetField(ref T field, T value, [CallerMemberName] string? proper #endregion Property stuff } - +[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] public class BrowserItem(Shell32.PIDL pidl, bool isFolder, List>? childItems = default) : AbstractBrowserItem(isFolder, childItems), INotifyPropertyChanged { @@ -214,8 +220,7 @@ protected bool SetField(ref T field, T value, [CallerMemberName] string? prop return true; } } - - +[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] public partial class BrowserItemCollection : List, IList { protected IList ListImplementation => new List(); diff --git a/src/electrifier/Controls/Vanara/ShellListView.xaml b/src/electrifier/Controls/Vanara/ShellListView.xaml index 679f1ed..dd180c4 100644 --- a/src/electrifier/Controls/Vanara/ShellListView.xaml +++ b/src/electrifier/Controls/Vanara/ShellListView.xaml @@ -29,5 +29,12 @@ + + + This is bender in da house + + From 720431dec3181ec444b7ae77c9279287a10360a1 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Fri, 22 Nov 2024 14:54:17 +0100 Subject: [PATCH 30/57] Add `BrowserItemFactory` --- .../Controls/Vanara/Helpers/BrowserItemFactory.cs | 10 ++++++++++ src/electrifier/electrifier.csproj | 3 --- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs diff --git a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs new file mode 100644 index 0000000..ad7a4ce --- /dev/null +++ b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace electrifier.Controls.Vanara.Helpers; +internal class BrowserItemFactory +{ +} diff --git a/src/electrifier/electrifier.csproj b/src/electrifier/electrifier.csproj index 2e57578..aa400b1 100644 --- a/src/electrifier/electrifier.csproj +++ b/src/electrifier/electrifier.csproj @@ -161,9 +161,6 @@ Resources.Designer.cs - - - true From 527c3d750890b5d134f4e649901d6e49858cdbaa Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Mon, 25 Nov 2024 18:48:20 +0100 Subject: [PATCH 31/57] prj: Add `.clang-format` styles --- src/electrifier 2024.clang-format | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/electrifier 2024.clang-format diff --git a/src/electrifier 2024.clang-format b/src/electrifier 2024.clang-format new file mode 100644 index 0000000..74a959a --- /dev/null +++ b/src/electrifier 2024.clang-format @@ -0,0 +1,54 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: false +AlignTrailingComments: false +AlwaysBreakTemplateDeclarations: Yes +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBraces: Custom +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseBlocks: true +IndentWidth: 4 +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +PointerAlignment: Left +SpaceInEmptyParentheses: false +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +TabWidth: 4 +... From 5508d1b29d4c8ebe7a2c7aeb8ac19a0f5235c771 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Tue, 26 Nov 2024 13:15:58 +0100 Subject: [PATCH 32/57] Refactor --- .../Vanara/Contracts/AbstractBrowserItem.cs | 54 +---------- .../Contracts/IShellNamespaceService.cs | 2 - .../Controls/Vanara/ExplorerBrowser.xaml.cs | 86 ++++-------------- .../Vanara/Helpers/BrowserItemFactory.cs | 89 +++++++++++++++++-- .../Vanara/Services/ShellNamespaceService.cs | 3 - .../Controls/Vanara/ShellBreadcrumbBar.xaml | 3 +- .../Vanara/ShellBreadcrumbBar.xaml.cs | 1 + .../Controls/Vanara/ShellContextMenu.cs | 5 +- .../Controls/Vanara/ShellListView.xaml | 3 +- .../Controls/Vanara/ShellListView.xaml.cs | 9 +- .../Vanara/ShellNamespaceTreeControl.xaml | 3 +- .../Vanara/ShellNamespaceTreeControl.xaml.cs | 6 +- src/electrifier/Views/WorkbenchPage.xaml.cs | 3 +- 13 files changed, 113 insertions(+), 154 deletions(-) diff --git a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs index 3a9e7f9..5f28270 100644 --- a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs +++ b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs @@ -1,53 +1 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using electrifier.Controls.Vanara.Services; -using Microsoft.UI.Xaml.Media.Imaging; -using System.Collections.Generic; -using System.Collections; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using System; -using Vanara.PInvoke; -using Vanara.Windows.Shell; -using static Vanara.PInvoke.ComCtl32; -using static Vanara.PInvoke.Shell32; - -namespace electrifier.Controls.Vanara.Contracts; - -[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public abstract class AbstractBrowserItem(bool isFolder, List>? childItems) -{ - public readonly bool IsFolder = isFolder; // WARN: TODO: Check this. If unknown, then find it out! ... edit: or use virtual function for this! - public readonly List> ChildItems = childItems ?? []; - // ShellNamespace.RequestStockIcon() - // StockIcon = new(int ArrayIndex, BitmapSource) - //internal void async IconUpdate(int Index, SoftwareBitmapSource bmpSrc); - //internal void async StockIconUpdate(STOCKICONID id, SoftwareBitmapSource bmpSrc); - //internal void async ChildItemsIconUpdate(); - public new string ToString() => $"AbstractBrowserItem(<{typeof(T)}>(isFolder {isFolder}, childItems {childItems})"; -} - -[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public abstract class AbstractBrowserItemCollection : IEnumerable>, IList> -{ - //protected readonly ShellItem? _parentOwnerItem; - protected readonly IList> Collection = []; - - AbstractBrowserItem IList>.this[int index] { get => Collection[index]; set => Collection[index] = value; } - int ICollection>.Count => Collection.Count; - bool ICollection>.IsReadOnly => false; - void ICollection>.Add(AbstractBrowserItem item) => Collection.Add(item); - void ICollection>.Clear() => Collection.Clear(); - bool ICollection>.Contains(AbstractBrowserItem item) => Collection.Contains(item); - void ICollection>.CopyTo(AbstractBrowserItem[] array, int arrayIndex) => Collection.CopyTo(array, arrayIndex); - IEnumerator> IEnumerable>.GetEnumerator() => Collection.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => Collection.GetEnumerator(); - int IList>.IndexOf(AbstractBrowserItem item) => Collection.IndexOf(item); - void IList>.Insert(int index, AbstractBrowserItem item) => Collection.Insert(index, item); - bool ICollection>.Remove(AbstractBrowserItem item) => Collection.Remove(item); - void IList>.RemoveAt(int index) => Collection.RemoveAt(index); - - public new string ToString() => $"AbstractBrowserItemCollection(<{typeof(T)}>(number of child items: {Collection.Count})"; -} + \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs index bf61f8d..99bf25e 100644 --- a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs @@ -1,6 +1,4 @@ using System.Runtime.InteropServices; -using electrifier.Controls.Vanara.Services; -using Microsoft.UI.Xaml.Media.Imaging; using Vanara.PInvoke; using Vanara.Windows.Shell; diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs index 5727c08..f227839 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs @@ -1,35 +1,25 @@ /* todo: Use Visual States for Errors, Empty folders, Empty Drives */ -using System.Collections; -using CommunityToolkit.Mvvm.Input; -using CommunityToolkit.WinUI.Collections; using electrifier.Controls.Vanara.Services; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media.Imaging; -using Microsoft.UI.Xaml; -using System.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel; -using System.Data; using System.Diagnostics; -using System.Drawing; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices.WindowsRuntime; using System.Runtime.InteropServices; -using System.Windows.Input; -using electrifier.Controls.Vanara.Contracts; +using electrifier.Controls.Vanara.Helpers; using Vanara.PInvoke; using Vanara.Windows.Shell; - using static Vanara.PInvoke.Shell32; namespace electrifier.Controls.Vanara; -using Visibility = Microsoft.UI.Xaml.Visibility; + // https://github.com/dahall/Vanara/blob/master/Windows.Forms/Controls/ExplorerBrowser.cs /// Replacement for Windows.Forms/Controls/ExplorerBrowser.cs public sealed partial class ExplorerBrowser : INotifyPropertyChanged { private bool _isLoading; + public bool IsLoading { get => _isLoading; @@ -44,6 +34,7 @@ public bool IsLoading OnPropertyChanged(); } } + public event EventHandler Navigated; public event EventHandler NavigationFailed; @@ -80,8 +71,8 @@ public async void Navigate(BrowserItem target) var ebItem = new BrowserItem(child.PIDL, child.IsFolder) { SoftwareBitmap = child.IsFolder - ? await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER) - : await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC) + ? await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER) + : await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC) }; target.ChildItems.Add(ebItem); @@ -90,7 +81,8 @@ public async void Navigate(BrowserItem target) } catch (COMException comEx) { - Debug.Fail($"[Error] Navigate(<{target}>) failed. COMException: : `{comEx.Message}`"); + Debug.Fail( + $"[Error] Navigate(<{target}>) failed. COMException: : `{comEx.Message}`"); throw; } catch (Exception ex) @@ -115,7 +107,8 @@ public async Task GetStockIconBitmapSource(Shell32.SHSTOCK var siFlags = Shell32.SHGSI.SHGSI_LARGEICON | Shell32.SHGSI.SHGSI_ICON; var icninfo = Shell32.SHSTOCKICONINFO.Default; - SHGetStockIconInfo(shStockIconId, siFlags, ref icninfo).ThrowIfFailed($"SHGetStockIconInfo({shStockIconId})"); + SHGetStockIconInfo(shStockIconId, siFlags, ref icninfo) + .ThrowIfFailed($"SHGetStockIconInfo({shStockIconId})"); var hIcon = icninfo.hIcon; var icnHandle = hIcon.ToIcon(); @@ -151,7 +144,8 @@ private void NativeTreeView_SelectionChanged(TreeView sender, TreeViewSelectionC Debug.Assert(addedItems.Count == 1); var selectedFolder = addedItems[0] as BrowserItem; var currentTreeNode = ShellTreeView.NativeTreeView.SelectedItem; - Debug.Print($".NativeTreeView_SelectionChanged(`{selectedFolder?.DisplayName}`, treeNode: {currentTreeNode?.ToString()}"); + Debug.Print( + $".NativeTreeView_SelectionChanged(`{selectedFolder?.DisplayName}`, treeNode: {currentTreeNode?.ToString()}"); if (currentTreeNode is BrowserItem browserItem && browserItem.PIDL.Equals(selectedFolder?.PIDL)) { @@ -173,12 +167,16 @@ private void NativeTreeView_SelectionChanged(TreeView sender, TreeViewSelectionC } } } + #region Property stuff + private void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } + public event PropertyChangedEventHandler? PropertyChanged; + private bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) @@ -190,57 +188,7 @@ private bool SetField(ref T field, T value, [CallerMemberName] string? proper OnPropertyChanged(propertyName); return true; } + #endregion Property stuff } -[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public class BrowserItem(Shell32.PIDL pidl, bool isFolder, List>? childItems = default) - : AbstractBrowserItem(isFolder, childItems), INotifyPropertyChanged -{ - public readonly Shell32.PIDL PIDL = new(pidl); - public string DisplayName => ShellItem.GetDisplayName(ShellItemDisplayString.NormalDisplay) ?? ShellItem.ToString(); - public ShellItem ShellItem = new(pidl); - public new ObservableCollection ChildItems = []; - public static BrowserItem FromPIDL(Shell32.PIDL pidl) => new(pidl, false); - public static BrowserItem FromShellFolder(ShellFolder shellFolder) => new(shellFolder.PIDL, true); - public static BrowserItem FromKnownFolderId(Shell32.KNOWNFOLDERID knownItemId) => new(new ShellFolder(knownItemId).PIDL, true); - - public SoftwareBitmapSource? SoftwareBitmap; - - public event PropertyChangedEventHandler? PropertyChanged; - protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) - { - if (EqualityComparer.Default.Equals(field, value)) return false; - field = value; - OnPropertyChanged(propertyName); - return true; - } -} -[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public partial class BrowserItemCollection : List, IList -{ - protected IList ListImplementation => new List(); - - public void CopyTo(Array array, int index) => ListImplementation.CopyTo(array, index); - public new int Count => ListImplementation.Count; - public bool IsSynchronized => ListImplementation.IsSynchronized; - public object SyncRoot => ListImplementation.SyncRoot; - public int Add(object? value) => ListImplementation.Add(value); - public new void Clear() => ListImplementation.Clear(); - public bool Contains(object? value) => ListImplementation.Contains(value); - public int IndexOf(object? value) => ListImplementation.IndexOf(value); - public void Insert(int index, object? value) => ListImplementation.Insert(index, value); - public void Remove(object? value) => ListImplementation.Remove(value); - public new void RemoveAt(int index) => ListImplementation.RemoveAt(index); - public bool IsFixedSize => ListImplementation.IsFixedSize; - public bool IsReadOnly => ListImplementation.IsReadOnly; - public new object? this[int index] - { - get => ListImplementation[index]; - set => ListImplementation[index] = value; - } -} diff --git a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs index ad7a4ce..4e9b3f7 100644 --- a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs +++ b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs @@ -1,10 +1,87 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using electrifier.Controls.Vanara.Contracts; +using Microsoft.UI.Xaml.Media.Imaging; +using Vanara.PInvoke; +using Vanara.Windows.Shell; namespace electrifier.Controls.Vanara.Helpers; -internal class BrowserItemFactory + +internal class BrowserItemFactory; + +[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] +public abstract class AbstractBrowserItem(bool isFolder, List>? childItems) +{ + public readonly bool + IsFolder = isFolder; // WARN: TODO: Check this. If unknown, then find it out! ... edit: or use virtual function for this! + + public readonly List> ChildItems = childItems ?? []; + + // ShellNamespace.RequestStockIcon() + // StockIcon = new(int ArrayIndex, BitmapSource) + //internal void async IconUpdate(int Index, SoftwareBitmapSource bmpSrc); + //internal void async StockIconUpdate(STOCKICONID id, SoftwareBitmapSource bmpSrc); + //internal void async ChildItemsIconUpdate(); + public new string ToString() => $"AbstractBrowserItem(<{typeof(T)}>(isFolder {isFolder}, childItems {childItems})"; +} + +[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] +public class BrowserItem(Shell32.PIDL pidl, bool isFolder, List>? childItems = default) + : AbstractBrowserItem(isFolder, childItems), INotifyPropertyChanged { + public readonly Shell32.PIDL PIDL = new(pidl); + public string DisplayName => ShellItem.GetDisplayName(ShellItemDisplayString.NormalDisplay) ?? ShellItem.ToString(); + public ShellItem ShellItem = new(pidl); + public new ObservableCollection ChildItems = []; + public static BrowserItem FromPIDL(Shell32.PIDL pidl) => new(pidl, false); + public static BrowserItem FromShellFolder(ShellFolder shellFolder) => new(shellFolder.PIDL, true); + + public static BrowserItem FromKnownFolderId(Shell32.KNOWNFOLDERID knownItemId) => + new(new ShellFolder(knownItemId).PIDL, true); + + public SoftwareBitmapSource? SoftwareBitmap; + + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + OnPropertyChanged(propertyName); + return true; + } } + +[DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] +public partial class BrowserItemCollection : List, IList +{ + protected IList ListImplementation => new List(); + + public void CopyTo(Array array, int index) => ListImplementation.CopyTo(array, index); + public new int Count => ListImplementation.Count; + public bool IsSynchronized => ListImplementation.IsSynchronized; + public object SyncRoot => ListImplementation.SyncRoot; + public int Add(object? value) => ListImplementation.Add(value); + public new void Clear() => ListImplementation.Clear(); + public bool Contains(object? value) => ListImplementation.Contains(value); + public int IndexOf(object? value) => ListImplementation.IndexOf(value); + public void Insert(int index, object? value) => ListImplementation.Insert(index, value); + public void Remove(object? value) => ListImplementation.Remove(value); + public new void RemoveAt(int index) => ListImplementation.RemoveAt(index); + public bool IsFixedSize => ListImplementation.IsFixedSize; + public bool IsReadOnly => ListImplementation.IsReadOnly; + + public new object? this[int index] + { + get => ListImplementation[index]; + set => ListImplementation[index] = value; + } +} \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs index 2e9ad18..b1c27c6 100644 --- a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs @@ -6,10 +6,7 @@ using System.Diagnostics; using static Vanara.PInvoke.Shell32; using Microsoft.UI.Xaml.Media.Imaging; -using JetBrains.Annotations; using electrifier.Controls.Vanara.Contracts; -using System.Collections; -using Microsoft.UI.Xaml.Controls; namespace electrifier.Controls.Vanara.Services; diff --git a/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml b/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml index 7a53a35..6f9702c 100644 --- a/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml +++ b/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml @@ -6,13 +6,14 @@ xmlns:local="using:electrifier.Controls.Vanara" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:shell="using:Vanara.Windows.Shell" + xmlns:helpers="using:electrifier.Controls.Vanara.Helpers" mc:Ignorable="d"> - + diff --git a/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml.cs b/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml.cs index a244994..71fb16a 100644 --- a/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml.cs +++ b/src/electrifier/Controls/Vanara/ShellBreadcrumbBar.xaml.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using electrifier.Controls.Vanara.Helpers; using Microsoft.UI.Xaml.Controls; namespace electrifier.Controls.Vanara; public sealed partial class ShellBreadcrumbBar : UserControl diff --git a/src/electrifier/Controls/Vanara/ShellContextMenu.cs b/src/electrifier/Controls/Vanara/ShellContextMenu.cs index 6effc9d..3faf5bb 100644 --- a/src/electrifier/Controls/Vanara/ShellContextMenu.cs +++ b/src/electrifier/Controls/Vanara/ShellContextMenu.cs @@ -1,6 +1,3 @@ namespace electrifier.Controls.Vanara; -public class ShellContextMenu -{ - -} \ No newline at end of file +public class ShellContextMenu; \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/ShellListView.xaml b/src/electrifier/Controls/Vanara/ShellListView.xaml index dd180c4..8420715 100644 --- a/src/electrifier/Controls/Vanara/ShellListView.xaml +++ b/src/electrifier/Controls/Vanara/ShellListView.xaml @@ -6,12 +6,13 @@ xmlns:local="using:electrifier.Controls.Vanara" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:services="using:electrifier.Controls.Vanara.Services" + xmlns:helpers="using:electrifier.Controls.Vanara.Helpers" d:DataContext="{d:DesignInstance Type=local:ExplorerBrowser}" mc:Ignorable="d"> + x:DataType="helpers:BrowserItem"> + x:DataType="helpers:BrowserItem"> Date: Tue, 26 Nov 2024 20:39:55 +0100 Subject: [PATCH 33/57] prj: Delete obsolete file `AbstractBrowserItem.cs` --- src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs diff --git a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs b/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs deleted file mode 100644 index 5f28270..0000000 --- a/src/electrifier/Controls/Vanara/Contracts/AbstractBrowserItem.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From c247e58c8eb56936cbd8c025a5633736eb179bee Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Wed, 27 Nov 2024 09:52:36 +0100 Subject: [PATCH 34/57] Refactoring --- .../Vanara/Helpers/BrowserItemFactory.cs | 66 ++++++++++--------- .../Vanara/Services/ShellNamespaceService.cs | 6 ++ .../Vanara/ShellNamespaceTreeControl.xaml.cs | 16 ++--- src/electrifier/Views/WorkbenchPage.xaml.cs | 2 +- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs index 4e9b3f7..c4a7763 100644 --- a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs +++ b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs @@ -1,27 +1,38 @@ -using System.Collections; +using electrifier.Controls.Vanara.Contracts; +using Microsoft.UI.Xaml.Media.Imaging; +using static Vanara.PInvoke.Shell32; using System.Collections.ObjectModel; +using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; -using electrifier.Controls.Vanara.Contracts; -using Microsoft.UI.Xaml.Media.Imaging; using Vanara.PInvoke; using Vanara.Windows.Shell; namespace electrifier.Controls.Vanara.Helpers; -internal class BrowserItemFactory; +public class BrowserItemFactory +{ + public static BrowserItem FromPIDL(Shell32.PIDL pidl) => new(pidl, isFolder: null); + public static BrowserItem FromShellFolder(ShellFolder shellFolder) => new(shellFolder.PIDL, true); + public static BrowserItem FromKnownFolderId(Shell32.KNOWNFOLDERID knownItemId) => + new(new ShellFolder(knownItemId).PIDL, true); +} + +/// Abstract base class BrowserItem of Type . +/// The derived Type of this abstract class. +/// +/// true +/// Default: False. +/// Default: Create new empty List of child items childItems. [DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public abstract class AbstractBrowserItem(bool isFolder, List>? childItems) +public abstract class + AbstractBrowserItem(bool? isFolder, List>? childItems) // TODO: IDisposable { - public readonly bool - IsFolder = isFolder; // WARN: TODO: Check this. If unknown, then find it out! ... edit: or use virtual function for this! - public readonly List> ChildItems = childItems ?? []; + public readonly bool IsFolder = isFolder ?? false; - // ShellNamespace.RequestStockIcon() - // StockIcon = new(int ArrayIndex, BitmapSource) //internal void async IconUpdate(int Index, SoftwareBitmapSource bmpSrc); //internal void async StockIconUpdate(STOCKICONID id, SoftwareBitmapSource bmpSrc); //internal void async ChildItemsIconUpdate(); @@ -29,31 +40,30 @@ public readonly bool } [DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public class BrowserItem(Shell32.PIDL pidl, bool isFolder, List>? childItems = default) - : AbstractBrowserItem(isFolder, childItems), INotifyPropertyChanged +public partial class BrowserItem( + Shell32.PIDL pidl, + bool? isFolder, + List>? childItems = default) + : AbstractBrowserItem(isFolder, childItems ?? []), INotifyPropertyChanged // TODO: IDisposable { - public readonly Shell32.PIDL PIDL = new(pidl); + //public new ObservableCollection ChildItems; // TODO: base.ChildItems; public string DisplayName => ShellItem.GetDisplayName(ShellItemDisplayString.NormalDisplay) ?? ShellItem.ToString(); + public readonly Shell32.PIDL PIDL = new(pidl); public ShellItem ShellItem = new(pidl); - public new ObservableCollection ChildItems = []; - public static BrowserItem FromPIDL(Shell32.PIDL pidl) => new(pidl, false); - public static BrowserItem FromShellFolder(ShellFolder shellFolder) => new(shellFolder.PIDL, true); - - public static BrowserItem FromKnownFolderId(Shell32.KNOWNFOLDERID knownItemId) => - new(new ShellFolder(knownItemId).PIDL, true); - public SoftwareBitmapSource? SoftwareBitmap; public event PropertyChangedEventHandler? PropertyChanged; - protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) { - if (EqualityComparer.Default.Equals(field, value)) return false; + if (EqualityComparer.Default.Equals(field, value)) + { + return false; + } + field = value; OnPropertyChanged(propertyName); return true; @@ -61,9 +71,9 @@ protected bool SetField(ref T field, T value, [CallerMemberName] string? prop } [DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public partial class BrowserItemCollection : List, IList +public partial class BrowserItemCollection : List, IList // TODO: IDisposable { - protected IList ListImplementation => new List(); + private protected IList ListImplementation => new List(); public void CopyTo(Array array, int index) => ListImplementation.CopyTo(array, index); public new int Count => ListImplementation.Count; @@ -79,9 +89,5 @@ public partial class BrowserItemCollection : List, IList public bool IsFixedSize => ListImplementation.IsFixedSize; public bool IsReadOnly => ListImplementation.IsReadOnly; - public new object? this[int index] - { - get => ListImplementation[index]; - set => ListImplementation[index] = value; - } + public new object? this[int index] => ListImplementation[index]; } \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs index b1c27c6..2bb5123 100644 --- a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs @@ -84,6 +84,12 @@ public async Task ExtractShellIcon() return null; } + /* + ? await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER) + : await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC) + + */ + public struct BrowserStockIcon( Shell32.SHSTOCKICONID shStockIconId, ShellIconType shellIconType = ShellIconType.Large, diff --git a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs index 77ebcbf..e7f209f 100644 --- a/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs +++ b/src/electrifier/Controls/Vanara/ShellNamespaceTreeControl.xaml.cs @@ -33,14 +33,14 @@ public ShellNamespaceTreeControl() private void ShellNamespaceTreeControl_Loading(FrameworkElement sender, object args) { // TODO: Raise event, and let the parent decide which folders to use as root - TreeItems.Add(BrowserItem.FromShellFolder(ShellNamespaceService.HomeShellFolder)); - TreeItems.Add(BrowserItem.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_SkyDrive)); - TreeItems.Add(BrowserItem.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Desktop)); - TreeItems.Add(BrowserItem.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Downloads)); - TreeItems.Add(BrowserItem.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Documents)); - TreeItems.Add(BrowserItem.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Pictures)); - TreeItems.Add(BrowserItem.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Music)); - TreeItems.Add(BrowserItem.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Videos)); + TreeItems.Add(BrowserItemFactory.FromShellFolder(ShellNamespaceService.HomeShellFolder)); + TreeItems.Add(BrowserItemFactory.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_SkyDrive)); + TreeItems.Add(BrowserItemFactory.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Desktop)); + TreeItems.Add(BrowserItemFactory.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Downloads)); + TreeItems.Add(BrowserItemFactory.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Documents)); + TreeItems.Add(BrowserItemFactory.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Pictures)); + TreeItems.Add(BrowserItemFactory.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Music)); + TreeItems.Add(BrowserItemFactory.FromKnownFolderId(Shell32.KNOWNFOLDERID.FOLDERID_Videos)); } // TODO: public object ItemFromContainer => NativeTreeView.ItemFromContainer() diff --git a/src/electrifier/Views/WorkbenchPage.xaml.cs b/src/electrifier/Views/WorkbenchPage.xaml.cs index ce21045..3277bce 100644 --- a/src/electrifier/Views/WorkbenchPage.xaml.cs +++ b/src/electrifier/Views/WorkbenchPage.xaml.cs @@ -21,7 +21,7 @@ public WorkbenchPage() public static async IAsyncEnumerable RequestDriveItemsAsync() { - yield return (BrowserItem.FromShellFolder(new(@"c:\"))); + yield return (BrowserItemFactory.FromShellFolder(new(@"c:\"))); //yield return (BrowserItem.FromShellFolder(new(@"d:\"))); //yield return (BrowserItem.FromShellFolder(new(@"f:\"))); } From 1d30d6443708f2fbb5733085c2bb409e0f902268 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Fri, 29 Nov 2024 15:20:06 +0100 Subject: [PATCH 35/57] Refactor --- .../Controls/Vanara/ExplorerBrowser.xaml.cs | 9 ++++++--- .../Vanara/Helpers/BrowserItemFactory.cs | 8 ++++---- .../Controls/Vanara/ShellListView.xaml.cs | 17 ++++++----------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs index f227839..b679919 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs @@ -51,13 +51,14 @@ public ExplorerBrowser() ShellTreeView.NativeTreeView.SelectionChanged += NativeTreeView_SelectionChanged; using var shHome = ShellNamespaceService.HomeShellFolder; - //Navigate(new BrowserItem(shHome.PIDL, true)); // TODO: Navigate to TreeViewItem! + //Navigate(new BrowserItem(shHome.PIDL, true)); // TODO: Navigate to TreeViewItem! } // TODO: @dahall: Maybe we should throw HRESULT-COM-Errors at least here? Your HRESULT.ThrowIfFailed() - Pattern? public async void Navigate(BrowserItem target) { - Debug.WriteLineIf(!target.IsFolder, $"Navigate({target.DisplayName}) => is not a folder!"); + //Debug.WriteLineIf(!target.IsFolder, $"Navigate({target.DisplayName}) => is not a folder!"); + // TODO: If no folder, or drive empty, etc... show empty listview with error message try { @@ -130,7 +131,7 @@ public async Task GetStockIconBitmapSource(Shell32.SHSTOCK } } - + // INFO: Is called from History... public async void Navigate(ShellItem target, TreeViewNode? treeViewNode = null) { // TODO: Search for best matching RootItem in the tree hierarchy @@ -150,6 +151,8 @@ private void NativeTreeView_SelectionChanged(TreeView sender, TreeViewSelectionC if (currentTreeNode is BrowserItem browserItem && browserItem.PIDL.Equals(selectedFolder?.PIDL)) { Debug.Print(".NativeTreeView_SelectionChanged(): CurrentTreeNode already equals selected /added Item."); + + // TODO: Refresh } else { diff --git a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs index c4a7763..f0d3713 100644 --- a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs +++ b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs @@ -31,12 +31,12 @@ public abstract class AbstractBrowserItem(bool? isFolder, List>? childItems) // TODO: IDisposable { public readonly List> ChildItems = childItems ?? []; - public readonly bool IsFolder = isFolder ?? false; + public readonly bool? IsFolder = isFolder; //internal void async IconUpdate(int Index, SoftwareBitmapSource bmpSrc); //internal void async StockIconUpdate(STOCKICONID id, SoftwareBitmapSource bmpSrc); //internal void async ChildItemsIconUpdate(); - public new string ToString() => $"AbstractBrowserItem(<{typeof(T)}>(isFolder {isFolder}, childItems {childItems})"; + public new string ToString() => $"AbstractBrowserItem(<{typeof(T)}>(isFolder {IsFolder}, childItems {childItems})"; } [DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] @@ -44,7 +44,7 @@ public partial class BrowserItem( Shell32.PIDL pidl, bool? isFolder, List>? childItems = default) - : AbstractBrowserItem(isFolder, childItems ?? []), INotifyPropertyChanged // TODO: IDisposable + : AbstractBrowserItem(isFolder, childItems ?? []), INotifyPropertyChanged // TODO: IDisposable // TODO: IComparable { //public new ObservableCollection ChildItems; // TODO: base.ChildItems; public string DisplayName => ShellItem.GetDisplayName(ShellItemDisplayString.NormalDisplay) ?? ShellItem.ToString(); @@ -71,7 +71,7 @@ protected bool SetField(ref T field, T value, [CallerMemberName] string? prop } [DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] -public partial class BrowserItemCollection : List, IList // TODO: IDisposable +public partial class BrowserItemCollection : List, IList // TODO: IDisposable { private protected IList ListImplementation => new List(); diff --git a/src/electrifier/Controls/Vanara/ShellListView.xaml.cs b/src/electrifier/Controls/Vanara/ShellListView.xaml.cs index cb8b390..8d983b4 100644 --- a/src/electrifier/Controls/Vanara/ShellListView.xaml.cs +++ b/src/electrifier/Controls/Vanara/ShellListView.xaml.cs @@ -1,30 +1,25 @@ -using System.Collections.ObjectModel; -using Microsoft.UI.Xaml.Controls; using CommunityToolkit.WinUI.Collections; using electrifier.Controls.Vanara.Helpers; +using Microsoft.UI.Xaml.Controls; +using System.Collections.ObjectModel; // todo: For EnumerateChildren-Calls, add HWND handle // todo: See ShellItemCollection, perhaps use this instead of ObservableCollection // https://github.com/dahall/Vanara/blob/master/Windows.Shell.Common/ShellObjects/ShellItemArray.cs - namespace electrifier.Controls.Vanara; public partial class ShellListView : UserControl { public ItemsView NativeItemsView => ItemsView; - public ObservableCollection Items; - private readonly AdvancedCollectionView _advancedCollectionView; + public ObservableCollection Items = new(); + public readonly AdvancedCollectionView AdvancedCollectionView; public ShellListView() { InitializeComponent(); DataContext = this; - Items = new ObservableCollection(); - _advancedCollectionView = new AdvancedCollectionView(Items, true); - NativeItemsView.ItemsSource = _advancedCollectionView; - - //NativeGridView.ShowsScrollingPlaceholders = true; - //NativeGridView.ScrollBarVisibility = ScrollBarVisibility.Auto; + AdvancedCollectionView = new AdvancedCollectionView(Items, true); + NativeItemsView.ItemsSource = AdvancedCollectionView; } } \ No newline at end of file From 548ec74a951ffe950a3a0aadcc9b1ca2d1703b81 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Fri, 29 Nov 2024 16:52:14 +0100 Subject: [PATCH 36/57] Add dummy Flags from original Browser --- .../Contracts/IShellNamespaceService.cs | 3 +- .../Controls/Vanara/ExplorerBrowser.xaml.cs | 389 +++++++++++++++++- .../Vanara/Helpers/BrowserItemFactory.cs | 6 +- .../Vanara/Services/ShellNamespaceService.cs | 35 +- 4 files changed, 395 insertions(+), 38 deletions(-) diff --git a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs index 99bf25e..2425ca2 100644 --- a/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Contracts/IShellNamespaceService.cs @@ -10,9 +10,8 @@ public interface IShellNamespaceService /// Fired when `Element not found` while enumerating the Shell32 Namespace. /// As far as I know, this also gets fired when No Disk in Drive error occurs. public static readonly HRESULT HResultElementNotFound = new(0x80070490); + /// of virtual `Home` directory. /// This equals Shell 32 URI: shell:::{679f85cb-0220-4080-b29b-5540cc05aab6} public static ShellFolder HomeShellFolder => new("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}"); - - } \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs index b679919..316025f 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml.cs @@ -11,6 +11,7 @@ using Vanara.PInvoke; using Vanara.Windows.Shell; using static Vanara.PInvoke.Shell32; +using Vanara.Collections; namespace electrifier.Controls.Vanara; @@ -131,12 +132,90 @@ public async Task GetStockIconBitmapSource(Shell32.SHSTOCK } } - // INFO: Is called from History... - public async void Navigate(ShellItem target, TreeViewNode? treeViewNode = null) + // INFO: Is called from + public void Navigate(ShellItem? shellItem, + ExplorerBrowserNavigationItemCategory category = ExplorerBrowserNavigationItemCategory.Default) { - // TODO: Search for best matching RootItem in the tree hierarchy + //Debug.WriteLineIf(!target.IsFolder, $"Navigate({target.DisplayName}) => is not a folder!"); + // TODO: If no folder, or drive empty, etc... show empty listview with error message + + + } + + + + // /// + // /// Clears the Explorer Browser of existing content, fills it with content from the specified container, and adds a new point to the + // /// Travel Log. + // /// + // /// The shell container to navigate to. + // /// The category of the . + // public void Navigate(ShellItem? shellItem, ExplorerBrowserNavigationItemCategory category = ExplorerBrowserNavigationItemCategory.Default) + // { + // if (explorerBrowserControl is null) + // { + // antecreationNavigationTarget = (shellItem, category); + // } + // else if (shellItem is not null) + // { + // var hr = explorerBrowserControl.BrowseToObject(shellItem.IShellItem, (SBSP)category); + // if (hr == HRESULT_RESOURCE_IN_USE || hr == HRESULT_CANCELLED) + // OnNavigationFailed(new NavigationFailedEventArgs { FailedLocation = shellItem }); + // else if (hr.Failed) + // throw new ArgumentException("Unable to browse to this shell item.", nameof(shellItem), hr.GetException()); + // } + // } + // + // /// + // /// Navigates to the last item in the navigation history list. This does not change the set of locations in the navigation log. + // /// + // public bool NavigateBack() + // { + // if (History.CanNavigateBackward) { Navigate(null, ExplorerBrowserNavigationItemCategory.NavigateBack); return true; } + // return false; + // } + // + // /// + // /// Navigates to the next item in the navigation history list. This does not change the set of locations in the navigation log. + // /// + // /// True if the navigation succeeded, false if it failed for any reason. + // public bool NavigateForward() + // { + // if (History.CanNavigateForward) { Navigate(null, ExplorerBrowserNavigationItemCategory.NavigateForward); return true; } + // return false; + // } + // + // /// + // /// Navigate within the navigation log in a specific direciton. This does not change the set of locations in the navigation log. + // /// + // /// The direction to navigate within the navigation logs collection. + // /// True if the navigation succeeded, false if it failed for any reason. + // public bool NavigateFromHistory(NavigationLogDirection direction) => History.NavigateLog(direction); + // + // /// Navigate within the navigation log. This does not change the set of locations in the navigation log. + // /// An index into the navigation logs Locations collection. + // /// True if the navigation succeeded, false if it failed for any reason. + // public bool NavigateToHistoryIndex(int historyIndex) => History.NavigateLog(historyIndex); + // + // /// Selects all items in the current view. + // public void SelectAll() + // { + // var fv2 = GetFolderView2(); + // if (fv2 is null) return; + // for (var i = 0; i < fv2.ItemCount(SVGIO.SVGIO_ALLVIEW); i++) + // fv2.SelectItem(i, SVSIF.SVSI_SELECT); + // } + // + // /// Unselects all items in the current view. + // public void UnselectAll() + // { + // var fv2 = GetFolderView2(); + // fv2?.SelectItem(-1, SVSIF.SVSI_DESELECTOTHERS); + // } + + private void NativeTreeView_SelectionChanged(TreeView sender, TreeViewSelectionChangedEventArgs args) { var addedItems = args.AddedItems; @@ -195,3 +274,307 @@ private bool SetField(ref T field, T value, [CallerMemberName] string? proper #endregion Property stuff } +#region DON'T TOUCH Imports from Vanara.Windows.Forms.ExplorerBrowser. +/// +/// Public imports from Vanara. +/// +public partial class ExplorerBrowser +{ + /// + /// Indicates the content options of the explorer browser. Typically use one, or a bitwise combination of these flags to specify how + /// content should appear in the explorer browser control + /// + [Flags] + public enum ExplorerBrowserContentSectionOptions : uint + { + /// No options. + None = FOLDERFLAGS.FWF_NONE, + + /// The view should be left-aligned. + AlignLeft = FOLDERFLAGS.FWF_ALIGNLEFT, + + /// Automatically arrange the elements in the view. + AutoArrange = FOLDERFLAGS.FWF_AUTOARRANGE, + + /// Turns on check mode for the view + CheckSelect = FOLDERFLAGS.FWF_CHECKSELECT, + + /// When the view is set to "Tile" the layout of a single item should be extended to the width of the view. + ExtendedTiles = FOLDERFLAGS.FWF_EXTENDEDTILES, + + /// When an item is selected, the item and all its sub-items are highlighted. + FullRowSelect = FOLDERFLAGS.FWF_FULLROWSELECT, + + /// The view should not display file names + HideFileNames = FOLDERFLAGS.FWF_HIDEFILENAMES, + + /// The view should not save view state in the browser. + NoBrowserViewState = FOLDERFLAGS.FWF_NOBROWSERVIEWSTATE, + + /// Do not display a column header in the view in any view mode. + NoColumnHeader = FOLDERFLAGS.FWF_NOCOLUMNHEADER, + + /// Only show the column header in details view mode. + NoHeaderInAllViews = FOLDERFLAGS.FWF_NOHEADERINALLVIEWS, + + /// The view should not display icons. + NoIcons = FOLDERFLAGS.FWF_NOICONS, + + /// Do not show subfolders. + NoSubfolders = FOLDERFLAGS.FWF_NOSUBFOLDERS, + + /// Navigate with a single click + SingleClickActivate = FOLDERFLAGS.FWF_SINGLECLICKACTIVATE, + + /// Do not allow more than a single item to be selected. + SingleSelection = FOLDERFLAGS.FWF_SINGLESEL, + + /// + /// Make the folder behave like the desktop. This value applies only to the desktop and is not used for typical Shell folders. + /// + Desktop = FOLDERFLAGS.FWF_DESKTOP, + + /// Draw transparently. This is used only for the desktop. + Transparent = FOLDERFLAGS.FWF_TRANSPARENT, + + /// Do not add scroll bars. This is used only for the desktop. + NoScrollBars = FOLDERFLAGS.FWF_NOSCROLL, + + /// The view should not be shown as a web view. + NoWebView = FOLDERFLAGS.FWF_NOWEBVIEW, + + /// + /// Windows Vista and later. Do not re-enumerate the view (or drop the current contents of the view) when the view is refreshed. + /// + NoEnumOnRefresh = FOLDERFLAGS.FWF_NOENUMREFRESH, + + /// Windows Vista and later. Do not allow grouping in the view + NoGrouping = FOLDERFLAGS.FWF_NOGROUPING, + + /// Windows Vista and later. Do not display filters in the view. + NoFilters = FOLDERFLAGS.FWF_NOFILTERS, + + /// Windows Vista and later. Items can be selected using check-boxes. + AutoCheckSelect = FOLDERFLAGS.FWF_AUTOCHECKSELECT, + + /// Windows Vista and later. The view should list the number of items displayed in each group. To be used with IFolderView2::SetGroupSubsetCount. + SubsetGroup = FOLDERFLAGS.FWF_SUBSETGROUPS, + + /// Windows Vista and later. Use the search folder for stacking and searching. + UseSearchFolder = FOLDERFLAGS.FWF_USESEARCHFOLDER, + + /// + /// Windows Vista and later. Ensure right-to-left reading layout in a right-to-left system. Without this flag, the view displays + /// strings from left-to-right both on systems set to left-to-right and right-to-left reading layout, which ensures that file names + /// display correctly. + /// + AllowRtlReading = FOLDERFLAGS.FWF_ALLOWRTLREADING, + } + + /// These flags are used with . + [Flags] + public enum ExplorerBrowserLoadFlags + { + /// No flags. + None = EXPLORER_BROWSER_FILL_FLAGS.EBF_NONE, + + /// + /// Causes to first populate the results folder with the contents of the parent + /// folders of the items in the data object, and then select only the items that are in the data object. + /// + SelectFromDataObject = EXPLORER_BROWSER_FILL_FLAGS.EBF_SELECTFROMDATAOBJECT, + + /// + /// Do not allow dropping on the folder. In other words, do not register a drop target for the view. Applications can then register + /// their own drop targets. + /// + NoDropTarget = EXPLORER_BROWSER_FILL_FLAGS.EBF_NODROPTARGET, + } + + /// + /// Specifies the options that control subsequent navigation. Typically use one, or a bitwise combination of these flags to specify how + /// the explorer browser navigates. + /// + [Flags] + public enum ExplorerBrowserNavigateOptions + { + /// No options. + None = EXPLORER_BROWSER_OPTIONS.EBO_NONE, + + /// Always navigate, even if you are attempting to navigate to the current folder. + AlwaysNavigate = EXPLORER_BROWSER_OPTIONS.EBO_ALWAYSNAVIGATE, + + /// Do not navigate further than the initial navigation. + NavigateOnce = EXPLORER_BROWSER_OPTIONS.EBO_NAVIGATEONCE, + + /// + /// Use the following standard panes: Commands Module pane, Navigation pane, Details pane, and Preview pane. An implementer of + /// IExplorerPaneVisibility can modify the components of the Commands Module that are shown. For more information see, + /// IExplorerPaneVisibility::GetPaneState. If EBO_SHOWFRAMES is not set, Explorer browser uses a single view object. + /// + ShowFrames = EXPLORER_BROWSER_OPTIONS.EBO_SHOWFRAMES, + + /// Do not update the travel log. + NoTravelLog = EXPLORER_BROWSER_OPTIONS.EBO_NOTRAVELLOG, + + /// Do not use a wrapper window. This flag is used with legacy clients that need the browser parented directly on themselves. + NoWrapperWindow = EXPLORER_BROWSER_OPTIONS.EBO_NOWRAPPERWINDOW, + + /// Show WebView for SharePoint sites. + HtmlSharePointView = EXPLORER_BROWSER_OPTIONS.EBO_HTMLSHAREPOINTVIEW, + + /// Introduced in Windows Vista. Do not draw a border around the browser window. + NoBorder = EXPLORER_BROWSER_OPTIONS.EBO_NOBORDER, + + /// Introduced in Windows Vista. Do not persist the view state. + NoPersistViewState = EXPLORER_BROWSER_OPTIONS.EBO_NOPERSISTVIEWSTATE, + } + + /// Flags specifying the folder to be browsed. + [Flags] + public enum ExplorerBrowserNavigationItemCategory : uint + { + /// An absolute PIDL, relative to the desktop. + Absolute = SBSP.SBSP_ABSOLUTE, + + /// Windows Vista and later. Navigate without the default behavior of setting focus into the new view. + ActivateNoFocus = SBSP.SBSP_ACTIVATE_NOFOCUS, + + /// Enable auto-navigation. + AllowAutoNavigate = SBSP.SBSP_ALLOW_AUTONAVIGATE, + + /// + /// Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The navigation was possibly initiated by a web page with scripting + /// code already present on the local system. + /// + CallerUntrusted = SBSP.SBSP_CALLERUNTRUSTED, + + /// + /// Windows 7 and later. Do not add a new entry to the travel log. When the user enters a search term in the search box and + /// subsequently refines the query, the browser navigates forward but does not add an additional travel log entry. + /// + CreateNoHistory = SBSP.SBSP_CREATENOHISTORY, + + /// + /// Use default behavior, which respects the view option (the user setting to create new windows or to browse in place). In most + /// cases, calling applications should use this flag. + /// + Default = SBSP.SBSP_DEFBROWSER, + + /// Use the current window. + UseCurrentWindow = SBSP.SBSP_DEFMODE, + + /// + /// Specifies a folder tree for the new browse window. If the current browser does not match the SBSP.SBSP_EXPLOREMODE of the browse + /// object call, a new window is opened. + /// + ExploreMode = SBSP.SBSP_EXPLOREMODE, + + /// + /// Windows Internet Explorer 7 and later. If allowed by current registry settings, give the browser a destination to navigate to. + /// + FeedNavigation = SBSP.SBSP_FEEDNAVIGATION, + + /// Windows Vista and later. Navigate without clearing the search entry field. + KeepSearchText = SBSP.SBSP_KEEPWORDWHEELTEXT, + + /// Navigate back, ignore the PIDL. + NavigateBack = SBSP.SBSP_NAVIGATEBACK, + + /// Navigate forward, ignore the PIDL. + NavigateForward = SBSP.SBSP_NAVIGATEFORWARD, + + /// Creates another window for the specified folder. + NewWindow = SBSP.SBSP_NEWBROWSER, + + /// Suppress selection in the history pane. + NoHistorySelect = SBSP.SBSP_NOAUTOSELECT, + + /// Do not transfer the browsing history to the new window. + NoTransferHistory = SBSP.SBSP_NOTRANSFERHIST, + + /// + /// Specifies no folder tree for the new browse window. If the current browser does not match the SBSP.SBSP_OPENMODE of the browse + /// object call, a new window is opened. + /// + NoFolderTree = SBSP.SBSP_OPENMODE, + + /// Browse the parent folder, ignore the PIDL. + ParentFolder = SBSP.SBSP_PARENT, + + /// Windows 7 and later. Do not make the navigation complete sound for each keystroke in the search box. + PlayNoSound = SBSP.SBSP_PLAYNOSOUND, + + /// Enables redirection to another URL. + Redirect = SBSP.SBSP_REDIRECT, + + /// A relative PIDL, relative to the current folder. + Relative = SBSP.SBSP_RELATIVE, + + /// Browse to another folder with the same Windows Explorer window. + SameWindow = SBSP.SBSP_SAMEBROWSER, + + /// Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The navigate should allow ActiveX prompts. + TrustedForActiveX = SBSP.SBSP_TRUSTEDFORACTIVEX, + + /// + /// Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The new window is the result of a user initiated action. Trust the + /// new window if it immediately attempts to download content. + /// + TrustFirstDownload = SBSP.SBSP_TRUSTFIRSTDOWNLOAD, + + /// + /// Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The window is navigating to an untrusted, non-HTML file. If the + /// user attempts to download the file, do not allow the download. + /// + UntrustedForDownload = SBSP.SBSP_UNTRUSTEDFORDOWNLOAD, + + /// Write no history of this navigation in the history Shell folder. + WriteNoHistory = SBSP.SBSP_WRITENOHISTORY + } + + /// Indicates the viewing mode of the explorer browser + public enum ExplorerBrowserViewMode + { + /// Choose the best view mode for the folder + Auto = FOLDERVIEWMODE.FVM_AUTO, + + /// (New for Windows7) + Content = FOLDERVIEWMODE.FVM_CONTENT, + + /// Object names and other selected information, such as the size or date last updated, are shown. + Details = FOLDERVIEWMODE.FVM_DETAILS, + + /// The view should display medium-size icons. + Icon = FOLDERVIEWMODE.FVM_ICON, + + /// Object names are displayed in a list view. + List = FOLDERVIEWMODE.FVM_LIST, + + /// The view should display small icons. + SmallIcon = FOLDERVIEWMODE.FVM_SMALLICON, + + /// The view should display thumbnail icons. + Thumbnail = FOLDERVIEWMODE.FVM_THUMBNAIL, + + /// The view should display icons in a filmstrip format. + ThumbStrip = FOLDERVIEWMODE.FVM_THUMBSTRIP, + + /// The view should display large icons. + Tile = FOLDERVIEWMODE.FVM_TILE + } + + /// Indicates the visibility state of an ExplorerBrowser pane. + public enum PaneVisibilityState + { + /// Allow the explorer browser to determine if this pane is displayed. + Default = EXPLORERPANESTATE.EPS_DONTCARE, + + /// Hide the pane + Hide = EXPLORERPANESTATE.EPS_DEFAULT_OFF | EXPLORERPANESTATE.EPS_FORCE, + + /// Show the pane + Show = EXPLORERPANESTATE.EPS_DEFAULT_ON | EXPLORERPANESTATE.EPS_FORCE + } +} +#endregion DON'T TOUCH Imports from Vanara.Windows.Forms.ExplorerBrowser \ No newline at end of file diff --git a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs index f0d3713..89c8bf2 100644 --- a/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs +++ b/src/electrifier/Controls/Vanara/Helpers/BrowserItemFactory.cs @@ -15,7 +15,6 @@ public class BrowserItemFactory { public static BrowserItem FromPIDL(Shell32.PIDL pidl) => new(pidl, isFolder: null); public static BrowserItem FromShellFolder(ShellFolder shellFolder) => new(shellFolder.PIDL, true); - public static BrowserItem FromKnownFolderId(Shell32.KNOWNFOLDERID knownItemId) => new(new ShellFolder(knownItemId).PIDL, true); } @@ -68,6 +67,11 @@ protected bool SetField(ref T field, T value, [CallerMemberName] string? prop OnPropertyChanged(propertyName); return true; } + + public void PreEnumerate() + { + + } } [DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] diff --git a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs index 2bb5123..e3b90cf 100644 --- a/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs +++ b/src/electrifier/Controls/Vanara/Services/ShellNamespaceService.cs @@ -30,32 +30,6 @@ public ShellNamespaceService() } - ///// Initialize default Stock Icons. - ///// TODO: INFO: Investigate - ///// - //public static async Task InitializeStockIconsAsync() - //{ - // /* Todo: inspect `SHGetStockIconInfo()` */ - // //var siFlags = SHGSI.SHGSI_LARGEICON | SHGSI.SHGSI_ICON; - // //var siStockIconInfo = new SHSTOCKICONINFO(); - // //SHGetStockIconInfo(Shell32.SHSTOCKICONID.SIID_APPLICATION, siFlags, ref siStockIconInfo).ThrowIfFailed(); - - // // TODO: Use embedded resource, red cross to signal something failed. - // using var siFolder = new StockIcon(SHSTOCKICONID.SIID_FOLDER); - // { - // var idx = siFolder.SystemImageIndex; - // var icnHandle = siFolder.IconHandle.ToIcon(); - // var bmpSource = GetWinUi3BitmapSourceFromIcon(icnHandle); - // } - - // using var siDocument = new StockIcon(SHSTOCKICONID.SIID_DOCASSOC); - // { - // var idx = siDocument.SystemImageIndex; - // var icnHandle = siDocument.IconHandle.ToIcon(); - // var bmpSource = GetWinUi3BitmapSourceFromIcon(icnHandle); - // } - //} - // TODO: Add await event handler to every ebItem, so Icon Extractor can call back the item public static async Task RequestChildItemsAsync(ShellFolder shFolder, FolderItemFilter itemFilter = (FolderItemFilter.Folders | FolderItemFilter.NonFolders), @@ -84,13 +58,10 @@ public async Task ExtractShellIcon() return null; } - /* - ? await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER) - : await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC) - - */ + /* ? await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_FOLDER) + : await GetStockIconBitmapSource(Shell32.SHSTOCKICONID.SIID_DOCNOASSOC) */ - public struct BrowserStockIcon( + public struct BrowserStockIcon( // TODO: => Implement SoftwareBitmapSource Shell32.SHSTOCKICONID shStockIconId, ShellIconType shellIconType = ShellIconType.Large, bool isLinkOverlay = false, From 91eeca024536ca53f776773af428c4f73b02cfe4 Mon Sep 17 00:00:00 2001 From: Thorsten Jung Date: Sat, 30 Nov 2024 10:08:04 +0100 Subject: [PATCH 37/57] Move `CommandBar` from to `ExplorerBrowser` --- .../Controls/Vanara/ExplorerBrowser.xaml | 268 +++++++++++++++- src/electrifier/Views/FileManagerPage.xaml | 287 +----------------- 2 files changed, 275 insertions(+), 280 deletions(-) diff --git a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml index 55af514..6f7e573 100644 --- a/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml +++ b/src/electrifier/Controls/Vanara/ExplorerBrowser.xaml @@ -10,10 +10,223 @@ mc:Ignorable="d"> + + + + + + + + + + + + + + + + + + + + + + + + + + + +