From e036cdc991878d8333a9d0e435573033ec83a7f9 Mon Sep 17 00:00:00 2001 From: Nice3point Date: Wed, 15 Nov 2023 02:40:26 +0300 Subject: [PATCH] Update services --- RevitLookup.UI.Demo/App.xaml.cs | 104 ++------ RevitLookup.UI.Demo/HostProvider.cs | 91 +++++++ RevitLookup.UI.Demo/Moq/MoqSnoopViewModel.cs | 235 ------------------ .../Services/MoqLookupService.cs | 111 +++++++++ .../Services/MoqSnoopService.cs | 133 ++++++++++ .../ViewModels/MoqSnoopViewModel.cs | 138 ++++++++++ RevitLookup.sln.DotSettings | 3 +- RevitLookup/Commands/DashboardCommand.cs | 8 +- RevitLookup/Commands/EventMonitorCommand.cs | 11 +- RevitLookup/Commands/SearchElementsCommand.cs | 15 +- RevitLookup/Commands/SnoopDatabaseCommand.cs | 12 +- RevitLookup/Commands/SnoopDocumentCommand.cs | 11 +- RevitLookup/Commands/SnoopEdgeCommand.cs | 11 +- RevitLookup/Commands/SnoopFaceCommand.cs | 11 +- .../Commands/SnoopLinkedElementCommand.cs | 11 +- RevitLookup/Commands/SnoopPointCommand.cs | 11 +- RevitLookup/Commands/SnoopSelectionCommand.cs | 11 +- .../Commands/SnoopSubElementCommand.cs | 11 +- RevitLookup/Commands/SnoopViewCommand.cs | 11 +- .../DefinitionBindingMapIteratorDescriptor.cs | 2 +- .../Descriptors/DependencyObjectDescriptor.cs | 2 +- .../Descriptors/EnumeratorDescriptor.cs | 2 +- .../Descriptors/FamilyManagerDescriptor.cs | 2 +- .../Descriptors/ReferenceDescriptor.cs | 2 +- .../Descriptors/StringDescriptor.cs | 2 +- .../Descriptors/UiObjectDescriptor.cs | 2 +- .../Descriptors/WorksetTableDescriptor.cs | 2 +- .../Core/Metadata/DescriptorBuilder.Api.cs | 2 +- .../Core/Metadata/DescriptorBuilder.Build.cs | 2 +- .../Metadata/DescriptorBuilder.Enumeration.cs | 2 +- .../Core/Metadata/DescriptorBuilder.Events.cs | 2 +- .../Metadata/DescriptorBuilder.Extensions.cs | 2 +- .../Core/Metadata/DescriptorBuilder.Fields.cs | 2 +- .../Metadata/DescriptorBuilder.Methods.cs | 2 +- .../Metadata/DescriptorBuilder.Properties.cs | 2 +- .../Core/Metadata/DescriptorBuilder.Write.cs | 2 +- .../Core/Metadata/DescriptorBuilder.cs | 2 +- RevitLookup/Core/Objects/SnoopableObject.cs | 4 +- RevitLookup/Core/RevitApi.cs | 65 ++++- RevitLookup/Core/Selector.cs | 38 ++- RevitLookup/Core/Utils/ContextUtils.cs | 2 +- RevitLookup/Host.cs | 111 +++++---- RevitLookup/RevitLookup.csproj | 1 - .../Services/Contracts/ISettingsService.cs | 1 + .../Services/Contracts/ISnoopService.cs | 2 +- RevitLookup/Services/Contracts/IWindow.cs | 11 +- .../Services/Contracts/IWindowController.cs | 42 ---- RevitLookup/Services/Enums/SnoopableType.cs | 3 +- RevitLookup/Services/LookupService.cs | 113 +++++++++ RevitLookup/Services/NotificationService.cs | 88 +++++++ RevitLookup/Services/SnoopService.cs | 102 ++++++++ RevitLookup/Services/WindowController.cs | 44 ---- .../ViewModels/Contracts/ISnoopViewModel.cs | 10 +- .../Dialogs/SearchElementsViewModel.cs | 106 ++++---- RevitLookup/ViewModels/Objects/UnitInfo.cs | 4 +- .../ViewModels/Pages/DashboardViewModel.cs | 76 ++++-- .../ViewModels/Pages/EventsViewModel.cs | 18 +- .../ViewModels/Pages/SnoopViewModel.cs | 59 +---- .../ViewModels/Pages/SnoopViewModelBase.cs | 75 ++---- RevitLookup/Views/Dialogs/UnitsDialog.xaml.cs | 27 +- RevitLookup/Views/Pages/SnoopView.xaml.cs | 4 +- RevitLookup/Views/Resources/Menus.xaml.cs | 2 +- RevitLookup/Views/RevitLookupView.xaml.cs | 44 +--- 63 files changed, 1210 insertions(+), 827 deletions(-) create mode 100644 RevitLookup.UI.Demo/HostProvider.cs delete mode 100644 RevitLookup.UI.Demo/Moq/MoqSnoopViewModel.cs create mode 100644 RevitLookup.UI.Demo/Services/MoqLookupService.cs create mode 100644 RevitLookup.UI.Demo/Services/MoqSnoopService.cs create mode 100644 RevitLookup.UI.Demo/ViewModels/MoqSnoopViewModel.cs delete mode 100644 RevitLookup/Services/Contracts/IWindowController.cs create mode 100644 RevitLookup/Services/LookupService.cs create mode 100644 RevitLookup/Services/NotificationService.cs create mode 100644 RevitLookup/Services/SnoopService.cs delete mode 100644 RevitLookup/Services/WindowController.cs diff --git a/RevitLookup.UI.Demo/App.xaml.cs b/RevitLookup.UI.Demo/App.xaml.cs index e864d032b..ef8a8f3d6 100644 --- a/RevitLookup.UI.Demo/App.xaml.cs +++ b/RevitLookup.UI.Demo/App.xaml.cs @@ -1,25 +1,29 @@ -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. -// Copyright (C) Leszek Pomianowski and WPF UI Contributors. -// All Rights Reserved. +// Copyright 2003-2023 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. -using System.Diagnostics; using System.IO; using System.Reflection; -using System.Runtime.Versioning; using System.Windows; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using RevitLookup.Services; using RevitLookup.Services.Contracts; -using RevitLookup.UI.Demo.Moq; -using RevitLookup.Utils; -using RevitLookup.ViewModels.Pages; -using RevitLookup.Views; +using RevitLookup.UI.Demo.Services; using RevitLookup.Views.Pages; -using Wpf.Ui.Contracts; -using Wpf.Ui.Services; namespace RevitLookup.UI.Demo; @@ -30,12 +34,10 @@ public sealed partial class App private void OnStartup(object sender, StartupEventArgs e) { AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve; - var host = CreateHost(); - Host.StartHost(host); + var host = HostProvider.CreateHost(); - var window = Host.GetService(); - window.Show(); - window.ServiceProvider.GetService().Navigate(typeof(DashboardView)); + Host.StartHost(host); + Host.GetService().Show(); } private void OnExit(object sender, ExitEventArgs e) @@ -46,66 +48,6 @@ private void OnExit(object sender, ExitEventArgs e) Host.StopHost(); } - private static IHost CreateHost() - { - var host = Microsoft.Extensions.Hosting.Host - .CreateDefaultBuilder() - .ConfigureAppConfiguration(builder => - { - var assembly = Assembly.GetExecutingAssembly(); - var assemblyLocation = assembly.Location; - var addinVersion = FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion; -#if RELEASE - var version = addinVersion.Split('.')[0]; - if (version == "1") version = "Develop"; - var programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - var userDataLocation = Path.Combine(programDataPath, @"Autodesk\Revit\Addins\", version, "RevitLookup"); -#else - var userDataLocation = Path.GetDirectoryName(assemblyLocation)!; -#endif - var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); - var writeAccess = AccessUtils.CheckWriteAccess(assemblyLocation) && !assemblyLocation.StartsWith(appDataPath); - - var targetFrameworkAttributes = assembly.GetCustomAttributes(typeof(TargetFrameworkAttribute), true); - var targetFrameworkAttribute = (TargetFrameworkAttribute) targetFrameworkAttributes.First(); - var targetFramework = targetFrameworkAttribute.FrameworkDisplayName; - - builder.AddInMemoryCollection(new KeyValuePair[] - { - new("Assembly", assemblyLocation), - new("Framework", targetFramework), - new("AddinVersion", addinVersion), - new("ConfigFolder", Path.Combine(userDataLocation, "Config")), - new("DownloadFolder", Path.Combine(userDataLocation, "Downloads")), - new("FolderAccess", writeAccess ? "Write" : "Read") - }); - }) - .ConfigureServices((_, services) => - { - services.AddSingleton(); - services.AddSingleton(); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddTransient(); - }).Build(); - return host; - } - private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) { var assemblyName = new AssemblyName(args.Name); diff --git a/RevitLookup.UI.Demo/HostProvider.cs b/RevitLookup.UI.Demo/HostProvider.cs new file mode 100644 index 000000000..7355574d2 --- /dev/null +++ b/RevitLookup.UI.Demo/HostProvider.cs @@ -0,0 +1,91 @@ +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.Versioning; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using RevitLookup.Services; +using RevitLookup.Services.Contracts; +using RevitLookup.UI.Demo.Services; +using RevitLookup.Utils; +using RevitLookup.ViewModels.Contracts; +using RevitLookup.ViewModels.Pages; +using RevitLookup.Views; +using RevitLookup.Views.Pages; +using Wpf.Ui.Contracts; +using Wpf.Ui.Services; +using MoqSnoopViewModel = RevitLookup.UI.Demo.ViewModels.MoqSnoopViewModel; + +namespace RevitLookup.UI.Demo; + +public static class HostProvider +{ + public static IHost CreateHost() + { + var host = Microsoft.Extensions.Hosting.Host + .CreateDefaultBuilder() + .ConfigureAppConfiguration(SetConfiguration) + .ConfigureServices(AddServices) + .Build(); + + return host; + } + + private static void AddServices(HostBuilderContext _, IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddTransient(); + } + + private static void SetConfiguration(IConfigurationBuilder builder) + { + var assembly = Assembly.GetExecutingAssembly(); + var assemblyLocation = assembly.Location; + var addinVersion = FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion; +#if RELEASE + var version = addinVersion.Split('.')[0]; + if (version == "1") version = "Develop"; + var programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var userDataLocation = Path.Combine(programDataPath, @"Autodesk\Revit\Addins\", version, "RevitLookup"); +#else + var userDataLocation = Path.GetDirectoryName(assemblyLocation)!; +#endif + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); + var writeAccess = AccessUtils.CheckWriteAccess(assemblyLocation) && !assemblyLocation.StartsWith(appDataPath); + + var targetFrameworkAttributes = assembly.GetCustomAttributes(typeof(TargetFrameworkAttribute), true); + var targetFrameworkAttribute = (TargetFrameworkAttribute) targetFrameworkAttributes.First(); + var targetFramework = targetFrameworkAttribute.FrameworkDisplayName; + + builder.AddInMemoryCollection(new KeyValuePair[] + { + new("Assembly", assemblyLocation), + new("Framework", targetFramework), + new("AddinVersion", addinVersion), + new("ConfigFolder", Path.Combine(userDataLocation, "Config")), + new("DownloadFolder", Path.Combine(userDataLocation, "Downloads")), + new("FolderAccess", writeAccess ? "Write" : "Read") + }); + } +} \ No newline at end of file diff --git a/RevitLookup.UI.Demo/Moq/MoqSnoopViewModel.cs b/RevitLookup.UI.Demo/Moq/MoqSnoopViewModel.cs deleted file mode 100644 index abdc77fbd..000000000 --- a/RevitLookup.UI.Demo/Moq/MoqSnoopViewModel.cs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2003-2023 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using Autodesk.Revit.DB; -using Bogus; -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using Microsoft.Extensions.DependencyInjection; -using RevitLookup.Core.Contracts; -using RevitLookup.Core.Objects; -using RevitLookup.Core.Utils; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.ViewModels.Contracts; -using RevitLookup.ViewModels.Enums; -using RevitLookup.ViewModels.Utils; -using RevitLookup.Views.Pages; -using Wpf.Ui.Common; -using Wpf.Ui.Contracts; -using Wpf.Ui.Controls; - -namespace RevitLookup.UI.Demo.Moq; - -public sealed partial class MoqSnoopViewModel : ObservableObject, ISnoopViewModel -{ - private readonly INavigationService _navigationService; - private readonly ISnackbarService _snackbarService; - private CancellationTokenSource _searchCancellationToken = new(); - [ObservableProperty] private string _searchText = string.Empty; - [ObservableProperty] private IReadOnlyCollection _snoopableObjects = Array.Empty(); - [ObservableProperty] private IReadOnlyCollection _filteredSnoopableObjects = Array.Empty(); - [ObservableProperty] private IReadOnlyCollection _snoopableData; - [ObservableProperty] private IReadOnlyCollection _filteredSnoopableData; - - public MoqSnoopViewModel(ISnackbarService snackbarService, INavigationService navigationService) - { - _snackbarService = snackbarService; - _navigationService = navigationService; - } - - public SnoopableObject SelectedObject { get; set; } - - public void Snoop(SnoopableObject snoopableObject) - { - if (snoopableObject.Descriptor is IDescriptorEnumerator {IsEmpty: false} descriptor) - SnoopableObjects = descriptor.ParseEnumerable(snoopableObject); - else - SnoopableObjects = new[] {snoopableObject}; - - _navigationService.Navigate(typeof(SnoopView)); - } - - public async Task Snoop(SnoopableType snoopableType) - { - int generationCount; - switch (snoopableType) - { - case SnoopableType.View: - generationCount = 50_000; - break; - case SnoopableType.Document: - generationCount = 10_000; - break; - case SnoopableType.Application: - generationCount = 5_000; - break; - case SnoopableType.UiApplication: - generationCount = 1_000; - break; - case SnoopableType.Database: - generationCount = 500; - break; - case SnoopableType.DependentElements: - generationCount = 100; - break; - case SnoopableType.Selection: - generationCount = 50; - break; - case SnoopableType.LinkedElement: - generationCount = 10; - break; - case SnoopableType.Face: - generationCount = 5; - break; - case SnoopableType.Edge: - generationCount = 3; - break; - case SnoopableType.Point: - generationCount = 2; - break; - case SnoopableType.SubElement: - generationCount = 1; - break; - case SnoopableType.ComponentManager: - case SnoopableType.PerformanceAdviser: - case SnoopableType.UpdaterRegistry: - case SnoopableType.Services: - case SnoopableType.Schemas: - case SnoopableType.Events: - generationCount = 0; - break; - default: - throw new ArgumentOutOfRangeException(nameof(snoopableType), snoopableType, null); - } - - SnoopableObjects = generationCount == 0 - ? Array.Empty() - : await Task.Run(() => - { - return new Faker() - .CustomInstantiator(faker => - { - if (faker.IndexFaker == 0) - return new SnoopableObject(null, faker.Lorem.Word()); - if (faker.IndexFaker % 1000 == 0) - return new SnoopableObject(null, faker.Make(150, () => faker.Internet.UserName())); - if (faker.IndexFaker % 700 == 0) - return new SnoopableObject(typeof(Console)); - if (faker.IndexFaker % 500 == 0) - return new SnoopableObject(null, null); - if (faker.IndexFaker % 200 == 0) - return new SnoopableObject(null, string.Empty); - if (faker.IndexFaker % 100 == 0) - return new SnoopableObject(null, new Color(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte())); - if (faker.IndexFaker % 5 == 0) - return new SnoopableObject(null, faker.Random.Int(0)); - if (faker.IndexFaker % 3 == 0) - return new SnoopableObject(null, faker.Random.Bool()); - - return new SnoopableObject(null, faker.Lorem.Word()); - }) - .Generate(generationCount); - }); - - SnoopableData = Array.Empty(); - _navigationService.Navigate(typeof(SnoopView)); - } - - public void Navigate(Descriptor selectedItem) - { - if (selectedItem.Value.Descriptor is not IDescriptorCollector or IDescriptorEnumerator {IsEmpty: true}) return; - - var window = Host.GetService(); - window.Show(); - window.ServiceProvider.GetService()!.Snoop(selectedItem.Value); - } - - partial void OnSearchTextChanged(string value) - { - UpdateSearchResults(SearchOption.Objects); - } - - partial void OnSnoopableObjectsChanged(IReadOnlyCollection value) - { - SelectedObject = null; - UpdateSearchResults(SearchOption.Objects); - } - - partial void OnSnoopableDataChanged(IReadOnlyCollection value) - { - UpdateSearchResults(SearchOption.Selection); - } - - private async void UpdateSearchResults(SearchOption option) - { - _searchCancellationToken.Cancel(); - _searchCancellationToken = new CancellationTokenSource(); - - if (string.IsNullOrEmpty(SearchText)) - { - FilteredSnoopableObjects = SnoopableObjects; - FilteredSnoopableData = SnoopableData; - return; - } - - try - { - var results = await SearchEngine.SearchAsync(this, option, _searchCancellationToken.Token); - if (results.Data is not null) FilteredSnoopableData = results.Data; - if (results.Objects is not null) FilteredSnoopableObjects = results.Objects; - } - catch (OperationCanceledException) - { - //Ignored - } - } - - [RelayCommand] - private async Task FetchMembersAsync() - { - await CollectMembers(true); - } - - [RelayCommand] - private async Task RefreshMembersAsync() - { - await CollectMembers(false); - } - - private async Task CollectMembers(bool useCached) - { - if (SelectedObject is null) - { - SnoopableData = Array.Empty(); - return; - } - - try - { - // ReSharper disable once MethodHasAsyncOverload - SnoopableData = SelectedObject.GetMembers(); - } - catch (Exception exception) - { - await _snackbarService.ShowAsync("Snoop engine error", exception.Message, SymbolRegular.ErrorCircle24, ControlAppearance.Danger); - } - } -} \ No newline at end of file diff --git a/RevitLookup.UI.Demo/Services/MoqLookupService.cs b/RevitLookup.UI.Demo/Services/MoqLookupService.cs new file mode 100644 index 000000000..cdb8cebcb --- /dev/null +++ b/RevitLookup.UI.Demo/Services/MoqLookupService.cs @@ -0,0 +1,111 @@ +// Copyright 2003-2023 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Controls; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Core.Objects; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using Wpf.Ui.Contracts; + +namespace RevitLookup.UI.Demo.Services; + +public class MoqLookupService +{ + private Window _owner; + private Task _activeTask; + private readonly IServiceProvider _serviceProvider; + + public MoqLookupService(IServiceScopeFactory scopeFactory) + { + _serviceProvider = scopeFactory.CreateScope().ServiceProvider; + } + + public MoqLookupService Snoop(SnoopableType snoopableType) + { + _activeTask = _serviceProvider.GetService()!.SnoopAsync(snoopableType); + return this; + } + + public MoqLookupService Snoop(SnoopableObject snoopableObject) + { + _serviceProvider.GetService()!.Snoop(snoopableObject); + return this; + } + + public MoqLookupService Attach(IWindow window) + { + _owner = (Window) window; + return this; + } + + public MoqLookupService Show() where T : Page + { + if (_activeTask is null) + { + ShowPage(); + } + else + { + _activeTask = _activeTask.ContinueWith(_ => ShowPage(), TaskScheduler.FromCurrentSynchronizationContext()); + } + + return this; + + void ShowPage() + { + var window = (Window) _serviceProvider.GetService(); + + if (_owner is null) + { + window.WindowStartupLocation = WindowStartupLocation.CenterScreen; + } + else + { + window.Left = _owner.Left + 47; + window.Top = _owner.Top + 49; + } + + window.Show(); + _serviceProvider.GetService().Navigate(typeof(T)); + } + } + + public void Execute(Action handler) where T : class + { + if (_activeTask is null) + { + InvokeHandler(); + } + else + { + _activeTask = _activeTask.ContinueWith(_ => InvokeHandler(), TaskScheduler.FromCurrentSynchronizationContext()); + } + + return; + + void InvokeHandler() + { + var service = _serviceProvider.GetService(); + handler.Invoke(service); + } + } +} \ No newline at end of file diff --git a/RevitLookup.UI.Demo/Services/MoqSnoopService.cs b/RevitLookup.UI.Demo/Services/MoqSnoopService.cs new file mode 100644 index 000000000..1e569480d --- /dev/null +++ b/RevitLookup.UI.Demo/Services/MoqSnoopService.cs @@ -0,0 +1,133 @@ +// Copyright 2003-2023 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB; +using Bogus; +using RevitLookup.Core.Contracts; +using RevitLookup.Core.Objects; +using RevitLookup.Core.Utils; +using RevitLookup.Services; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.ViewModels.Contracts; +using Visibility = System.Windows.Visibility; + +namespace RevitLookup.UI.Demo.Services; + +public class MoqSnoopService : ISnoopService +{ + private readonly NotificationService _notificationService; + private readonly ISnoopViewModel _viewModel; + private readonly IWindow _window; + + public MoqSnoopService(NotificationService notificationService, ISnoopViewModel viewModel, IWindow window) + { + _notificationService = notificationService; + _viewModel = viewModel; + _window = window; + } + + public void Snoop(SnoopableObject snoopableObject) + { + try + { + if (snoopableObject.Descriptor is IDescriptorEnumerator {IsEmpty: false} descriptor) + { + _viewModel.SnoopableObjects = descriptor.ParseEnumerable(snoopableObject); + } + else + { + _viewModel.SnoopableObjects = new[] {snoopableObject}; + } + } + catch (Exception exception) + { + _notificationService.ShowError("Invalid object", exception); + } + } + + public async Task SnoopAsync(SnoopableType snoopableType) + { + switch (snoopableType) + { + case SnoopableType.Face: + case SnoopableType.Edge: + case SnoopableType.LinkedElement: + case SnoopableType.Point: + case SnoopableType.SubElement: + UpdateWindowVisibility(Visibility.Hidden); + await Task.Delay(TimeSpan.FromSeconds(2)); + break; + } + + var generationCount = snoopableType switch + { + SnoopableType.View => 50_000, + SnoopableType.Document => 25_000, + SnoopableType.Application => 10_000, + SnoopableType.UiApplication => 5_000, + SnoopableType.Database => 2_000, + SnoopableType.DependentElements => 1_000, + SnoopableType.Selection => 500, + SnoopableType.LinkedElement => 250, + SnoopableType.Face => 125, + SnoopableType.Edge => 60, + SnoopableType.Point => 30, + SnoopableType.SubElement => 15, + SnoopableType.ComponentManager => 8, + SnoopableType.PerformanceAdviser => 4, + SnoopableType.UpdaterRegistry => 2, + SnoopableType.Services => 1, + SnoopableType.Schemas => 0, + _ => throw new ArgumentOutOfRangeException(nameof(snoopableType), snoopableType, null) + }; + + _viewModel.SnoopableObjects = await GenerateObjectsAsync(generationCount); + _viewModel.SnoopableData = Array.Empty(); + UpdateWindowVisibility(Visibility.Visible); + } + + private void UpdateWindowVisibility(Visibility visibility) + { + if (!_window.IsLoaded) return; + + _window.Visibility = visibility; + } + + private static async Task> GenerateObjectsAsync(int generationCount) + { + if (generationCount == 0) return Array.Empty(); + + return await Task.Run(() => new Faker() + .CustomInstantiator(faker => + { + if (faker.IndexFaker % 1000 == 0) return new SnoopableObject(faker.Make(150, () => faker.Internet.UserName())); + if (faker.IndexFaker % 700 == 0) return new SnoopableObject(typeof(Console)); + if (faker.IndexFaker % 500 == 0) return new SnoopableObject(null); + if (faker.IndexFaker % 200 == 0) return new SnoopableObject(string.Empty); + if (faker.IndexFaker % 100 == 0) return new SnoopableObject(new Color(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte())); + if (faker.IndexFaker % 5 == 0) return new SnoopableObject(faker.Random.Int(0)); + if (faker.IndexFaker % 3 == 0) return new SnoopableObject(faker.Random.Bool()); + + return new SnoopableObject(faker.Lorem.Word()); + }) + .Generate(generationCount)); + } +} \ No newline at end of file diff --git a/RevitLookup.UI.Demo/ViewModels/MoqSnoopViewModel.cs b/RevitLookup.UI.Demo/ViewModels/MoqSnoopViewModel.cs new file mode 100644 index 000000000..f95db997e --- /dev/null +++ b/RevitLookup.UI.Demo/ViewModels/MoqSnoopViewModel.cs @@ -0,0 +1,138 @@ +// Copyright 2003-2023 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using RevitLookup.Core.Contracts; +using RevitLookup.Core.Objects; +using RevitLookup.Services; +using RevitLookup.Services.Contracts; +using RevitLookup.UI.Demo.Services; +using RevitLookup.ViewModels.Contracts; +using RevitLookup.ViewModels.Enums; +using RevitLookup.ViewModels.Utils; +using RevitLookup.Views.Pages; + +namespace RevitLookup.UI.Demo.ViewModels; + +public sealed partial class MoqSnoopViewModel : ObservableObject, ISnoopViewModel +{ + private readonly IWindow _window; + private readonly NotificationService _notificationService; + private CancellationTokenSource _searchCancellationToken = new(); + + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private IReadOnlyCollection _snoopableObjects = Array.Empty(); + [ObservableProperty] private IReadOnlyCollection _filteredSnoopableObjects = Array.Empty(); + [ObservableProperty] private IReadOnlyCollection _snoopableData; + [ObservableProperty] private IReadOnlyCollection _filteredSnoopableData; + + public MoqSnoopViewModel(NotificationService notificationService, IWindow window) + { + _notificationService = notificationService; + _window = window; + } + + public SnoopableObject SelectedObject { get; set; } + + public void Navigate(Descriptor selectedItem) + { + if (selectedItem.Value.Descriptor is not IDescriptorCollector) return; + if (selectedItem.Value.Descriptor is IDescriptorEnumerator {IsEmpty: true}) return; + + Host.GetService() + .Snoop(selectedItem.Value) + .Attach(_window) + .Show(); + } + + partial void OnSearchTextChanged(string value) + { + UpdateSearchResults(SearchOption.Objects); + } + + partial void OnSnoopableObjectsChanged(IReadOnlyCollection value) + { + SelectedObject = null; + UpdateSearchResults(SearchOption.Objects); + } + + partial void OnSnoopableDataChanged(IReadOnlyCollection value) + { + UpdateSearchResults(SearchOption.Selection); + } + + private async void UpdateSearchResults(SearchOption option) + { + _searchCancellationToken.Cancel(); + _searchCancellationToken = new CancellationTokenSource(); + + if (string.IsNullOrEmpty(SearchText)) + { + FilteredSnoopableObjects = SnoopableObjects; + FilteredSnoopableData = SnoopableData; + return; + } + + try + { + var results = await SearchEngine.SearchAsync(this, option, _searchCancellationToken.Token); + if (results.Data is not null) FilteredSnoopableData = results.Data; + if (results.Objects is not null) FilteredSnoopableObjects = results.Objects; + } + catch (OperationCanceledException) + { + //Ignored + } + } + + [RelayCommand] + private Task FetchMembersAsync() + { + CollectMembers(true); + return Task.CompletedTask; + } + + [RelayCommand] + private Task RefreshMembersAsync() + { + CollectMembers(false); + return Task.CompletedTask; + } + + private void CollectMembers(bool useCached) + { + if (SelectedObject is null) + { + SnoopableData = Array.Empty(); + return; + } + + try + { + // ReSharper disable once MethodHasAsyncOverload + SnoopableData = SelectedObject.GetMembers(); + } + catch (Exception exception) + { + _notificationService.ShowError("Snoop engine error", exception); + } + } +} \ No newline at end of file diff --git a/RevitLookup.sln.DotSettings b/RevitLookup.sln.DotSettings index 89e8e1e36..ce29fdbf9 100644 --- a/RevitLookup.sln.DotSettings +++ b/RevitLookup.sln.DotSettings @@ -1,5 +1,5 @@  - Copyright 2003-$CREATED_YEAR$ by Autodesk, Inc. + Copyright 2003-$File.CreatedYear by Autodesk, Inc. Permission to use, copy, modify, and distribute this software in object code form for any purpose and without fee is hereby granted, @@ -18,6 +18,7 @@ Use, duplication, or disclosure by the U.S. Government is subject to restrictions set forth in FAR 52.227-19 (Commercial Computer Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) (Rights in Technical Data and Computer Software), as applicable. + True True True True diff --git a/RevitLookup/Commands/DashboardCommand.cs b/RevitLookup/Commands/DashboardCommand.cs index 46a5e603a..91cf3fca6 100644 --- a/RevitLookup/Commands/DashboardCommand.cs +++ b/RevitLookup/Commands/DashboardCommand.cs @@ -21,6 +21,7 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Views.Pages; using Wpf.Ui.Contracts; @@ -33,11 +34,6 @@ public class DashboardCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.ShowAttached(); - window.ServiceProvider.GetService().Navigate(typeof(DashboardView)); - }); + Host.GetService().Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/EventMonitorCommand.cs b/RevitLookup/Commands/EventMonitorCommand.cs index 0c89b72e8..e0af69d58 100644 --- a/RevitLookup/Commands/EventMonitorCommand.cs +++ b/RevitLookup/Commands/EventMonitorCommand.cs @@ -19,11 +19,9 @@ // (Rights in Technical Data and Computer Software), as applicable. using Autodesk.Revit.Attributes; -using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; +using RevitLookup.Services; using RevitLookup.Views.Pages; -using Wpf.Ui.Contracts; namespace RevitLookup.Commands; @@ -33,11 +31,6 @@ public class EventMonitorCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.ShowAttached(); - window.ServiceProvider.GetService().Navigate(typeof(EventsView)); - }); + Host.GetService().Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SearchElementsCommand.cs b/RevitLookup/Commands/SearchElementsCommand.cs index d9b52ea1c..597ad36d9 100644 --- a/RevitLookup/Commands/SearchElementsCommand.cs +++ b/RevitLookup/Commands/SearchElementsCommand.cs @@ -21,7 +21,9 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; using RevitLookup.ViewModels.Pages; using RevitLookup.Views.Pages; using Wpf.Ui.Contracts; @@ -34,12 +36,11 @@ public class SearchElementsCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.ShowAttached(); - window.ServiceProvider.GetService().Navigate(typeof(DashboardView)); - window.ServiceProvider.GetService().OpenDialogCommand.Execute("search"); - }); + Host.GetService() + .Show() + .Execute(dashboard => + { + dashboard.OpenDialogCommand.Execute("search"); + }); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopDatabaseCommand.cs b/RevitLookup/Commands/SnoopDatabaseCommand.cs index 8a34375fe..bee6ef74d 100644 --- a/RevitLookup/Commands/SnoopDatabaseCommand.cs +++ b/RevitLookup/Commands/SnoopDatabaseCommand.cs @@ -21,8 +21,11 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.ViewModels.Pages; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +35,8 @@ public class SnoopDatabaseCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.Database); - }); + Host.GetService() + .Snoop(SnoopableType.Database) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopDocumentCommand.cs b/RevitLookup/Commands/SnoopDocumentCommand.cs index 76d4dcda6..64d8e1d11 100644 --- a/RevitLookup/Commands/SnoopDocumentCommand.cs +++ b/RevitLookup/Commands/SnoopDocumentCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopDocumentCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.Document); - }); + Host.GetService() + .Snoop(SnoopableType.Document) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopEdgeCommand.cs b/RevitLookup/Commands/SnoopEdgeCommand.cs index 1982e1692..ac64f4f59 100644 --- a/RevitLookup/Commands/SnoopEdgeCommand.cs +++ b/RevitLookup/Commands/SnoopEdgeCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopEdgeCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.Edge); - }); + Host.GetService() + .Snoop(SnoopableType.Edge) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopFaceCommand.cs b/RevitLookup/Commands/SnoopFaceCommand.cs index e0f98016e..63159fe33 100644 --- a/RevitLookup/Commands/SnoopFaceCommand.cs +++ b/RevitLookup/Commands/SnoopFaceCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopFaceCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.Face); - }); + Host.GetService() + .Snoop(SnoopableType.Face) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopLinkedElementCommand.cs b/RevitLookup/Commands/SnoopLinkedElementCommand.cs index 46f929e40..b6e371240 100644 --- a/RevitLookup/Commands/SnoopLinkedElementCommand.cs +++ b/RevitLookup/Commands/SnoopLinkedElementCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopLinkedElementCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.LinkedElement); - }); + Host.GetService() + .Snoop(SnoopableType.LinkedElement) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopPointCommand.cs b/RevitLookup/Commands/SnoopPointCommand.cs index e5c714960..2c4756c70 100644 --- a/RevitLookup/Commands/SnoopPointCommand.cs +++ b/RevitLookup/Commands/SnoopPointCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopPointCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.Point); - }); + Host.GetService() + .Snoop(SnoopableType.Point) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopSelectionCommand.cs b/RevitLookup/Commands/SnoopSelectionCommand.cs index df4310d43..08af4fcb6 100644 --- a/RevitLookup/Commands/SnoopSelectionCommand.cs +++ b/RevitLookup/Commands/SnoopSelectionCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopSelectionCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.Selection); - }); + Host.GetService() + .Snoop(SnoopableType.Selection) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopSubElementCommand.cs b/RevitLookup/Commands/SnoopSubElementCommand.cs index 0fe408222..8f91c41a9 100644 --- a/RevitLookup/Commands/SnoopSubElementCommand.cs +++ b/RevitLookup/Commands/SnoopSubElementCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopSubElementCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.SubElement); - }); + Host.GetService() + .Snoop(SnoopableType.SubElement) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Commands/SnoopViewCommand.cs b/RevitLookup/Commands/SnoopViewCommand.cs index 52a817fe6..c9c09a580 100644 --- a/RevitLookup/Commands/SnoopViewCommand.cs +++ b/RevitLookup/Commands/SnoopViewCommand.cs @@ -21,8 +21,10 @@ using Autodesk.Revit.Attributes; using Microsoft.Extensions.DependencyInjection; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; namespace RevitLookup.Commands; @@ -32,11 +34,8 @@ public class SnoopViewCommand : ExternalCommand { public override void Execute() { - RevitLookup.Application.Raise(() => - { - var window = Host.GetService(); - window.Initialize(); - window.ServiceProvider.GetService()!.Snoop(SnoopableType.View); - }); + Host.GetService() + .Snoop(SnoopableType.View) + .Show(); } } \ No newline at end of file diff --git a/RevitLookup/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs index fa2baf332..b3cc52b7c 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs @@ -24,7 +24,7 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class DefinitionBindingMapIteratorDescriptor : Descriptor, IDescriptorRedirection +public sealed class DefinitionBindingMapIteratorDescriptor : Descriptor, IDescriptorRedirection { private readonly object _object; diff --git a/RevitLookup/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs index e103b2780..82b325075 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs @@ -26,7 +26,7 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class DependencyObjectDescriptor : Descriptor, IDescriptorResolver +public sealed class DependencyObjectDescriptor : Descriptor, IDescriptorResolver { public ResolveSet Resolve(Document context, string target, ParameterInfo[] parameters) { diff --git a/RevitLookup/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs index 8759f7611..1c0032590 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs @@ -25,7 +25,7 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class EnumeratorDescriptor : Descriptor, IDescriptorRedirection +public sealed class EnumeratorDescriptor : Descriptor, IDescriptorRedirection { private readonly object _object; diff --git a/RevitLookup/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs index dd308ced2..48c7f470c 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs @@ -25,7 +25,7 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class FamilyManagerDescriptor : Descriptor, IDescriptorResolver +public sealed class FamilyManagerDescriptor : Descriptor, IDescriptorResolver { private readonly FamilyManager _familyManager; diff --git a/RevitLookup/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs index b1d244684..c755ae423 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs @@ -25,7 +25,7 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class ReferenceDescriptor : Descriptor, IDescriptorResolver +public sealed class ReferenceDescriptor : Descriptor, IDescriptorResolver { private readonly Reference _reference; diff --git a/RevitLookup/Core/ComponentModel/Descriptors/StringDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/StringDescriptor.cs index cac79495c..1aeb61707 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/StringDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/StringDescriptor.cs @@ -20,7 +20,7 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class StringDescriptor : EnumerableDescriptor +public sealed class StringDescriptor : EnumerableDescriptor { public StringDescriptor(string text) : base(text) { diff --git a/RevitLookup/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs index a244b372e..21b018207 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs @@ -23,6 +23,6 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class UiObjectDescriptor : Descriptor, IDescriptorCollector +public sealed class UiObjectDescriptor : Descriptor, IDescriptorCollector { } \ No newline at end of file diff --git a/RevitLookup/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs b/RevitLookup/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs index 9c682077e..287811a6e 100644 --- a/RevitLookup/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs +++ b/RevitLookup/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs @@ -25,7 +25,7 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; -public class WorksetTableDescriptor : Descriptor, IDescriptorResolver +public sealed class WorksetTableDescriptor : Descriptor, IDescriptorResolver { public ResolveSet Resolve(Document context, string target, ParameterInfo[] parameters) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Api.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Api.cs index 1728f931f..282609b79 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Api.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Api.cs @@ -23,7 +23,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { public static IReadOnlyCollection Build(Type type) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Build.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Build.cs index ce2ecd77f..d2aa0cdc3 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Build.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Build.cs @@ -24,7 +24,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private IReadOnlyCollection BuildInstanceObject(Type type) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Enumeration.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Enumeration.cs index 8e6fd79da..f81afd711 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Enumeration.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Enumeration.cs @@ -22,7 +22,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private void AddEnumerableItems() { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Events.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Events.cs index 3cedf6ad6..644610740 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Events.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Events.cs @@ -3,7 +3,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private void AddEvents(BindingFlags bindingFlags) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Extensions.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Extensions.cs index 69f6c7f92..513392942 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Extensions.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Extensions.cs @@ -23,7 +23,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder : IExtensionManager +public sealed partial class DescriptorBuilder : IExtensionManager { private void AddExtensions() { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Fields.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Fields.cs index e6d179890..e697ba0cc 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Fields.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Fields.cs @@ -22,7 +22,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private void AddFields(BindingFlags bindingFlags) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Methods.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Methods.cs index e77937bf9..13dba584b 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Methods.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Methods.cs @@ -23,7 +23,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private void AddMethods(BindingFlags bindingFlags) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Properties.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Properties.cs index fab4991ea..3cdc121ca 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Properties.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Properties.cs @@ -23,7 +23,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private void AddProperties(BindingFlags bindingFlags) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.Write.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.Write.cs index 8a34104d7..9177e4fc6 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.Write.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.Write.cs @@ -26,7 +26,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private void WriteDescriptor(object value) { diff --git a/RevitLookup/Core/Metadata/DescriptorBuilder.cs b/RevitLookup/Core/Metadata/DescriptorBuilder.cs index 218d45c65..0052100cb 100644 --- a/RevitLookup/Core/Metadata/DescriptorBuilder.cs +++ b/RevitLookup/Core/Metadata/DescriptorBuilder.cs @@ -25,7 +25,7 @@ namespace RevitLookup.Core.Metadata; -public partial class DescriptorBuilder +public sealed partial class DescriptorBuilder { private readonly List _descriptors; private readonly Stopwatch _tracker = new(); diff --git a/RevitLookup/Core/Objects/SnoopableObject.cs b/RevitLookup/Core/Objects/SnoopableObject.cs index 8eb936364..5d5dd4f63 100644 --- a/RevitLookup/Core/Objects/SnoopableObject.cs +++ b/RevitLookup/Core/Objects/SnoopableObject.cs @@ -61,7 +61,7 @@ public IReadOnlyCollection GetMembers() public async Task> GetMembersAsync() { - return _members = await Application.ExternalDescriptorHandler.RaiseAsync(GetMembersAsync); + return _members = await Application.ExternalDescriptorHandler.RaiseAsync(GetMembers); } public async Task> GetCachedMembersAsync() @@ -69,7 +69,7 @@ public async Task> GetCachedMembersAsync() return _members ?? await GetMembersAsync(); } - private IReadOnlyCollection GetMembersAsync(UIApplication uiApplication) + private IReadOnlyCollection GetMembers(UIApplication uiApplication) { return DescriptorBuilder.Build(Object, Context); } diff --git a/RevitLookup/Core/RevitApi.cs b/RevitLookup/Core/RevitApi.cs index b4696fc06..c9bb06b81 100644 --- a/RevitLookup/Core/RevitApi.cs +++ b/RevitLookup/Core/RevitApi.cs @@ -19,6 +19,7 @@ // (Rights in Technical Data and Computer Software), as applicable. using System.Reflection; +using System.Runtime.InteropServices; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using RevitLookup.ViewModels.Objects; @@ -49,10 +50,10 @@ public static List GetUnitInfos(Type unitType) { var parameters = Enum.GetValues(unitType).Cast(); var list = new List(); - foreach (var builtInParameter in parameters) + foreach (var parameter in parameters) try { - list.Add(new UnitInfo(builtInParameter.ToString(), builtInParameter.ToLabel())); + list.Add(new UnitInfo(parameter, parameter.ToString(), parameter.ToLabel())); } catch { @@ -70,7 +71,7 @@ public static List GetUnitInfos(Type unitType) foreach (var category in categories) try { - list.Add(new UnitInfo(category.ToString(), category.ToLabel())); + list.Add(new UnitInfo(category, category.ToString(), category.ToLabel())); } catch { @@ -89,14 +90,66 @@ public static List GetUnitInfos(Type unitType) .Concat(SpecUtils.GetAllSpecs()) .Concat(ParameterUtils.GetAllBuiltInGroups()) .Concat(ParameterUtils.GetAllBuiltInParameters()) - .Select(typeId => new UnitInfo(typeId.TypeId, typeId.ToLabel())) + .Select(typeId => new UnitInfo(typeId, typeId.TypeId, typeId.ToLabel())) .ToList(); #else - return UnitUtils.GetAllUnits().Select(typeId => new UnitInfo(typeId.TypeId, typeId.ToUnitLabel())) - .Concat(UnitUtils.GetAllSpecs().Select(typeId => new UnitInfo(typeId.TypeId, typeId.ToSpecLabel()))) + return UnitUtils.GetAllUnits().Select(typeId => new UnitInfo(typeId, typeId.TypeId, typeId.ToUnitLabel())) + .Concat(UnitUtils.GetAllSpecs().Select(typeId => new UnitInfo(typeId, typeId.TypeId, typeId.ToSpecLabel()))) .ToList(); #endif throw new NotSupportedException(); } + + public static Parameter GetBuiltinParameter(BuiltInParameter builtInParameter) + { + const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; + + var documentType = typeof(Document); + var parameterType = typeof(Parameter); + var assembly = Assembly.GetAssembly(parameterType); + var aDocumentType = assembly.GetType("ADocument"); + var elementIdType = assembly.GetType("ElementId"); + var elementIdIdType = elementIdType.GetField("", bindingFlags)!; + var getADocumentType = documentType.GetMethod("getADocument", bindingFlags)!; + var parameterCtorType = parameterType.GetConstructor(bindingFlags, null, new[] {aDocumentType.MakePointerType(), elementIdType.MakePointerType()}, null)!; + + var elementId = Activator.CreateInstance(elementIdType); + elementIdIdType.SetValue(elementId, builtInParameter); + + var handle = GCHandle.Alloc(elementId); + var elementIdPointer = GCHandle.ToIntPtr(handle); + Marshal.StructureToPtr(elementId, elementIdPointer, true); + + var parameter = (Parameter) parameterCtorType.Invoke(new[] {getADocumentType.Invoke(Document, null), elementIdPointer}); + handle.Free(); + + return parameter; + } + + public static Category GetBuiltinCategory(BuiltInCategory builtInCategory) + { + const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; + + var documentType = typeof(Document); + var categoryType = typeof(Category); + var assembly = Assembly.GetAssembly(categoryType); + var aDocumentType = assembly.GetType("ADocument"); + var elementIdType = assembly.GetType("ElementId"); + var elementIdIdType = elementIdType.GetField("", bindingFlags)!; + var getADocumentType = documentType.GetMethod("getADocument", bindingFlags)!; + var categoryCtorType = categoryType.GetConstructor(bindingFlags, null, new[] {aDocumentType.MakePointerType(), elementIdType.MakePointerType()}, null)!; + + var elementId = Activator.CreateInstance(elementIdType); + elementIdIdType.SetValue(elementId, builtInCategory); + + var handle = GCHandle.Alloc(elementId); + var elementIdPointer = GCHandle.ToIntPtr(handle); + Marshal.StructureToPtr(elementId, elementIdPointer, true); + + var category = (Category) categoryCtorType.Invoke(new[] {getADocumentType.Invoke(Document, null), elementIdPointer}); + handle.Free(); + + return category; + } } \ No newline at end of file diff --git a/RevitLookup/Core/Selector.cs b/RevitLookup/Core/Selector.cs index e8f5798b3..39360c1c1 100644 --- a/RevitLookup/Core/Selector.cs +++ b/RevitLookup/Core/Selector.cs @@ -51,29 +51,28 @@ public static IReadOnlyCollection Snoop(SnoopableType type) SnoopableType.UpdaterRegistry => SnoopUpdaterRegistry(), SnoopableType.Services => SnoopServices(), SnoopableType.Schemas => SnoopSchemas(), - SnoopableType.Events => throw new NotSupportedException(), _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; } private static IReadOnlyCollection SnoopView() { - return new SnoopableObject[] {new(RevitApi.Document, RevitApi.ActiveView)}; + return new SnoopableObject[] {new(RevitApi.ActiveView)}; } private static IReadOnlyCollection SnoopDocument() { - return new SnoopableObject[] {new(RevitApi.Document, RevitApi.Document)}; + return new SnoopableObject[] {new(RevitApi.Document)}; } private static IReadOnlyCollection SnoopApplication() { - return new SnoopableObject[] {new(RevitApi.Document, RevitApi.Application)}; + return new SnoopableObject[] {new(RevitApi.Application)}; } private static IReadOnlyCollection SnoopUiApplication() { - return new SnoopableObject[] {new(RevitApi.Document, RevitApi.UiApplication)}; + return new SnoopableObject[] {new(RevitApi.UiApplication)}; } private static IReadOnlyCollection SnoopEdge() @@ -108,12 +107,12 @@ private static IReadOnlyCollection SnoopSelection() return RevitApi.Document .GetElements(selectedIds) .WherePasses(new ElementIdSetFilter(selectedIds)) - .Select(element => new SnoopableObject(RevitApi.Document, element)) + .Select(element => new SnoopableObject(element)) .ToList(); return RevitApi.Document .GetElements(RevitApi.ActiveView.Id) - .Select(element => new SnoopableObject(RevitApi.Document, element)) + .Select(element => new SnoopableObject(element)) .ToList(); } @@ -123,7 +122,7 @@ private static IReadOnlyCollection SnoopDatabase() var elementInstances = RevitApi.Document.GetElements().WhereElementIsNotElementType(); return elementTypes .UnionWith(elementInstances) - .Select(element => new SnoopableObject(RevitApi.Document, element)) + .Select(element => new SnoopableObject(element)) .ToList(); } @@ -143,7 +142,7 @@ private static IReadOnlyCollection SnoopDependentElements() return RevitApi.Document.GetElements() .WherePasses(new ElementIdSetFilter(elements)) - .Select(element => new SnoopableObject(RevitApi.Document, element)) + .Select(element => new SnoopableObject(element)) .ToList(); } @@ -154,22 +153,22 @@ private static IReadOnlyCollection SnoopComponentManager() private static IReadOnlyCollection SnoopPerformanceAdviser() { - return new[] {new SnoopableObject(RevitApi.Document, PerformanceAdviser.GetPerformanceAdviser())}; + return new[] {new SnoopableObject(PerformanceAdviser.GetPerformanceAdviser())}; } private static IReadOnlyCollection SnoopUpdaterRegistry() { - return UpdaterRegistry.GetRegisteredUpdaterInfos().Select(schema => new SnoopableObject(RevitApi.Document, schema)).ToArray(); + return UpdaterRegistry.GetRegisteredUpdaterInfos().Select(schema => new SnoopableObject(schema)).ToArray(); } private static IReadOnlyCollection SnoopSchemas() { - return Schema.ListSchemas().Select(schema => new SnoopableObject(RevitApi.Document, schema)).ToArray(); + return Schema.ListSchemas().Select(schema => new SnoopableObject(schema)).ToArray(); } private static IReadOnlyCollection SnoopServices() { - return ExternalServiceRegistry.GetServices().Select(service => new SnoopableObject(RevitApi.Document, service)).ToArray(); + return ExternalServiceRegistry.GetServices().Select(service => new SnoopableObject(service)).ToArray(); } private static SnoopableObject SelectObject(ObjectType objectType) @@ -177,33 +176,28 @@ private static SnoopableObject SelectObject(ObjectType objectType) var reference = RevitApi.UiDocument.Selection.PickObject(objectType); object element; - Document document; switch (objectType) { case ObjectType.Edge: case ObjectType.Face: - document = RevitApi.Document; - element = document.GetElement(reference).GetGeometryObjectFromReference(reference); + element = RevitApi.Document.GetElement(reference).GetGeometryObjectFromReference(reference); break; case ObjectType.Element: case ObjectType.Subelement: - document = RevitApi.Document; - element = document.GetElement(reference); + element = RevitApi.Document.GetElement(reference); break; case ObjectType.PointOnElement: - document = RevitApi.Document; element = reference.GlobalPoint; break; case ObjectType.LinkedElement: var revitLinkInstance = reference.ElementId.ToElement(RevitApi.Document); - document = revitLinkInstance.GetLinkDocument(); - element = document.GetElement(reference.LinkedElementId); + element = revitLinkInstance.GetLinkDocument().GetElement(reference.LinkedElementId); break; case ObjectType.Nothing: default: throw new NotSupportedException(); } - return new SnoopableObject(document, element); + return new SnoopableObject(element); } } \ No newline at end of file diff --git a/RevitLookup/Core/Utils/ContextUtils.cs b/RevitLookup/Core/Utils/ContextUtils.cs index 27fdd3354..5abb4c597 100644 --- a/RevitLookup/Core/Utils/ContextUtils.cs +++ b/RevitLookup/Core/Utils/ContextUtils.cs @@ -47,7 +47,7 @@ private static Document FindContext(object obj) return obj switch { Element element => element.Document, - Parameter parameter => parameter.Element.Document, + Parameter {Element: not null} parameter => parameter.Element.Document, Document document => document, _ => null }; diff --git a/RevitLookup/Host.cs b/RevitLookup/Host.cs index 8ec4d22cc..b040c78cf 100644 --- a/RevitLookup/Host.cs +++ b/RevitLookup/Host.cs @@ -8,6 +8,7 @@ using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Utils; +using RevitLookup.ViewModels.Contracts; using RevitLookup.ViewModels.Pages; using RevitLookup.Views; using RevitLookup.Views.Pages; @@ -24,61 +25,68 @@ public static void StartHost() { _host = Microsoft.Extensions.Hosting.Host .CreateDefaultBuilder() - .ConfigureAppConfiguration(builder => - { - var assembly = Assembly.GetExecutingAssembly(); - var assemblyLocation = assembly.Location; - var addinVersion = FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion; -#if RELEASE - var version = addinVersion.Split('.')[0]; - if (version == "1") version = "Develop"; - var programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - var userDataLocation = Path.Combine(programDataPath, @"Autodesk\Revit\Addins\", version, "RevitLookup"); -#else - var userDataLocation = Path.GetDirectoryName(assemblyLocation)!; -#endif - var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); - var writeAccess = AccessUtils.CheckWriteAccess(assemblyLocation) && !assemblyLocation.StartsWith(appDataPath); + .ConfigureAppConfiguration(SetConfiguration) + .ConfigureServices(AddServices) + .Build(); - var targetFrameworkAttributes = assembly.GetCustomAttributes(typeof(TargetFrameworkAttribute), true); - var targetFrameworkAttribute = (TargetFrameworkAttribute) targetFrameworkAttributes.First(); - var targetFramework = targetFrameworkAttribute.FrameworkDisplayName; + _host.Start(); + } - builder.AddInMemoryCollection(new KeyValuePair[] - { - new("Assembly", assemblyLocation), - new("Framework", targetFramework), - new("AddinVersion", addinVersion), - new("ConfigFolder", Path.Combine(userDataLocation, "Config")), - new("DownloadFolder", Path.Combine(userDataLocation, "Downloads")), - new("FolderAccess", writeAccess ? "Write" : "Read") - }); - }) - .ConfigureServices((_, services) => - { - services.AddSingleton(); - services.AddSingleton(); + private static void AddServices(HostBuilderContext context, IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); - services.AddTransient(); - }).Build(); + services.AddTransient(); + } - _host.Start(); + private static void SetConfiguration(IConfigurationBuilder builder) + { + var assembly = Assembly.GetExecutingAssembly(); + var assemblyLocation = assembly.Location; + var addinVersion = FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion; +#if RELEASE + var version = addinVersion.Split('.')[0]; + if (version == "1") version = "Develop"; + var programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var userDataLocation = Path.Combine(programDataPath, @"Autodesk\Revit\Addins\", version, "RevitLookup"); +#else + var userDataLocation = Path.GetDirectoryName(assemblyLocation)!; +#endif + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); + var writeAccess = AccessUtils.CheckWriteAccess(assemblyLocation) && !assemblyLocation.StartsWith(appDataPath); + + var targetFrameworkAttributes = assembly.GetCustomAttributes(typeof(TargetFrameworkAttribute), true); + var targetFrameworkAttribute = (TargetFrameworkAttribute) targetFrameworkAttributes.First(); + var targetFramework = targetFrameworkAttribute.FrameworkDisplayName; + + builder.AddInMemoryCollection(new KeyValuePair[] + { + new("Assembly", assemblyLocation), + new("Framework", targetFramework), + new("AddinVersion", addinVersion), + new("ConfigFolder", Path.Combine(userDataLocation, "Config")), + new("DownloadFolder", Path.Combine(userDataLocation, "Downloads")), + new("FolderAccess", writeAccess ? "Write" : "Read") + }); } public static void StartHost(IHost host) @@ -96,4 +104,9 @@ public static T GetService() where T : class { return _host.Services.GetService(typeof(T)) as T; } + + public static T GetService(this IServiceProvider serviceProvider) where T : class + { + return serviceProvider.GetService(typeof(T)) as T; + } } \ No newline at end of file diff --git a/RevitLookup/RevitLookup.csproj b/RevitLookup/RevitLookup.csproj index 24ae9594e..0141cc39f 100644 --- a/RevitLookup/RevitLookup.csproj +++ b/RevitLookup/RevitLookup.csproj @@ -87,7 +87,6 @@ - diff --git a/RevitLookup/Services/Contracts/ISettingsService.cs b/RevitLookup/Services/Contracts/ISettingsService.cs index 0ac3b69cb..c55bfa833 100644 --- a/RevitLookup/Services/Contracts/ISettingsService.cs +++ b/RevitLookup/Services/Contracts/ISettingsService.cs @@ -38,5 +38,6 @@ public interface ISettingsService bool IsExtensionsAllowed { get; set; } bool IsTimeColumnAllowed { get; set; } int ApplyTransition(bool value); + void Save(); } \ No newline at end of file diff --git a/RevitLookup/Services/Contracts/ISnoopService.cs b/RevitLookup/Services/Contracts/ISnoopService.cs index b1ec6863f..990960401 100644 --- a/RevitLookup/Services/Contracts/ISnoopService.cs +++ b/RevitLookup/Services/Contracts/ISnoopService.cs @@ -26,5 +26,5 @@ namespace RevitLookup.Services.Contracts; public interface ISnoopService { void Snoop(SnoopableObject snoopableObject); - Task Snoop(SnoopableType snoopableType); + Task SnoopAsync(SnoopableType snoopableType); } \ No newline at end of file diff --git a/RevitLookup/Services/Contracts/IWindow.cs b/RevitLookup/Services/Contracts/IWindow.cs index 9faa35b12..0e29d111f 100644 --- a/RevitLookup/Services/Contracts/IWindow.cs +++ b/RevitLookup/Services/Contracts/IWindow.cs @@ -24,9 +24,12 @@ namespace RevitLookup.Services.Contracts; public interface IWindow { - IServiceProvider ServiceProvider { get; } + bool IsLoaded { get; } + Visibility Visibility { get; set; } + void Show(); - void Show(Window window); - void ShowAttached(); - void Initialize(); + bool? ShowDialog(); + bool Focus(); + + event RoutedEventHandler Loaded; } \ No newline at end of file diff --git a/RevitLookup/Services/Contracts/IWindowController.cs b/RevitLookup/Services/Contracts/IWindowController.cs deleted file mode 100644 index f1adeb1b5..000000000 --- a/RevitLookup/Services/Contracts/IWindowController.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2003-2023 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.Windows; - -namespace RevitLookup.Services.Contracts; - -public interface IWindowController -{ - /// - /// Lets you attach the window that represents the . - /// - /// Instance of the . - void SetControlledWindow(Window window); - - /// - /// Hide navigation window - /// - void Hide(); - - /// - /// Show navigation window - /// - void Show(); -} \ No newline at end of file diff --git a/RevitLookup/Services/Enums/SnoopableType.cs b/RevitLookup/Services/Enums/SnoopableType.cs index 08b5d2cc7..ab41dc38b 100644 --- a/RevitLookup/Services/Enums/SnoopableType.cs +++ b/RevitLookup/Services/Enums/SnoopableType.cs @@ -38,6 +38,5 @@ public enum SnoopableType PerformanceAdviser, UpdaterRegistry, Services, - Schemas, - Events + Schemas } \ No newline at end of file diff --git a/RevitLookup/Services/LookupService.cs b/RevitLookup/Services/LookupService.cs new file mode 100644 index 000000000..a7039a3c7 --- /dev/null +++ b/RevitLookup/Services/LookupService.cs @@ -0,0 +1,113 @@ +// Copyright 2003-2023 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Controls; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Core; +using RevitLookup.Core.Objects; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using Wpf.Ui.Contracts; + +namespace RevitLookup.Services; + +public sealed class LookupService +{ + private Window _owner; + private Task _activeTask; + private readonly IServiceProvider _serviceProvider; + + public LookupService(IServiceScopeFactory scopeFactory) + { + _serviceProvider = scopeFactory.CreateScope().ServiceProvider; + } + + public LookupService Snoop(SnoopableType snoopableType) + { + _activeTask = _serviceProvider.GetService()!.SnoopAsync(snoopableType); + return this; + } + + public LookupService Snoop(SnoopableObject snoopableObject) + { + _serviceProvider.GetService()!.Snoop(snoopableObject); + return this; + } + + + public LookupService Attach(IWindow window) + { + _owner = (Window) window; + return this; + } + + public LookupService Show() where T : Page + { + if (_activeTask is null) + { + ShowPage(); + } + else + { + _activeTask = _activeTask.ContinueWith(_ => ShowPage(), TaskScheduler.FromCurrentSynchronizationContext()); + } + + return this; + + void ShowPage() + { + var window = (Window) _serviceProvider.GetService(); + + if (_owner is null) + { + window.WindowStartupLocation = WindowStartupLocation.CenterScreen; + } + else + { + window.Left = _owner.Left + 47; + window.Top = _owner.Top + 49; + } + + window.Show(RevitApi.UiApplication.MainWindowHandle); + _serviceProvider.GetService().Navigate(typeof(T)); + } + } + + public void Execute(Action handler) where T : class + { + if (_activeTask is null) + { + InvokeHandler(); + } + else + { + _activeTask = _activeTask.ContinueWith(_ => InvokeHandler(), TaskScheduler.FromCurrentSynchronizationContext()); + } + + return; + + void InvokeHandler() + { + var service = _serviceProvider.GetService(); + handler.Invoke(service); + } + } +} \ No newline at end of file diff --git a/RevitLookup/Services/NotificationService.cs b/RevitLookup/Services/NotificationService.cs new file mode 100644 index 000000000..5195428db --- /dev/null +++ b/RevitLookup/Services/NotificationService.cs @@ -0,0 +1,88 @@ +// Copyright 2003-2023 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using RevitLookup.Services.Contracts; +using Wpf.Ui.Common; +using Wpf.Ui.Contracts; +using Wpf.Ui.Controls; + +namespace RevitLookup.Services; + +public sealed class NotificationService +{ + private readonly IWindow _window; + private readonly ISnackbarService _snackbarService; + private Action _pendingNotifications; + + public NotificationService(ISnackbarService snackbarService, IWindow window) + { + _snackbarService = snackbarService; + _window = window; + } + + public void ShowError(string title, Exception exception) + { + ShowError(title, exception.Message); + } + + public void ShowError(string title, string message) + { + if (!_window.IsLoaded) + { + if (_pendingNotifications is null) _window.Loaded += ShowPendingNotifications; + _pendingNotifications += () => ShowErrorBar(title, message); + } + else + { + ShowErrorBar(title, message); + } + } + + public void ShowWarning(string title, string message) + { + if (!_window.IsLoaded) + { + if (_pendingNotifications is null) _window.Loaded += ShowPendingNotifications; + _pendingNotifications += () => ShowWarningBar(title, message); + } + else + { + ShowWarningBar(title, message); + } + } + + private void ShowWarningBar(string title, string message) + { + _snackbarService.Show(title, message, SymbolRegular.Warning24, ControlAppearance.Caution); + } + + private void ShowErrorBar(string title, string message) + { + _snackbarService.Show(title, message, SymbolRegular.ErrorCircle24, ControlAppearance.Danger); + } + + private void ShowPendingNotifications(object sender, RoutedEventArgs args) + { + _window.Loaded -= ShowPendingNotifications; + _pendingNotifications.Invoke(); + _pendingNotifications = null; + } +} \ No newline at end of file diff --git a/RevitLookup/Services/SnoopService.cs b/RevitLookup/Services/SnoopService.cs new file mode 100644 index 000000000..37225cc8f --- /dev/null +++ b/RevitLookup/Services/SnoopService.cs @@ -0,0 +1,102 @@ +// Copyright 2003-2023 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using RevitLookup.Core; +using RevitLookup.Core.Contracts; +using RevitLookup.Core.Objects; +using RevitLookup.Core.Utils; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.ViewModels.Contracts; + +namespace RevitLookup.Services; + +public sealed class SnoopService : ISnoopService +{ + private readonly NotificationService _notificationService; + private readonly ISnoopViewModel _viewModel; + private readonly IWindow _window; + + public SnoopService(NotificationService notificationService, ISnoopViewModel viewModel, IWindow window) + { + _notificationService = notificationService; + _viewModel = viewModel; + _window = window; + } + + public void Snoop(SnoopableObject snoopableObject) + { + try + { + if (snoopableObject.Descriptor is IDescriptorEnumerator {IsEmpty: false} descriptor) + { + _viewModel.SnoopableObjects = descriptor.ParseEnumerable(snoopableObject); + } + else + { + _viewModel.SnoopableObjects = new[] {snoopableObject}; + } + } + catch (Exception exception) + { + _notificationService.ShowError("Invalid object", exception); + } + } + + public async Task SnoopAsync(SnoopableType snoopableType) + { + try + { + switch (snoopableType) + { + case SnoopableType.Face: + case SnoopableType.Edge: + case SnoopableType.LinkedElement: + case SnoopableType.Point: + case SnoopableType.SubElement: + UpdateWindowVisibility(Visibility.Hidden); + break; + } + + _viewModel.SnoopableObjects = await Application.ExternalElementHandler.RaiseAsync(_ => Selector.Snoop(snoopableType)); + _viewModel.SnoopableData = Array.Empty(); + } + catch (OperationCanceledException) + { + _notificationService.ShowWarning("Operation cancelled", "Operation cancelled by user"); + } + catch (Exception exception) + { + _notificationService.ShowError("Operation cancelled", exception); + } + finally + { + UpdateWindowVisibility(Visibility.Visible); + } + } + + private void UpdateWindowVisibility(Visibility visibility) + { + if (!_window.IsLoaded) return; + + _window.Visibility = visibility; + } +} \ No newline at end of file diff --git a/RevitLookup/Services/WindowController.cs b/RevitLookup/Services/WindowController.cs deleted file mode 100644 index eaf460e8f..000000000 --- a/RevitLookup/Services/WindowController.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2003-2023 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.Windows; -using RevitLookup.Services.Contracts; - -namespace RevitLookup.Services; - -public sealed class WindowController : IWindowController -{ - private Window _window; - - public void SetControlledWindow(Window window) - { - _window = window; - } - - public void Hide() - { - _window.Hide(); - } - - public void Show() - { - _window.Show(); - } -} \ No newline at end of file diff --git a/RevitLookup/ViewModels/Contracts/ISnoopViewModel.cs b/RevitLookup/ViewModels/Contracts/ISnoopViewModel.cs index fb92ba693..71d6dc92b 100644 --- a/RevitLookup/ViewModels/Contracts/ISnoopViewModel.cs +++ b/RevitLookup/ViewModels/Contracts/ISnoopViewModel.cs @@ -24,12 +24,12 @@ namespace RevitLookup.ViewModels.Contracts; -public interface ISnoopViewModel : ISnoopService +public interface ISnoopViewModel { - IReadOnlyCollection SnoopableObjects { get; } - IReadOnlyCollection SnoopableData { get; } - IReadOnlyCollection FilteredSnoopableObjects { get; set; } - IReadOnlyCollection FilteredSnoopableData { get; set; } + IReadOnlyCollection SnoopableObjects { get; set; } + IReadOnlyCollection SnoopableData { get; set; } + IReadOnlyCollection FilteredSnoopableObjects { get; } + IReadOnlyCollection FilteredSnoopableData { get; } IAsyncRelayCommand FetchMembersCommand { get; } IAsyncRelayCommand RefreshMembersCommand { get; } public string SearchText { get; set; } diff --git a/RevitLookup/ViewModels/Dialogs/SearchElementsViewModel.cs b/RevitLookup/ViewModels/Dialogs/SearchElementsViewModel.cs index 46edd5860..1a8984600 100644 --- a/RevitLookup/ViewModels/Dialogs/SearchElementsViewModel.cs +++ b/RevitLookup/ViewModels/Dialogs/SearchElementsViewModel.cs @@ -32,25 +32,12 @@ public sealed partial class SearchElementsViewModel : ObservableObject public bool SearchIds(ISnoopService snoopService) { - var delimiters = new[] {'\t', ';', ',', ' '}; var rows = SearchText.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries); - - var items = new List(rows.Length); - foreach (var row in rows) - for (var i = 0; i < delimiters.Length; i++) - { - var delimiter = delimiters[i]; - var split = row.Split(new[] {delimiter}, StringSplitOptions.RemoveEmptyEntries); - if (split.Length > 1 || i == delimiters.Length - 1 || split.Length == 1 && split[0] != row) - { - items.AddRange(split); - break; - } - } - + var items = ParseRawRequest(rows); var results = new List(items.Count); foreach (var rawId in items) + { #if R24_OR_GREATER if (long.TryParse(rawId, out var id)) { @@ -69,43 +56,74 @@ public bool SearchIds(ISnoopService snoopService) } else if (rawId.Length == 22 && rawId.Count(c => c == ' ') == 0) { - var guidProvider = new ParameterValueProvider(new ElementId(BuiltInParameter.IFC_GUID)); - var typeGuidProvider = new ParameterValueProvider(new ElementId(BuiltInParameter.IFC_TYPE_GUID)); -#if R22_OR_GREATER - var filterRule = new FilterStringRule(guidProvider, new FilterStringEquals(), rawId); - var typeFilterRule = new FilterStringRule(typeGuidProvider, new FilterStringEquals(), rawId); -#else - var filterRule = new FilterStringRule(guidProvider, new FilterStringEquals(), rawId, true); - var typeFilterRule = new FilterStringRule(typeGuidProvider, new FilterStringEquals(), rawId, true); -#endif - var elementFilter = new ElementParameterFilter(filterRule); - var typeElementFilter = new ElementParameterFilter(typeFilterRule); - - - var typeGuidsCollector = RevitApi.Document - .GetElements() - .WherePasses(typeElementFilter); - - var elements = RevitApi.Document - .GetElements() - .WherePasses(elementFilter) - .UnionWith(typeGuidsCollector) - .ToElements(); - + var elements = SearchBuIfcGuid(rawId); results.AddRange(elements); } else { - var elementTypes = RevitApi.Document.GetElements().WhereElementIsElementType(); - var elementInstances = RevitApi.Document.GetElements().WhereElementIsNotElementType(); - results.AddRange(elementTypes - .UnionWith(elementInstances) - .Where(element => element.Name.Contains(rawId, StringComparison.OrdinalIgnoreCase))); + var elements = SearchByName(rawId); + results.AddRange(elements); } + } if (results.Count == 0) return false; - snoopService.Snoop(new SnoopableObject(RevitApi.Document, results)); + snoopService.Snoop(new SnoopableObject(results)); return true; } + + private static IEnumerable SearchByName(string rawId) + { + var elementTypes = RevitApi.Document.GetElements().WhereElementIsElementType(); + var elementInstances = RevitApi.Document.GetElements().WhereElementIsNotElementType(); + return elementTypes + .UnionWith(elementInstances) + .Where(element => element.Name.Contains(rawId, StringComparison.OrdinalIgnoreCase)); + } + + private static IList SearchBuIfcGuid(string rawId) + { + var guidProvider = new ParameterValueProvider(new ElementId(BuiltInParameter.IFC_GUID)); + var typeGuidProvider = new ParameterValueProvider(new ElementId(BuiltInParameter.IFC_TYPE_GUID)); +#if R22_OR_GREATER + var filterRule = new FilterStringRule(guidProvider, new FilterStringEquals(), rawId); + var typeFilterRule = new FilterStringRule(typeGuidProvider, new FilterStringEquals(), rawId); +#else + var filterRule = new FilterStringRule(guidProvider, new FilterStringEquals(), rawId, true); + var typeFilterRule = new FilterStringRule(typeGuidProvider, new FilterStringEquals(), rawId, true); +#endif + var elementFilter = new ElementParameterFilter(filterRule); + var typeElementFilter = new ElementParameterFilter(typeFilterRule); + + var typeGuidsCollector = RevitApi.Document + .GetElements() + .WherePasses(typeElementFilter); + + return RevitApi.Document + .GetElements() + .WherePasses(elementFilter) + .UnionWith(typeGuidsCollector) + .ToElements(); + } + + private static List ParseRawRequest(string[] rows) + { + var items = new List(rows.Length); + var delimiters = new[] {'\t', ';', ',', ' '}; + foreach (var row in rows) + { + for (var i = 0; i < delimiters.Length; i++) + { + var delimiter = delimiters[i]; + var split = row.Split(new[] {delimiter}, StringSplitOptions.RemoveEmptyEntries); + if (split.Length > 1 || i == delimiters.Length - 1 || split.Length == 1 && split[0] != row) + { + items.AddRange(split); + break; + } + } + } + + return items; + } } \ No newline at end of file diff --git a/RevitLookup/ViewModels/Objects/UnitInfo.cs b/RevitLookup/ViewModels/Objects/UnitInfo.cs index 5d12cb4f6..427a075fb 100644 --- a/RevitLookup/ViewModels/Objects/UnitInfo.cs +++ b/RevitLookup/ViewModels/Objects/UnitInfo.cs @@ -22,12 +22,14 @@ namespace RevitLookup.ViewModels.Objects; public sealed class UnitInfo { - public UnitInfo(string unit, string label) + public UnitInfo(object unitObject, string unit, string label) { Unit = unit; Label = label; + UnitObject = unitObject; } public string Unit { get; } public string Label { get; } + public object UnitObject { get; } } \ No newline at end of file diff --git a/RevitLookup/ViewModels/Pages/DashboardViewModel.cs b/RevitLookup/ViewModels/Pages/DashboardViewModel.cs index b2687a180..be67c209c 100644 --- a/RevitLookup/ViewModels/Pages/DashboardViewModel.cs +++ b/RevitLookup/ViewModels/Pages/DashboardViewModel.cs @@ -22,9 +22,11 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using RevitLookup.Core; +using RevitLookup.Services; using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; using RevitLookup.Views.Dialogs; +using RevitLookup.Views.Pages; using Wpf.Ui.Common; using Wpf.Ui.Contracts; using Wpf.Ui.Controls; @@ -34,19 +36,23 @@ namespace RevitLookup.ViewModels.Pages; public sealed partial class DashboardViewModel : ObservableObject { private readonly IContentDialogService _dialogService; + private readonly NotificationService _notificationService; private readonly IServiceProvider _serviceProvider; - private readonly ISnackbarService _snackbarService; + private readonly INavigationService _navigationService; private readonly ISnoopService _snoopService; - public DashboardViewModel(ISnoopService snoopService, + public DashboardViewModel( + INavigationService navigationService, + ISnoopService snoopService, IContentDialogService dialogService, - ISnackbarService snackbarService, + NotificationService notificationService, IServiceProvider serviceProvider) { + _navigationService = navigationService; _snoopService = snoopService; _serviceProvider = serviceProvider; _dialogService = dialogService; - _snackbarService = snackbarService; + _notificationService = notificationService; } [RelayCommand] @@ -57,59 +63,75 @@ private async Task NavigateSnoopPage(string parameter) switch (parameter) { case "view": - await _snoopService.Snoop(SnoopableType.View); + await _snoopService.SnoopAsync(SnoopableType.View); + _navigationService.Navigate(typeof(SnoopView)); break; case "document": - await _snoopService.Snoop(SnoopableType.Document); + await _snoopService.SnoopAsync(SnoopableType.Document); + _navigationService.Navigate(typeof(SnoopView)); break; case "application": - await _snoopService.Snoop(SnoopableType.Application); + await _snoopService.SnoopAsync(SnoopableType.Application); + _navigationService.Navigate(typeof(SnoopView)); break; case "uiApplication": - await _snoopService.Snoop(SnoopableType.UiApplication); + await _snoopService.SnoopAsync(SnoopableType.UiApplication); + _navigationService.Navigate(typeof(SnoopView)); break; case "database": - await _snoopService.Snoop(SnoopableType.Database); + await _snoopService.SnoopAsync(SnoopableType.Database); + _navigationService.Navigate(typeof(SnoopView)); break; case "dependents": - await _snoopService.Snoop(SnoopableType.DependentElements); + await _snoopService.SnoopAsync(SnoopableType.DependentElements); + _navigationService.Navigate(typeof(SnoopView)); break; case "selection": - await _snoopService.Snoop(SnoopableType.Selection); + await _snoopService.SnoopAsync(SnoopableType.Selection); + _navigationService.Navigate(typeof(SnoopView)); break; case "linked": - await _snoopService.Snoop(SnoopableType.LinkedElement); + await _snoopService.SnoopAsync(SnoopableType.LinkedElement); + _navigationService.Navigate(typeof(SnoopView)); break; case "face": - await _snoopService.Snoop(SnoopableType.Face); + await _snoopService.SnoopAsync(SnoopableType.Face); + _navigationService.Navigate(typeof(SnoopView)); break; case "edge": - await _snoopService.Snoop(SnoopableType.Edge); + await _snoopService.SnoopAsync(SnoopableType.Edge); + _navigationService.Navigate(typeof(SnoopView)); break; case "point": - await _snoopService.Snoop(SnoopableType.Point); + await _snoopService.SnoopAsync(SnoopableType.Point); + _navigationService.Navigate(typeof(SnoopView)); break; case "subElement": - await _snoopService.Snoop(SnoopableType.SubElement); + await _snoopService.SnoopAsync(SnoopableType.SubElement); + _navigationService.Navigate(typeof(SnoopView)); break; case "components": - await _snoopService.Snoop(SnoopableType.ComponentManager); + await _snoopService.SnoopAsync(SnoopableType.ComponentManager); + _navigationService.Navigate(typeof(SnoopView)); break; case "performance": - await _snoopService.Snoop(SnoopableType.PerformanceAdviser); + await _snoopService.SnoopAsync(SnoopableType.PerformanceAdviser); + _navigationService.Navigate(typeof(SnoopView)); break; case "updaters": - await _snoopService.Snoop(SnoopableType.UpdaterRegistry); + await _snoopService.SnoopAsync(SnoopableType.UpdaterRegistry); + _navigationService.Navigate(typeof(SnoopView)); break; case "services": - await _snoopService.Snoop(SnoopableType.Services); + await _snoopService.SnoopAsync(SnoopableType.Services); + _navigationService.Navigate(typeof(SnoopView)); break; case "schemas": - await _snoopService.Snoop(SnoopableType.Schemas); + await _snoopService.SnoopAsync(SnoopableType.Schemas); + _navigationService.Navigate(typeof(SnoopView)); break; case "events": - var service = (EventsViewModel) _serviceProvider.GetService(typeof(EventsViewModel)); - await service.Snoop(SnoopableType.Events); + _navigationService.Navigate(typeof(EventsView)); break; default: throw new ArgumentOutOfRangeException(nameof(parameter), parameter); @@ -127,7 +149,7 @@ private async Task OpenDialog(string parameter) case "parameters": var units = await Task.Run(() => RevitApi.GetUnitInfos(typeof(BuiltInParameter))); dialog.Title = "BuiltIn Parameters"; - dialog.Content = new UnitsDialog(units); + dialog.Content = new UnitsDialog(_serviceProvider, units); dialog.DialogWidth = 800; dialog.DialogHeight = 600; await dialog.ShowAsync(); @@ -135,7 +157,7 @@ private async Task OpenDialog(string parameter) case "categories": units = await Task.Run(() => RevitApi.GetUnitInfos(typeof(BuiltInCategory))); dialog.Title = "BuiltIn Categories"; - dialog.Content = new UnitsDialog(units); + dialog.Content = new UnitsDialog(_serviceProvider, units); dialog.DialogWidth = 800; dialog.DialogHeight = 600; await dialog.ShowAsync(); @@ -143,7 +165,7 @@ private async Task OpenDialog(string parameter) case "forge": units = await Task.Run(() => RevitApi.GetUnitInfos(typeof(ForgeTypeId))); dialog.Title = "Forge Schema"; - dialog.Content = new UnitsDialog(units); + dialog.Content = new UnitsDialog(_serviceProvider, units); dialog.DialogWidth = 800; dialog.DialogHeight = 600; await dialog.ShowAsync(); @@ -162,7 +184,7 @@ private bool Validate() if (RevitApi.UiApplication is null) return true; if (RevitApi.UiDocument is not null) return true; - _snackbarService.Show("Request denied", "There are no open documents", SymbolRegular.Warning24, ControlAppearance.Caution); + _notificationService.ShowWarning("Request denied", "There are no open documents"); return false; } } \ No newline at end of file diff --git a/RevitLookup/ViewModels/Pages/EventsViewModel.cs b/RevitLookup/ViewModels/Pages/EventsViewModel.cs index 04fb09dfd..51d8d7445 100644 --- a/RevitLookup/ViewModels/Pages/EventsViewModel.cs +++ b/RevitLookup/ViewModels/Pages/EventsViewModel.cs @@ -22,8 +22,8 @@ using RevitLookup.Core; using RevitLookup.Core.Contracts; using RevitLookup.Core.Objects; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Services; +using RevitLookup.Services.Contracts; using Wpf.Ui.Contracts; using Wpf.Ui.Controls.Navigation; @@ -33,11 +33,9 @@ public sealed class EventsViewModel : SnoopViewModelBase, INavigationAware { private readonly EventMonitor _eventMonitor; private readonly Stack _events = new(); - private readonly INavigationService _navigationService; - public EventsViewModel(INavigationService navigationService, ISnackbarService snackbarService) : base(navigationService, snackbarService) + public EventsViewModel(NotificationService notificationService, IWindow window) : base(notificationService, window) { - _navigationService = navigationService; SnoopableObjects = new ObservableCollection(); _eventMonitor = new EventMonitor(OnHandlingEvent); } @@ -52,17 +50,9 @@ public void OnNavigatedFrom() _eventMonitor.Unsubscribe(); } - public override async Task Snoop(SnoopableType snoopableType) - { - await Task.CompletedTask; - if (snoopableType != SnoopableType.Events) throw new NotSupportedException(); - - _navigationService.Navigate(typeof(EventsView)); - } - private void OnHandlingEvent(string name, EventArgs args) { - var snoopableObject = new SnoopableObject(RevitApi.Document, args) + var snoopableObject = new SnoopableObject(args) { Descriptor = { diff --git a/RevitLookup/ViewModels/Pages/SnoopViewModel.cs b/RevitLookup/ViewModels/Pages/SnoopViewModel.cs index e65ad696f..c1139fd9d 100644 --- a/RevitLookup/ViewModels/Pages/SnoopViewModel.cs +++ b/RevitLookup/ViewModels/Pages/SnoopViewModel.cs @@ -18,69 +18,14 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -using RevitLookup.Core; -using RevitLookup.Core.Objects; +using RevitLookup.Services; using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; -using Wpf.Ui.Common; -using Wpf.Ui.Contracts; -using Wpf.Ui.Controls; -using OperationCanceledException = Autodesk.Revit.Exceptions.OperationCanceledException; namespace RevitLookup.ViewModels.Pages; public sealed class SnoopViewModel : SnoopViewModelBase { - private readonly INavigationService _navigationService; - private readonly ISnackbarService _snackbarService; - private readonly IWindowController _windowController; - - public SnoopViewModel(IWindowController windowController, INavigationService navigationService, ISnackbarService snackbarService) - : base(navigationService, snackbarService) - { - _windowController = windowController; - _navigationService = navigationService; - _snackbarService = snackbarService; - } - - public override async Task Snoop(SnoopableType snoopableType) + public SnoopViewModel(NotificationService notificationService, IWindow window) : base(notificationService, window) { - try - { - switch (snoopableType) - { - case SnoopableType.Face: - case SnoopableType.Edge: - case SnoopableType.LinkedElement: - case SnoopableType.Point: - case SnoopableType.SubElement: - _windowController.Hide(); - break; - } - - try - { - SnoopableObjects = await Application.ExternalElementHandler.RaiseAsync(_ => Selector.Snoop(snoopableType)); - } - finally - { - _windowController.Show(); - } - - SnoopableData = Array.Empty(); - _navigationService.Navigate(typeof(SnoopView)); - } - catch (OperationCanceledException exception) - { - _navigationService.Navigate(typeof(DashboardView)); - // ReSharper disable once MethodHasAsyncOverload - _snackbarService.Show("Operation cancelled", exception.Message, SymbolRegular.Warning24, ControlAppearance.Caution); - } - catch (Exception exception) - { - // ReSharper disable once MethodHasAsyncOverload - _snackbarService.Show("Snoop engine error", exception.Message, SymbolRegular.ErrorCircle24, ControlAppearance.Danger); - } } } \ No newline at end of file diff --git a/RevitLookup/ViewModels/Pages/SnoopViewModelBase.cs b/RevitLookup/ViewModels/Pages/SnoopViewModelBase.cs index 40e532420..49bacfaf9 100644 --- a/RevitLookup/ViewModels/Pages/SnoopViewModelBase.cs +++ b/RevitLookup/ViewModels/Pages/SnoopViewModelBase.cs @@ -22,69 +22,47 @@ using Autodesk.Revit.Exceptions; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Microsoft.Extensions.DependencyInjection; using RevitLookup.Core.Contracts; using RevitLookup.Core.Objects; -using RevitLookup.Core.Utils; +using RevitLookup.Services; using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; using RevitLookup.ViewModels.Contracts; using RevitLookup.ViewModels.Enums; using RevitLookup.ViewModels.Utils; using RevitLookup.Views.Pages; -using Wpf.Ui.Common; -using Wpf.Ui.Contracts; -using Wpf.Ui.Controls; using OperationCanceledException = System.OperationCanceledException; namespace RevitLookup.ViewModels.Pages; public abstract partial class SnoopViewModelBase : ObservableObject, ISnoopViewModel { - private readonly INavigationService _navigationService; - private readonly ISnackbarService _snackbarService; + private readonly IWindow _window; + private readonly NotificationService _notificationService; + private CancellationTokenSource _searchCancellationToken = new(); + [ObservableProperty] private IReadOnlyCollection _filteredSnoopableData; [ObservableProperty] private IReadOnlyCollection _filteredSnoopableObjects = Array.Empty(); - private CancellationTokenSource _searchCancellationToken = new(); [ObservableProperty] private string _searchText = string.Empty; [ObservableProperty] private IReadOnlyCollection _snoopableData; [ObservableProperty] private IReadOnlyCollection _snoopableObjects = Array.Empty(); - protected SnoopViewModelBase(INavigationService navigationService, ISnackbarService snackbarService) + protected SnoopViewModelBase(NotificationService notificationService, IWindow window) { - _navigationService = navigationService; - _snackbarService = snackbarService; + _notificationService = notificationService; + _window = window; } public SnoopableObject SelectedObject { get; set; } - public void Snoop(SnoopableObject snoopableObject) - { - if (snoopableObject.Descriptor is IDescriptorEnumerator {IsEmpty: false} descriptor) - try - { - SnoopableObjects = descriptor.ParseEnumerable(snoopableObject); - } - catch (Exception exception) - { - SnowException("Invalid object", exception.Message); - } - else - SnoopableObjects = new[] {snoopableObject}; - - _navigationService.Navigate(typeof(SnoopView)); - } - - public abstract Task Snoop(SnoopableType snoopableType); - public void Navigate(Descriptor selectedItem) { - if (selectedItem.Value.Descriptor is not IDescriptorCollector or IDescriptorEnumerator {IsEmpty: true}) return; + if (selectedItem.Value.Descriptor is not IDescriptorCollector) return; + if (selectedItem.Value.Descriptor is IDescriptorEnumerator {IsEmpty: true}) return; - var owner = Wpf.Ui.Application.MainWindow; - var window = Host.GetService(); - window.Show(owner); - window.ServiceProvider.GetService()!.Snoop(selectedItem.Value); + Host.GetService() + .Snoop(selectedItem.Value) + .Attach(_window) + .Show(); } partial void OnSearchTextChanged(string value) @@ -130,16 +108,16 @@ private async void UpdateSearchResults(SearchOption option) [RelayCommand] private async Task FetchMembersAsync() { - await CollectMembers(true); + await CollectMembersAsync(true); } [RelayCommand] private async Task RefreshMembersAsync() { - await CollectMembers(false); + await CollectMembersAsync(false); } - private async Task CollectMembers(bool useCached) + private async Task CollectMembersAsync(bool useCached) { if (SelectedObject is null) { @@ -153,26 +131,23 @@ private async Task CollectMembers(bool useCached) } catch (InvalidObjectException exception) { - SnowException("Invalid object", exception.Message); + _notificationService.ShowError("Invalid object", exception); } catch (InternalException) { - const string message = "A problem in the Revit code. Usually occurs when a managed API object is no longer valid and is unloaded from memory"; - SnowException("Revit API internal error", message); + _notificationService.ShowError( + "Invalid object", + "A problem in the Revit code. Usually occurs when a managed API object is no longer valid and is unloaded from memory"); } catch (SEHException) { - const string message = "A problem in the Revit code. Usually occurs when a managed API object is no longer valid and is unloaded from memory"; - SnowException("Revit API internal error", message); + _notificationService.ShowError( + "Revit API internal error", + "A problem in the Revit code. Usually occurs when a managed API object is no longer valid and is unloaded from memory"); } catch (Exception exception) { - SnowException("Snoop engine error", exception.Message); + _notificationService.ShowError("Snoop engine error", exception); } } - - private void SnowException(string title, string message) - { - _snackbarService.Show(title, message, SymbolRegular.ErrorCircle24, ControlAppearance.Danger); - } } \ No newline at end of file diff --git a/RevitLookup/Views/Dialogs/UnitsDialog.xaml.cs b/RevitLookup/Views/Dialogs/UnitsDialog.xaml.cs index c45c34c8a..23d232960 100644 --- a/RevitLookup/Views/Dialogs/UnitsDialog.xaml.cs +++ b/RevitLookup/Views/Dialogs/UnitsDialog.xaml.cs @@ -21,6 +21,11 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Autodesk.Revit.DB; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Core; +using RevitLookup.Core.Objects; +using RevitLookup.Services.Contracts; using RevitLookup.ViewModels.Dialogs; using RevitLookup.ViewModels.Objects; using RevitLookup.Views.Extensions; @@ -29,8 +34,11 @@ namespace RevitLookup.Views.Dialogs; public sealed partial class UnitsDialog { - public UnitsDialog(List unitType) + private readonly IServiceProvider _serviceProvider; + + public UnitsDialog(IServiceProvider serviceProvider, List unitType) { + _serviceProvider = serviceProvider; InitializeComponent(); DataContext = new UnitsViewModel(unitType); } @@ -51,11 +59,24 @@ private void CreateTreeContextMenu(UnitInfo info, FrameworkElement row) row.ContextMenu.AddMenuItem("CopyMenuItem") .SetHeader("Copy unit") - .SetCommand(info, parameter => Clipboard.SetText(parameter.Unit)) + .SetCommand(info, unitInfo => Clipboard.SetText(unitInfo.Unit)) .SetShortcut(row, ModifierKeys.Control, Key.C); row.ContextMenu.AddMenuItem("CopyMenuItem") .SetHeader("Copy label") - .SetCommand(info, parameter => Clipboard.SetText(parameter.Label)) + .SetCommand(info, unitInfo => Clipboard.SetText(unitInfo.Label)) .SetShortcut(row, ModifierKeys.Control | ModifierKeys.Shift, Key.C); + row.ContextMenu.AddMenuItem() + .SetHeader("Snoop") + .SetCommand(info, unitInfo => + { + var obj = unitInfo.UnitObject switch + { + BuiltInParameter parameter => RevitApi.GetBuiltinParameter(parameter), + BuiltInCategory category => RevitApi.GetBuiltinCategory(category), + _ => unitInfo.UnitObject + }; + + _serviceProvider.GetService().Snoop(new SnoopableObject(obj)); + }); } } \ No newline at end of file diff --git a/RevitLookup/Views/Pages/SnoopView.xaml.cs b/RevitLookup/Views/Pages/SnoopView.xaml.cs index bd4be9241..e5942e4ee 100644 --- a/RevitLookup/Views/Pages/SnoopView.xaml.cs +++ b/RevitLookup/Views/Pages/SnoopView.xaml.cs @@ -26,7 +26,7 @@ namespace RevitLookup.Views.Pages; public sealed partial class SnoopView { - public SnoopView(IServiceProvider serviceProvider, ISettingsService settingsService) : base(settingsService) + public SnoopView(ISettingsService settingsService, ISnoopViewModel viewModel) : base(settingsService) { InitializeComponent(); @@ -36,7 +36,7 @@ public SnoopView(IServiceProvider serviceProvider, ISettingsService settingsServ TreeView.SelectedItemChanged += OnTreeSelectionChanged; TreeView.ItemsSourceChanged += OnTreeSourceChanged; - ViewModel = (ISnoopViewModel) serviceProvider.GetService(typeof(ISnoopService)); + ViewModel = viewModel; DataContext = this; Theme.Apply(this, settingsService.Theme, settingsService.Background); diff --git a/RevitLookup/Views/Resources/Menus.xaml.cs b/RevitLookup/Views/Resources/Menus.xaml.cs index 8237102de..48e64f44e 100644 --- a/RevitLookup/Views/Resources/Menus.xaml.cs +++ b/RevitLookup/Views/Resources/Menus.xaml.cs @@ -20,7 +20,7 @@ namespace RevitLookup.Views.Resources; -partial class Menus +sealed partial class Menus { public Menus() { diff --git a/RevitLookup/Views/RevitLookupView.xaml.cs b/RevitLookup/Views/RevitLookupView.xaml.cs index d54f0b4cd..8ff61097c 100644 --- a/RevitLookup/Views/RevitLookupView.xaml.cs +++ b/RevitLookup/Views/RevitLookupView.xaml.cs @@ -18,12 +18,8 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -using System.Windows; using System.Windows.Input; -using System.Windows.Interop; using CommunityToolkit.Mvvm.Input; -using Microsoft.Extensions.DependencyInjection; -using RevitLookup.Core; using RevitLookup.Services.Contracts; using Wpf.Ui.Appearance; using Wpf.Ui.Contracts; @@ -40,43 +36,15 @@ private RevitLookupView() AddShortcuts(); } - public RevitLookupView(IServiceScopeFactory scopeFactory, ISettingsService settingsService) : this() + public RevitLookupView( + INavigationService navigationService, + IContentDialogService dialogService, + ISnackbarService snackbarService, + ISettingsService settingsService) + : this() { SetTheme(settingsService); - SetupServices(scopeFactory); - } - - public IServiceProvider ServiceProvider { get; private set; } - - public void Show(Window window) - { - Left = window.Left + 47; - Top = window.Top + 49; - this.Show(RevitApi.UiApplication.MainWindowHandle); - } - - public void ShowAttached() - { - WindowStartupLocation = WindowStartupLocation.CenterScreen; - this.Show(RevitApi.UiApplication.MainWindowHandle); - } - - public void Initialize() - { - WindowStartupLocation = WindowStartupLocation.CenterScreen; - var interopHelper = new WindowInteropHelper(this) {Owner = RevitApi.UiApplication.MainWindowHandle}; - interopHelper.EnsureHandle(); - } - - private void SetupServices(IServiceScopeFactory scopeFactory) - { - ServiceProvider = scopeFactory.CreateScope().ServiceProvider; - var navigationService = ServiceProvider.GetService()!; - var windowController = ServiceProvider.GetService()!; - var dialogService = ServiceProvider.GetService()!; - var snackbarService = ServiceProvider.GetService()!; - windowController.SetControlledWindow(this); navigationService.SetNavigationControl(RootNavigation); dialogService.SetContentPresenter(RootContentDialog);