diff --git a/Vanara-Jnana/App.xaml.cs b/Vanara-Jnana/App.xaml.cs index 16fe5c1c..dbbb27c7 100644 --- a/Vanara-Jnana/App.xaml.cs +++ b/Vanara-Jnana/App.xaml.cs @@ -1,3 +1,4 @@ +using Jnana; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; //using LaunchActivatedEventArgs = Windows.ApplicationModel.Activation.LaunchActivatedEventArgs; diff --git a/Vanara-Jnana/Assets/Vanara/dahall-NuGet Avatar.png b/Vanara-Jnana/Assets/Vanara/dahall-NuGet Avatar.png new file mode 100644 index 00000000..f04a0b92 Binary files /dev/null and b/Vanara-Jnana/Assets/Vanara/dahall-NuGet Avatar.png differ diff --git a/Vanara-Jnana/Directory.Packages.props b/Vanara-Jnana/Directory.Packages.props index d915cf5f..c7226e90 100644 --- a/Vanara-Jnana/Directory.Packages.props +++ b/Vanara-Jnana/Directory.Packages.props @@ -1,6 +1,5 @@ - diff --git a/Vanara-Jnana/Helpers/ImageExtensions.cs b/Vanara-Jnana/Helpers/ImageExtensions.cs new file mode 100644 index 00000000..9452ed3b --- /dev/null +++ b/Vanara-Jnana/Helpers/ImageExtensions.cs @@ -0,0 +1,25 @@ +using Microsoft.UI.Xaml.Media.Imaging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jnana.Helpers; + +public class ImageExtensions +{ + public static BitmapImage? ToBitmapImage(byte[]? bytes) + { + if (bytes == null || bytes.Length == 0) + return null; + + var bitmap = new BitmapImage(); + + using var ms = new MemoryStream(bytes); + var ras = ms.AsRandomAccessStream(); + + bitmap.SetSource(ras); + return bitmap; + } +} diff --git a/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs b/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs index 7e7023c7..5f93150a 100644 --- a/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs +++ b/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs @@ -1,6 +1,6 @@ using Microsoft.UI.Dispatching; -namespace ClassicSamplesBrowser.Helpers; +namespace Jnana.Helpers; public class WindowsSystemDispatcherQueueHelper { diff --git a/Vanara-Jnana/Jnana.csproj b/Vanara-Jnana/Jnana.csproj index 520e6023..107897eb 100644 --- a/Vanara-Jnana/Jnana.csproj +++ b/Vanara-Jnana/Jnana.csproj @@ -26,9 +26,19 @@ + + - - + + + + + + + + + + diff --git a/Vanara-Jnana/MainWindow.xaml b/Vanara-Jnana/MainWindow.xaml index 87402db4..0fec0fbe 100644 --- a/Vanara-Jnana/MainWindow.xaml +++ b/Vanara-Jnana/MainWindow.xaml @@ -1,9 +1,8 @@ diff --git a/Vanara-Jnana/MainWindow.xaml.cs b/Vanara-Jnana/MainWindow.xaml.cs index f66ed72b..8eea1a8d 100644 --- a/Vanara-Jnana/MainWindow.xaml.cs +++ b/Vanara-Jnana/MainWindow.xaml.cs @@ -1,17 +1,15 @@ -using ClassicSamplesBrowser.Helpers; -using ClassicSamplesBrowser.Views; +using Jnana.Views; using Microsoft.UI.Composition.SystemBackdrops; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI; -using System.Drawing; +using System.Diagnostics; using Vanara.PInvoke; using Windows.Graphics; using WinRT; -using ClassicSamplesBrowser.Services; -using System.Diagnostics; +using Jnana.Helpers; -namespace ClassicSamplesBrowser; +namespace Jnana; public sealed partial class MainWindow : Window { @@ -28,8 +26,8 @@ public MainWindow() // _navigationService = new NavigationService(RootFrame); - //var initialSize = ApplicationData.Current.LocalSettings.Values["InitialWindowSize"] as string; - //this.AppWindow.Size = _initialWindowSize; + // var initialSize = ApplicationData.Current.LocalSettings.Values["InitialWindowSize"] as string; + // this.AppWindow.Size = _initialWindowSize; // AppWindow.Size = new Size() { Width = 800, Height = 600 }; _ = RootFrame.Navigate(typeof(ShellPage)); diff --git a/Vanara-Jnana/Models/ApiAssemblyModel.cs b/Vanara-Jnana/Models/ApiAssemblyModel.cs deleted file mode 100644 index 12e786ba..00000000 --- a/Vanara-Jnana/Models/ApiAssemblyModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ClassicSamplesBrowser.Models; - -internal class ApiAssemblyModel -{ -} \ No newline at end of file diff --git a/Vanara-Jnana/Models/ApiEnumModel.cs b/Vanara-Jnana/Models/ApiEnumModel.cs deleted file mode 100644 index b3fd6f9b..00000000 --- a/Vanara-Jnana/Models/ApiEnumModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ClassicSamplesBrowser.Models; - -internal class ApiEnumModel -{ -} \ No newline at end of file diff --git a/Vanara-Jnana/Models/ApiMethodModel.cs b/Vanara-Jnana/Models/ApiMethodModel.cs deleted file mode 100644 index e7f45188..00000000 --- a/Vanara-Jnana/Models/ApiMethodModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ClassicSamplesBrowser.Models; - -internal class ApiMethodModel -{ -} \ No newline at end of file diff --git a/Vanara-Jnana/Models/ApiNamespaceModel.cs b/Vanara-Jnana/Models/ApiNamespaceModel.cs deleted file mode 100644 index 6c0e2e09..00000000 --- a/Vanara-Jnana/Models/ApiNamespaceModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ClassicSamplesBrowser.Models; - -internal class ApiNamespaceModel -{ -} \ No newline at end of file diff --git a/Vanara-Jnana/Models/ApiPropertyModel.cs b/Vanara-Jnana/Models/ApiPropertyModel.cs deleted file mode 100644 index bc91c5d7..00000000 --- a/Vanara-Jnana/Models/ApiPropertyModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ClassicSamplesBrowser.Models; - -internal class ApiPropertyModel -{ -} \ No newline at end of file diff --git a/Vanara-Jnana/Models/ApiSampleModel.cs b/Vanara-Jnana/Models/ApiSampleModel.cs deleted file mode 100644 index 650c7826..00000000 --- a/Vanara-Jnana/Models/ApiSampleModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ClassicSamplesBrowser.Models; - -internal class ApiSampleModel -{ -} \ No newline at end of file diff --git a/Vanara-Jnana/Models/ApiTypeModel.cs b/Vanara-Jnana/Models/ApiTypeModel.cs deleted file mode 100644 index 5bdd927b..00000000 --- a/Vanara-Jnana/Models/ApiTypeModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ClassicSamplesBrowser.Models; - -internal class ApiTypeModel -{ -} \ No newline at end of file diff --git a/Vanara-Jnana/Models/INavigationService.cs b/Vanara-Jnana/Models/INavigationService.cs new file mode 100644 index 00000000..984546f1 --- /dev/null +++ b/Vanara-Jnana/Models/INavigationService.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jnana.Models; + +public interface INavigationService +{ + public enum Area + { + Void, + NuGets, + GitHub, + Samples, + Disassembler, + Utilities, + Settings + } + + void NavigateTo(Area area); +} diff --git a/Vanara-Jnana/Services/ISettingsSerializer.cs b/Vanara-Jnana/Models/ISettingsSerializer.cs similarity index 84% rename from Vanara-Jnana/Services/ISettingsSerializer.cs rename to Vanara-Jnana/Models/ISettingsSerializer.cs index 852b0637..756fe96b 100644 --- a/Vanara-Jnana/Services/ISettingsSerializer.cs +++ b/Vanara-Jnana/Models/ISettingsSerializer.cs @@ -1,6 +1,6 @@ using System.ComponentModel; -namespace ClassicSamplesBrowser.Services; +namespace Jnana.Models; public interface ISettingsSerializer : INotifyPropertyChanged { diff --git a/Vanara-Jnana/Services/INuGetCatalogService.cs b/Vanara-Jnana/Services/INuGetCatalogService.cs new file mode 100644 index 00000000..3b0e13c8 --- /dev/null +++ b/Vanara-Jnana/Services/INuGetCatalogService.cs @@ -0,0 +1,36 @@ +using Microsoft.UI.Xaml.Media.Imaging; +using NuGet.Versioning; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jnana.Services; + +public record PackageId(string Id); + +public record PackageVersionInfo( + string Id, + string Version, + Uri? IconUrl, + string? Description, + string? Summary, + BitmapImage? Icon +); + +public record PackageContent( + string Id, + NuGetVersion Version, + IReadOnlyList Assemblies, + string? Readme, + byte[]? IconBytes, + BitmapImage? Icon +); + +public interface INuGetCatalogService +{ + IAsyncEnumerable SearchPackagesAsync(string prefix, CancellationToken token); + Task GetLatestStableVersionAsync(string packageId, CancellationToken token); + Task DownloadPackageAsync(string id, NuGetVersion version, CancellationToken token); +} diff --git a/Vanara-Jnana/Services/NavigationService.cs b/Vanara-Jnana/Services/NavigationService.cs index 27e97594..de9e4e5a 100644 --- a/Vanara-Jnana/Services/NavigationService.cs +++ b/Vanara-Jnana/Services/NavigationService.cs @@ -1,125 +1,51 @@ -using ClassicSamplesBrowser.Views; -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; +using Jnana.Models; using Jnana.Views; using Microsoft.UI.Xaml.Controls; -using Microsoft.Win32; using System.Diagnostics; -using Vanara.PInvoke; -using static ClassicSamplesBrowser.Services.INavigationService; +using static Jnana.Models.INavigationService; -namespace ClassicSamplesBrowser.Services; - -public interface INavigationService -{ - public enum Area - { - Void, - NuGets, - GitHub, - Samples, - Disassembler, - Utilities, - Settings - } - - void NavigateTo(Area area); -} +namespace Jnana.Services; public partial class NavigationService : ObservableObject, INavigationService { - public Area CurrentArea - { - get; - set - { - if (SetProperty(ref field, value)) - { - OnPropertyChanged(nameof(CurrentPage)); - } - } - } = Area.Void; - - public Page CurrentPage => CurrentArea switch - { - Area.GitHub => new GitHubPage(), - Area.NuGets => new NuGetsPage(), - Area.Samples => new SamplesPage(), - Area.Settings => new SettingsPage(), - _ => new VoidPage() - }; - private readonly Frame _frame; private readonly Dictionary _areaPageMap; public NavigationService(Frame frame) { - _frame = frame; + _frame = frame ?? throw new ArgumentNullException(nameof(frame)); _areaPageMap = new() { + { Area.Disassembler, typeof(DisassemblerPage) }, { Area.GitHub, typeof(GitHubPage) }, { Area.NuGets, typeof(NuGetsPage) }, { Area.Samples, typeof(SamplesPage) }, { Area.Settings, typeof(SettingsPage) }, + { Area.Utilities, typeof(UtilitiesPage) }, { Area.Void, typeof(VoidPage) }, }; - - // INFO: @dahall - select a default page to navigate to on loading, to ensure the main content area is populated with a page, and to establish a consistent starting point for navigation - //NavigateTo(Area.Void); - //NavigateTo(Area.Settings); } - // // TODO: - // // public static void Navigate(Shell32.IShellFolder shellFolder) - // // { - // // TryNavigate(shellFolder); - // // } - // public bool TryNavigate(object target, bool allowPageCreation = true) - // { - // try - // { - // var pageType = target switch - // { - // "Assemblies" => typeof(AssembliesPage), - // "GitHub" => typeof(GitHubPage), - // "NuGets" => typeof(NuGetsPage), - // "Samples" => typeof(SamplesPage), - // "Settings" => typeof(SettingsPage), - // "Start" => typeof(StartPage), - // "Utilities" => typeof(UtilitiesPage), - // _ => null - // }; - // - // // Check if the page type is null and if page creation is allowed - // if (pageType == null && !allowPageCreation) - // { - // //LogWriter.PrintLine("Page type is null and page creation is not allowed."); - // return false; - // } - // - // // TODO: _frame.Navigate(pageType ?? new UtilitiesPage()); - // //return _frame.Navigate(pageType); - // return true; - // } - // catch (Exception ex) - // { - // Debug.Fail(ex.ToString()); - // throw; - // } - // } - - public static void NavigateBack() { } - - public static void Forward() { } - public void NavigateTo(Area area) { - if (_areaPageMap.TryGetValue(area, out var pageType)) + try + { + if (_areaPageMap.TryGetValue(area, out var pageType)) + { + Debug.Print($"Navigating to `{area}` page."); + _frame.Navigate(pageType); + } + else + { + Debug.Print($"Failed to get page for `{area}` from PageMap."); + } + } + catch (Exception ex) { - Debug.Print($"Navigating to `{area}` page."); - _frame.Navigate(pageType); + Debug.Fail(ex.ToString()); + throw; } } - - //public void Navigate(Area area) { CurrentArea = area; } } diff --git a/Vanara-Jnana/Services/NuGetCatalogDiskCache.cs b/Vanara-Jnana/Services/NuGetCatalogDiskCache.cs new file mode 100644 index 00000000..83b8097d --- /dev/null +++ b/Vanara-Jnana/Services/NuGetCatalogDiskCache.cs @@ -0,0 +1,105 @@ +using NuGet.Versioning; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Jnana.Services; + +public sealed class NuGetCatalogDiskCache : INuGetCatalogService +{ + private readonly INuGetCatalogService _inner; + private readonly string _cacheFile; + private readonly TimeSpan _ttl = TimeSpan.FromHours(24); + + private Dictionary? _cache; + private DateTime _timestamp; + + public NuGetCatalogDiskCache(INuGetCatalogService inner, string cacheFile) + { + _inner = inner; + _cacheFile = cacheFile; + + _ = LoadFromDisk(); + } + + private async Task LoadFromDisk() + { + if (!File.Exists(_cacheFile)) + return; + + try + { + var json = File.ReadAllText(_cacheFile); + var data = JsonSerializer.Deserialize(json); + + if (data != null && DateTime.UtcNow - data.Timestamp < _ttl) + { + _timestamp = data.Timestamp; + _cache = data.Packages.ToDictionary(p => p.Id, p => p); + + Debug.WriteLine("LoadFromDisk(): Cache dated {0} successfully loaded from disk ", _timestamp); + } + } + catch + { + // we can ignore any errors here - if the cache is corrupted or unreadable, we'll just start fresh + } + } + + private void SaveToDisk() + { + var data = new CacheData + { + Timestamp = DateTime.UtcNow, + Packages = _cache?.Values.ToList() ?? new() + }; + + var json = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true }); + Directory.CreateDirectory(Path.GetDirectoryName(_cacheFile)!); + File.WriteAllText(_cacheFile, json); + } + + public async IAsyncEnumerable SearchPackagesAsync( + string prefix, + [EnumeratorCancellation] CancellationToken token) + { + await foreach (var pkg in _inner.SearchPackagesAsync(prefix, token)) + yield return pkg; + } + + public async Task GetLatestStableVersionAsync( + string packageId, + CancellationToken token) + { + _cache ??= new(); + + if (_cache.TryGetValue(packageId, out var info)) + return info; + + var latest = await _inner.GetLatestStableVersionAsync(packageId, token); + if (latest != null) + { + _cache[packageId] = latest; + SaveToDisk(); + } + + return latest; + } + + public Task DownloadPackageAsync( + string id, + NuGetVersion version, + CancellationToken token) + => _inner.DownloadPackageAsync(id, version, token); + + private sealed class CacheData + { + public DateTime Timestamp { get; set; } + public List Packages { get; set; } = new(); + } +} diff --git a/Vanara-Jnana/Services/NuGetCatalogMemoryCache.cs b/Vanara-Jnana/Services/NuGetCatalogMemoryCache.cs new file mode 100644 index 00000000..80302916 --- /dev/null +++ b/Vanara-Jnana/Services/NuGetCatalogMemoryCache.cs @@ -0,0 +1,49 @@ +using NuGet.Versioning; +using System.Runtime.CompilerServices; + +namespace Jnana.Services; + +public sealed class NuGetCatalogMemoryCache : INuGetCatalogService +{ + private readonly INuGetCatalogService _inner; + private readonly TimeSpan _ttl = TimeSpan.FromHours(24); + + private readonly Dictionary _cache + = new(); + + public NuGetCatalogMemoryCache(INuGetCatalogService inner) + { + _inner = inner; + } + + public async IAsyncEnumerable SearchPackagesAsync( + string prefix, + [EnumeratorCancellation] CancellationToken token) + { + await foreach (var pkg in _inner.SearchPackagesAsync(prefix, token)) + yield return pkg; + } + + public async Task GetLatestStableVersionAsync( + string packageId, + CancellationToken token) + { + if (_cache.TryGetValue(packageId, out var entry)) + { + if (DateTime.UtcNow - entry.Timestamp < _ttl) + return entry.Info; + } + + var info = await _inner.GetLatestStableVersionAsync(packageId, token); + if (info != null) + _cache[packageId] = (DateTime.UtcNow, info); + + return info; + } + + public Task DownloadPackageAsync( + string id, + NuGetVersion version, + CancellationToken token) + => _inner.DownloadPackageAsync(id, version, token); +} diff --git a/Vanara-Jnana/Services/NuGetCatalogService.cs b/Vanara-Jnana/Services/NuGetCatalogService.cs new file mode 100644 index 00000000..52f247bc --- /dev/null +++ b/Vanara-Jnana/Services/NuGetCatalogService.cs @@ -0,0 +1,134 @@ +using Jnana.Helpers; +using Microsoft.UI.Xaml.Media.Imaging; +using NuGet.Common; +using NuGet.Packaging; +using NuGet.Protocol.Core.Types; +using NuGet.Protocol; +using NuGet.Versioning; +using System.Runtime.CompilerServices; + +namespace Jnana.Services; + +public sealed class NuGetCatalogService : INuGetCatalogService +{ + private readonly SourceRepository _repo; + private readonly ILogger? _logger; + + public NuGetCatalogService(string sourceUrl, ILogger? logger = null) + { + _repo = Repository.Factory.GetCoreV3(sourceUrl); + _logger = logger ?? NullLogger.Instance; + } + + public async IAsyncEnumerable SearchPackagesAsync( + string prefix, + [EnumeratorCancellation] CancellationToken token) + { + var search = await _repo.GetResourceAsync(token); + var filter = new SearchFilter(includePrerelease: true); + + // TODO: @dahall NuGet's search API doesn't support prefix searching, so we may fetch a bunch of results and then would have to filter them ourselves. + // TODO: See the results, they include `MonitoringUtils` and `LeadManager.Common`. Note these appear in VS NuGet Pane, too. + var results = await search.SearchAsync(prefix, filter, 0, 200, _logger, token); + + foreach (var r in results) + yield return new PackageId(r.Identity.Id); + } + + public async Task GetLatestStableVersionAsync( + string packageId, + CancellationToken token) + { + var search = await _repo.GetResourceAsync(token); + var filter = new SearchFilter(includePrerelease: true); + + var results = await search.SearchAsync(packageId, filter, 0, 1, _logger, token); + + var pkg = results.FirstOrDefault(); + if (pkg is null) + return null; + + var versions = await pkg.GetVersionsAsync(); + + var latestStable = versions + .Where(v => !v.Version.IsPrerelease) + .OrderBy(v => v.Version) + .LastOrDefault(); + + if (latestStable is null) + return null; + + return new PackageVersionInfo( + pkg.Identity.Id, + latestStable.Version.ToString(), + pkg.IconUrl, + pkg.Description, + pkg.Summary, + Icon: null + ); + } + + public async Task DownloadPackageAsync( + string id, + NuGetVersion version, + CancellationToken token) + { + var find = await _repo.GetResourceAsync(token); + + using var cache = new SourceCacheContext(); + using var stream = new MemoryStream(); + + bool ok = await find.CopyNupkgToStreamAsync( + id, version, stream, cache, _logger, token); + + if (!ok) + throw new InvalidOperationException($"Could not download {id} {version}"); + + stream.Position = 0; + using var reader = new PackageArchiveReader(stream); + var packageFiles = reader.GetFiles().ToList(); + + // First, extract all DLLs + var dlls = packageFiles + .Where(f => f.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + .ToList(); + + // Extract the readme if it exists + string? readmeText = null; + var readmePath = packageFiles.FirstOrDefault(f => + f.EndsWith("readme.md", StringComparison.OrdinalIgnoreCase)); + + if (readmePath != null) + { + using var readmeStream = await reader.GetStreamAsync(readmePath, token); + using var sr = new StreamReader(readmeStream); + readmeText = await sr.ReadToEndAsync(); + } + + // Extract the icon if it exists + byte[]? iconBytes = null; + var iconPath = packageFiles.FirstOrDefault(f => + f.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || + f.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)); + + BitmapImage? Icon = null; + if (iconPath != null) + { + using var iconStream = await reader.GetStreamAsync(iconPath, token); + using var ms = new MemoryStream(); + await iconStream.CopyToAsync(ms, token); + iconBytes = ms.ToArray(); + + Icon = ImageExtensions.ToBitmapImage(iconBytes); + } + + return new PackageContent( + id, + version, + dlls, + readmeText, + iconBytes, + Icon + ); + } +} diff --git a/Vanara-Jnana/Services/TabNavigationService.cs b/Vanara-Jnana/Services/TabNavigationService.cs index c48ad068..55559b3a 100644 --- a/Vanara-Jnana/Services/TabNavigationService.cs +++ b/Vanara-Jnana/Services/TabNavigationService.cs @@ -1,9 +1,7 @@ -using ClassicSamplesBrowser.Views; +using Jnana.Views; using Microsoft.UI.Xaml.Controls; -using System; using System.Collections.ObjectModel; -//using System.Reflection.Metadata; -//using static ICSharpCode.Decompiler.SingleFileBundle; +using System; namespace Jnana.Services; @@ -16,7 +14,7 @@ public static void Initialize(TabView tabView) { _tabView = tabView; } - public static void AddPageTab(string header, Type pageType, object? parameter = null, bool selectTab = true) + public static void AddPageTab(string header, Type pageType, object? parameter = null, bool selectTab = true) where T : Control { var tab = new TabViewItem diff --git a/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml b/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml index 4a7fcccd..bc6e5d5e 100644 --- a/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml +++ b/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml @@ -1,5 +1,5 @@ DebugSettings.; - } - // Dependency Properties public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(FeatureTile), @@ -38,7 +29,13 @@ public FeatureTile() ((FeatureTile)d).IconElement.Glyph = (string)e.NewValue; })); - public event EventHandler Click; + public static readonly DependencyProperty CommandProperty = + DependencyProperty.Register(nameof(Command), typeof(StandardUICommand), typeof(FeatureTile), + new PropertyMetadata(null, (d, e) => + { + ((FeatureTile)d).Command = (StandardUICommand)e.NewValue; + })); + public string Title { @@ -58,6 +55,22 @@ public string Icon set => SetValue(IconProperty, value); } + public event EventHandler Click; + + public StandardUICommand Command + { + get => (StandardUICommand)GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } + + public FeatureTile() + { + InitializeComponent(); + SetupInteractions(); + + this.Click += (_, __) => Debug.WriteLine($"FeatureTile clicked: Title='{Title}', Subtitle='{Subtitle}'"); + } + private void SetupInteractions() { Root.PointerEntered += (_, __) => diff --git a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml index 879389bc..a2c71a82 100644 --- a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml +++ b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml @@ -1,30 +1,33 @@ 56 - - + - - + + + + + diff --git a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs index 14778d63..996241dc 100644 --- a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs +++ b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs @@ -1,10 +1,11 @@ -using Microsoft.UI.Xaml.Controls; +using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; using System.ComponentModel; using System.Runtime.CompilerServices; -using CommunityToolkit.Mvvm.ComponentModel; +using WinRT.Interop; -namespace ClassicSamplesBrowser.Vanara.Controls; +namespace Jnana.Vanara.Controls; public sealed partial class FloatingStatusBar : UserControl, INotifyPropertyChanged @@ -22,12 +23,22 @@ public FloatingStatusBar() _hideTimer.Tick += (s, e) => { if (_autoHide) Hide(); }; Show("READY."); + ResizeGrip.PointerPressed += ResizeGrip_PointerPressed; + /* TODO: Sizer Glyphs: Klassischer Resize‑Grip E7BF „GripperResize“ – diagonale Linien, wirkt wie der alte Win32‑Grip Alternative minimal E7C0 „GripperBarHorizontal“ – drei Punkte, subtiler Look Symbolisch E7C1 „GripperBarVertical“ – vertikale Punkte, wenn du rechts unten eine Spalte andeutest */ } + + private void ResizeGrip_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) + { + //var hwnd = WindowNative.GetWindowHandle(this); + + // TODO: NativeMethods.SendMessage(hwnd, NativeMethods.WM_NCLBUTTONDOWN, (IntPtr)NativeMethods.HTBOTTOMRIGHT, IntPtr.Zero); + } + public void Show(string message, string icon = "\uE946") { MessageElement.Text = message; diff --git a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml index fa5c66c4..2aa665c9 100644 --- a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml +++ b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml @@ -1,9 +1,9 @@ diff --git a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs index 5b2f85d0..dd2873c2 100644 --- a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs +++ b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs @@ -3,7 +3,7 @@ // To learn more about WinUI, the WinUI project structure, // and more about our project templates, see: http://aka.ms/winui-project-info. -namespace ClassicSamplesBrowser.Vanara.Controls; +namespace Jnana.Vanara.Controls; public sealed partial class Shell32AppBar : UserControl { diff --git a/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml b/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml index 13111e4c..da954380 100644 --- a/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml +++ b/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml @@ -1,8 +1,8 @@ LoadVanaraAssemblyTreeAsync() - { - // Get Vanara packages from NuGet -// var packages = await NuGetUtils.GetVanaraPackagesAsync(); -// -// // Select the latest version (simple for now) -// var latest = packages.OrderByDescending(p => p.Version).FirstOrDefault(); -// if (latest == null) -// return null; -// -// // Download package and extract DLLs -// var dllPaths = await NuGetUtils.DownloadAndExtractAssembliesAsync(latest); -// -// // Create reflection tree -// var root = AssemblyElements.CreateFromAssemblies(dllPaths); -// -// return root; - return null; - } -} diff --git a/Vanara-Jnana/Vanara/Services/NavigationService.cs b/Vanara-Jnana/Vanara/Services/NavigationService.cs deleted file mode 100644 index 8aa8ec3b..00000000 --- a/Vanara-Jnana/Vanara/Services/NavigationService.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Microsoft.UI.Xaml.Controls; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ClassicSamplesBrowser.Views; - -namespace ClassicSamplesBrowser.Vanara.Services; - - -public static class NavigationService -{ - // The Frame control used for navigation - private static Frame _frame; - - public static void Initialize(Frame frame) - { - _frame = frame; - } - - public static List NavigationHistory { get; } = []; - - // TODO: Events: Navigated, Navigating, NavigationFailed, NavigationStopped - - public static bool CanGoBack => _frame.CanGoBack; - public static bool CanGoForward => _frame.CanGoForward; - - - public static void NavigateToStart() - => Navigate(typeof(StartPage)); - - public static void NavigateToSamples() - => Navigate(typeof(SamplesPage)); - - public static void Navigate(Type pageType, object parameter = null) - { - try - { - _frame.Navigate(pageType, parameter); - } - catch (Exception ex) - { - Debug.Fail(ex.ToString()); - throw; - } - } - - public static void GoBack() - { - if(CanGoBack) - { - _frame.GoBack(); - } - } - - public static void GoForward() - { - if(CanGoForward) - { - _frame.GoForward(); - } - } - - //// object = null; => Home! - //public bool Navigate(object navigationTarget, object? parameter = null, bool writeHistory = true) - //{ - // try - // { - // if (navigationTarget != null) - // { - // return parameter != null ? - // Frame.Navigate(navigationTarget.GetType(), parameter) - // : Frame.Navigate(navigationTarget.GetType()); - // } - - // // TODO: search the web - // } - // catch (Exception ex) - // { - // // Handle navigation exceptions as needed. - // Debug.WriteLine($"Navigation error: {ex.Message}"); - // return false; - // } - - // if (writeHistory) - // { - // // Navigate to the target page and add it to the navigation history - // } - - // return true; - //} -} diff --git a/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs b/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs index a95c537d..213e6e5a 100644 --- a/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs +++ b/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs @@ -1,11 +1,18 @@ -using ClassicSamplesBrowser.Vanara.Reflection; -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Jnana.Vanara.NuGet; using System.Collections.ObjectModel; +using System.Security.Policy; namespace Jnana.ViewModels; public partial class GitHubAreaViewModel : ObservableObject { + private readonly Url gitHubRepoUrl = new("https://github.com/vanara/Vanara"); + private readonly Url gitHubIssuesUrl = new("https://github.com/vanara/Vanara/issues"); + private readonly Url gitHubPullRequestsUrl = new("https://github.com/vanara/Vanara/pulls"); + + public Url GitHubRepoUrl => gitHubRepoUrl; + public Url GitHubIssuesUrl => gitHubIssuesUrl; + public Url GitHubPullRequestsUrl => gitHubPullRequestsUrl; } diff --git a/Vanara-Jnana/ViewModels/NuGetPackageDetailViewModel.cs b/Vanara-Jnana/ViewModels/NuGetPackageDetailViewModel.cs new file mode 100644 index 00000000..be5d0484 --- /dev/null +++ b/Vanara-Jnana/ViewModels/NuGetPackageDetailViewModel.cs @@ -0,0 +1,68 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Jnana.Helpers; +using Jnana.Services; +using Microsoft.UI.Xaml.Media.Imaging; +using NuGet.Versioning; + +namespace Jnana.ViewModels; + +public sealed partial class NuGetPackageDetailViewModel : ObservableObject +{ + private readonly INuGetCatalogService _catalog; + private PackageContent? _content; + public string? Id => _content?.Id; + public string? Version => _content?.Version?.ToNormalizedString(); + public string? Readme => _content?.Readme; + + private BitmapImage? _icon; + public BitmapImage? Icon + { + get + { + if (_icon == null && _content?.IconBytes != null) + _icon = ImageExtensions.ToBitmapImage(_content.IconBytes); + return _icon; + } + } + public NuGetPackageDetailViewModel(INuGetCatalogService catalog) + { + _catalog = catalog; + + // TODO: Consider adding a placeholder icon here while the real one is loading, or if it fails to load. + // TODO: Bind Details Pane against Package Details View Model, and show + } + + public async Task LoadAsync(string id, NuGetVersion version, CancellationToken token) + { + _content = await _catalog.DownloadPackageAsync(id, version, token); + OnPropertyChanged(nameof(Id)); + OnPropertyChanged(nameof(Version)); + OnPropertyChanged(nameof(Readme)); + OnPropertyChanged(nameof(Icon)); + } + + public void Clear() + { + _content = null; + _icon = null; + OnPropertyChanged(nameof(Id)); + OnPropertyChanged(nameof(Version)); + OnPropertyChanged(nameof(Readme)); + OnPropertyChanged(nameof(Icon)); + } + + /* + // Handle the selection of the package version info + //await PackageDetailViewModel.LoadAsync(SelectedPackage.Id, NuGet.Versioning.NuGetVersion.Parse(SelectedPackage.Version), cancelToken).ContinueWith(t => + //{ + // if (t.IsFaulted) + // { + // Debug.Print($"Failed to load package details: {t.Exception}"); + // //logger?.LogError(t.Exception, "Failed to load package details"); + // } + //}, cancelToken); + // + //await PackageDetailViewModel.LoadAsync(SelectedPackage.Id, NuGet.Versioning.NuGetVersion.Parse(SelectedPackage.Version), CancellationToken.None); + + */ +} diff --git a/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs b/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs index 0b278d9b..15b43781 100644 --- a/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs +++ b/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs @@ -1,138 +1,68 @@ -using ClassicSamplesBrowser.Vanara.Reflection; -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Jnana.Vanara.NuGet; +using Jnana.Services; +using NuGet.Common; +using NuGet.Versioning; using System.Collections.ObjectModel; using System.Windows.Input; +using Windows.ApplicationModel.Background; namespace Jnana.ViewModels; public partial class NuGetsAreaViewModel : ObservableObject { - // TODO: Use `NuGetPackageInfo` here: - public ObservableCollection Packages { get; } = - new ObservableCollection(); + private readonly NuGetCatalogService nuGetCatalogService; + private readonly NuGetCatalogMemoryCache nuGetCatalogMemoryCache; + private readonly NuGetCatalogDiskCache nuGetCatalogDiskCache; - public ICommand RefreshCommand { get; } + /// Get the current INuGetCatalogService that is in use. + public INuGetCatalogService NuGetCatalogService => nuGetCatalogDiskCache; - public NuGetsAreaViewModel() + public ObservableCollection Packages { get; } = new(); + + public NuGetPackageDetailViewModel PackageDetailViewModel { get; } + + public ICommand SelectVersionCommand { get; } + + public NuGetsAreaViewModel(ILogger? logger = null) { - RefreshCommand = new RelayCommand(LoadPackages); + nuGetCatalogService = new NuGetCatalogService("https://api.nuget.org/v3/index.json", logger); + nuGetCatalogMemoryCache = new NuGetCatalogMemoryCache(nuGetCatalogService); + + var cachePath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Jnana", "nuget-cache.json"); + + nuGetCatalogDiskCache = new NuGetCatalogDiskCache(nuGetCatalogMemoryCache, cachePath); + PackageDetailViewModel = new NuGetPackageDetailViewModel(nuGetCatalogDiskCache); + + SelectVersionCommand = new RelayCommand(OnVersionSelected); } - private void LoadPackages() + public async Task SynchronizePackageCacheAsync() { - // TODO: API call + // TODO: Instead of clearing the entire cache, consider implementing a more efficient synchronization strategy that only updates changed packages. + Packages.Clear(); + + await foreach (var pkg in nuGetCatalogDiskCache.SearchPackagesAsync("Vanara.", CancellationToken.None)) + { + var latest = await nuGetCatalogDiskCache.GetLatestStableVersionAsync(pkg.Id, CancellationToken.None); + if (latest != null) + Packages.Add(latest); + } } - // private readonly AssemblyLoaderService _loader; - // - // public NuGetViewModel(AssemblyLoaderService loader) - // { - // _loader = loader; - // - // Packages = new ObservableCollection(); - // Versions = new ObservableCollection(); - // } - // - // // ----------------------------- - // // Collections - // // ----------------------------- - // public ObservableCollection Packages { get; } - // public ObservableCollection Versions { get; } - // - // // ----------------------------- - // // Selected Items - // // ----------------------------- - // [ObservableProperty] - // private NuGetPackageInfo? selectedPackage; - // - // partial void OnSelectedPackageChanged(NuGetPackageInfo? value) - // { - // if (value != null) - // LoadVersionsCommand.Execute(value); - // } - // - // [ObservableProperty] - // private string? selectedVersion; - // - // partial void OnSelectedVersionChanged(string? value) - // { - // if (value != null) - // LoadAssemblyTreeCommand.Execute(value); - // } - // - // // ----------------------------- - // // Reflection Root - // // ----------------------------- - // [ObservableProperty] - // private IElementInfo? rootElement; - // - // // ----------------------------- - // // Loading Flags - // // ----------------------------- - // [ObservableProperty] private bool isLoadingPackages; - // [ObservableProperty] private bool isLoadingVersions; - // [ObservableProperty] private bool isLoadingAssemblies; - // - // // ----------------------------- - // // Commands - // // ----------------------------- - // [RelayCommand] - // private async Task LoadPackagesAsync() - // { - // try - // { - // IsLoadingPackages = true; - // Packages.Clear(); - // - // var pkgs = await _nuget.GetVanaraPackagesAsync(); - // - // foreach (var pkg in pkgs) - // Packages.Add(pkg); - // } - // finally - // { - // IsLoadingPackages = false; - // } - // } - // - // [RelayCommand] - // private async Task LoadVersionsAsync(NuGetPackageInfo package) - // { - // try - // { - // IsLoadingVersions = true; - // Versions.Clear(); - // - // var versions = await _nuget.GetPackageVersionsAsync(package.Id); - // - // foreach (var v in versions) - // Versions.Add(v); - // } - // finally - // { - // IsLoadingVersions = false; - // } - // } - // - // [RelayCommand] - // private async Task LoadAssemblyTreeAsync(string version) - // { - // try - // { - // IsLoadingAssemblies = true; - // - // var assemblies = await _nuget.DownloadAndExtractAssembliesAsync( - // SelectedPackage!.Id, - // version - // ); - // - // RootElement = await _loader.LoadFromAssembliesAsync(assemblies); - // } - // finally - // { - // IsLoadingAssemblies = false; - // } - // } + private async void OnVersionSelected(PackageVersionInfo? version) + { + if (version != null) + { + // TODO: Update package Detail view with the selected version + await PackageDetailViewModel.LoadAsync(version.Id, NuGetVersion.Parse(version.Version), CancellationToken.None); + } + else + { + // Make sure all values are cleared if no version is selected + PackageDetailViewModel.Clear(); + } + // TODO: Update Details pane to show the selected version's details + } } diff --git a/Vanara-Jnana/ViewModels/UtilitiesAreaViewModel.cs b/Vanara-Jnana/ViewModels/UtilitiesAreaViewModel.cs new file mode 100644 index 00000000..5854cab0 --- /dev/null +++ b/Vanara-Jnana/ViewModels/UtilitiesAreaViewModel.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jnana.ViewModels; + +internal class UtilitiesAreaViewModel +{ +} diff --git a/Vanara-Jnana/ViewModels/VoidPageViewModel.cs b/Vanara-Jnana/ViewModels/VoidPageViewModel.cs index 83af207e..87321b3e 100644 --- a/Vanara-Jnana/ViewModels/VoidPageViewModel.cs +++ b/Vanara-Jnana/ViewModels/VoidPageViewModel.cs @@ -12,63 +12,17 @@ namespace Jnana.ViewModels; public partial class VoidPageViewModel : ObservableObject { - public NuGetsAreaViewModel NuGetArea { get; } - public GitHubAreaViewModel GitHubArea { get; } - public SamplesAreaViewModel SamplesArea { get; } - - public List NugetItems => ["NuGet", "GitHub", "Samples"]; - - private object _currentArea; - public object CurrentArea - { - get => _currentArea; - set => SetProperty(ref _currentArea, value); - } - - public ICommand NavigateCommand { get; } + public NuGetsAreaViewModel NuGetsViewModel { get; } + public GitHubAreaViewModel GitHubViewModel { get; } + public SamplesAreaViewModel SamplesViewModel { get; } public VoidPageViewModel( NuGetsAreaViewModel nuget, GitHubAreaViewModel github, SamplesAreaViewModel samples) { - NuGetArea = nuget; - GitHubArea = github; - SamplesArea = samples; - - CurrentArea = NuGetArea; - - NavigateCommand = new RelayCommand(OnNavigate); - } - - private void OnNavigate(string target) - { - CurrentArea = target switch - { - "NuGet" => NuGetArea, - "GitHub" => GitHubArea, - "Samples" => SamplesArea, - _ => CurrentArea - }; + NuGetsViewModel = nuget; + GitHubViewModel = github; + SamplesViewModel = samples; } - - /// - /// the following properties are just placeholders for the actual content of each area. In a real application, these would likely be more complex types representing the data and functionality of each area. - /// -// public List NugetItems { get; set; } -// public List GitHubItems { get; set; } -// public List SamplesItems { get; set; } } - -// internal class VoidPageViewModel { -// public List NugetItems { get; set; } -// public List GitHubItems { get; set; } -// public List SamplesItems { get; set; } -// public VoidPageViewModel() -// { NugetItems = new List(); -// GitHubItems = new List(); -// SamplesItems = new List(); -// -// NugetItems.AddRange(new String[] { "Vanara.Core", "Vanara.PInvoke", "Vanara.Windows", "etc." }); -// GitHubItems.AddRange(new String[] { "Home", "Releases", "Issues", "Pull Requests" }); -// SamplesItems.AddRange(new String[] { "Item 1", "Item 2", "Item 3", "etc." }); } } diff --git a/Vanara-Jnana/Views/GitHubPage.xaml b/Vanara-Jnana/Views/GitHubPage.xaml index 3da8b0e2..621b5282 100644 --- a/Vanara-Jnana/Views/GitHubPage.xaml +++ b/Vanara-Jnana/Views/GitHubPage.xaml @@ -1,8 +1,8 @@ + diff --git a/Vanara-Jnana/Views/GitHubPage.xaml.cs b/Vanara-Jnana/Views/GitHubPage.xaml.cs index 1fcf3d28..9dc9d752 100644 --- a/Vanara-Jnana/Views/GitHubPage.xaml.cs +++ b/Vanara-Jnana/Views/GitHubPage.xaml.cs @@ -1,39 +1,11 @@ using Microsoft.UI.Xaml.Controls; -namespace ClassicSamplesBrowser.Views; +namespace Jnana.Views; public sealed partial class GitHubPage : Page { public GitHubPage() { InitializeComponent(); - - //ContentFrame.Navigate(typeof(HomePage)); } - -// private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) -// { -// if (args.SelectedItem is NavigationViewItem item) -// { -// var tag = item.Tag?.ToString(); -// -// switch (tag) -// { -// case "HomePage": -// ContentFrame.Navigate(typeof(HomePage)); -// //HeaderTitle.Text = "Home"; -// break; -// -// case "SamplesPage": -// ContentFrame.Navigate(typeof(SamplesPage)); -// //HeaderTitle.Text = "Samples"; -// break; -// -// case "AboutPage": -// ContentFrame.Navigate(typeof(AboutPage)); -// //HeaderTitle.Text = "About"; -// break; -// } -// } -// } } \ No newline at end of file diff --git a/Vanara-Jnana/Views/NuGetsPage.xaml b/Vanara-Jnana/Views/NuGetsPage.xaml index 6647002b..c5fe8889 100644 --- a/Vanara-Jnana/Views/NuGetsPage.xaml +++ b/Vanara-Jnana/Views/NuGetsPage.xaml @@ -1,20 +1,62 @@ + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"> - + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Vanara-Jnana/Views/UtilitiesPage.xaml.cs b/Vanara-Jnana/Views/UtilitiesPage.xaml.cs index 8d7e0786..2d07dc1b 100644 --- a/Vanara-Jnana/Views/UtilitiesPage.xaml.cs +++ b/Vanara-Jnana/Views/UtilitiesPage.xaml.cs @@ -1,31 +1,20 @@ -using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Controls.Primitives; -using Microsoft.UI.Xaml.Data; -using Microsoft.UI.Xaml.Input; -using Microsoft.UI.Xaml.Media; -using Microsoft.UI.Xaml.Navigation; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Foundation; -using Windows.Foundation.Collections; -// To learn more about WinUI, the WinUI project structure, -// and more about our project templates, see: http://aka.ms/winui-project-info. +namespace Jnana.Views; -namespace ClassicSamplesBrowser.Views +public sealed partial class UtilitiesPage : Page { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public sealed partial class UtilitiesPage : Page + public UtilitiesPage() { - public UtilitiesPage() - { - InitializeComponent(); - } + InitializeComponent(); + //Loaded += OnLoaded; } + + //private void OnLoaded(object sender, RoutedEventArgs e) + //{ + // if (!ToolManager.HasOpenTools) + // { + // ToolManager.Open(); + // } + //} } diff --git a/Vanara-Jnana/Views/VoidPage.xaml b/Vanara-Jnana/Views/VoidPage.xaml index d4504847..291a5c24 100644 --- a/Vanara-Jnana/Views/VoidPage.xaml +++ b/Vanara-Jnana/Views/VoidPage.xaml @@ -4,9 +4,12 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:Jnana.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:toolkit="using:CommunityToolkit.WinUI.Controls" xmlns:viewmodels="using:Jnana.ViewModels" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:controls="using:CommunityToolkit.WinUI.Controls" + d:DataContext="{d:DesignInstance Type=viewmodels:VoidPageViewModel}" mc:Ignorable="d"> @@ -16,79 +19,45 @@ - - - - - + + + + + + + + - - - - - - + + + + + -