diff --git a/.gitignore b/.gitignore
index 80046ed..4f43da1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,13 @@ bin/
obj/
publish/
*.sln
+*.slnx
+
+# IDE support (keep locally, don't track)
+/.vs/
+/.vscode/
+*.user
+*.suo
+*.sln.DotSettings
+Properties/launchSettings.json
+nuget.local.config
diff --git a/ConsoleGuiTools.build.ps1 b/ConsoleGuiTools.build.ps1
index 3fa225b..5ba0fa6 100644
--- a/ConsoleGuiTools.build.ps1
+++ b/ConsoleGuiTools.build.ps1
@@ -23,15 +23,18 @@ task Build {
Push-Location src/Microsoft.PowerShell.ConsoleGuiTools
Invoke-BuildExec { & dotnet publish --configuration $Configuration --output publish }
- $Assets = $(
- "./publish/Microsoft.PowerShell.ConsoleGuiTools.dll",
- "./publish/Microsoft.PowerShell.ConsoleGuiTools.psd1",
- "./publish/Microsoft.PowerShell.OutGridView.Models.dll",
- "./publish/Terminal.Gui.dll",
- "./publish/NStack.dll")
- $Assets | ForEach-Object {
- Copy-Item -Force -Path $_ -Destination ../../module
+
+ # Copy all DLLs except PowerShell SDK dependencies (those are provided by PowerShell itself)
+ Get-ChildItem "./publish/*.dll" | Where-Object {
+ $_.Name -notlike "System.Management.Automation.dll" -and
+ $_.Name -notlike "Microsoft.PowerShell.Commands.Diagnostics.dll" -and
+ $_.Name -notlike "Microsoft.Management.Infrastructure.CimCmdlets.dll"
+ } | ForEach-Object {
+ Copy-Item -Force -Path $_.FullName -Destination ../../module
}
+
+ # Copy the module manifest
+ Copy-Item -Force -Path "./publish/Microsoft.PowerShell.ConsoleGuiTools.psd1" -Destination ../../module
Pop-Location
$Assets = $(
diff --git a/Directory.Build.props b/Directory.Build.props
index 1932808..0f11888 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,5 +1,8 @@
true
+
+ $(MSBuildThisFileDirectory)nuget.local.config
diff --git a/Directory.Packages.props b/Directory.Packages.props
index be0590b..c661351 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,8 +1,8 @@
-
-
-
-
+
+
+
+
-
+
\ No newline at end of file
diff --git a/global.json b/global.json
index 19e4d7e..a1ce647 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.405",
+ "version": "10.0.101",
"rollForward": "latestFeature",
"allowPrerelease": false
}
diff --git a/nuget.config b/nuget.config
index f003b0f..663bd86 100644
--- a/nuget.config
+++ b/nuget.config
@@ -3,5 +3,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.PowerShell.ConsoleGuiTools/CachedMemberResult.cs b/src/Microsoft.PowerShell.ConsoleGuiTools/CachedMemberResult.cs
new file mode 100644
index 0000000..14534c5
--- /dev/null
+++ b/src/Microsoft.PowerShell.ConsoleGuiTools/CachedMemberResult.cs
@@ -0,0 +1,152 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace Microsoft.PowerShell.ConsoleGuiTools;
+
+///
+/// Represents a cached reflection result for a property or field member, including its value and collection details.
+///
+internal sealed class CachedMemberResult
+{
+ #region Fields
+
+ private readonly string? _representation;
+ private List? _valueAsList;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the member information (property or field) that was accessed.
+ ///
+ public MemberInfo Member { get; set; }
+
+ ///
+ /// Gets or sets the value retrieved from the member.
+ ///
+ public object? Value { get; set; }
+
+ ///
+ /// Gets or sets the parent object that contains this member.
+ ///
+ public object Parent { get; set; }
+
+ ///
+ /// Gets a value indicating whether this member's value is a collection.
+ ///
+ public bool IsCollection => _valueAsList != null;
+
+ ///
+ /// Gets the collection elements if this member's value is a collection; otherwise, .
+ ///
+ public IReadOnlyCollection? Elements => _valueAsList?.AsReadOnly();
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Initializes a new instance of the class by reflecting on the specified member.
+ ///
+ /// The parent object containing the member.
+ /// The member information to retrieve the value from.
+ public CachedMemberResult(object parent, MemberInfo mem)
+ {
+ Parent = parent;
+ Member = mem;
+
+ try
+ {
+ if (mem is PropertyInfo p)
+ Value = p.GetValue(parent);
+ else if (mem is FieldInfo f)
+ Value = f.GetValue(parent);
+ else
+ throw new NotSupportedException($"Unknown {nameof(MemberInfo)} Type");
+
+ _representation = ValueToString();
+ }
+ catch (Exception)
+ {
+ Value = _representation = "Unavailable";
+ }
+ }
+
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// Returns a string representation of this member in the format "MemberName: value".
+ ///
+ /// A formatted string showing the member name and value.
+ public override string ToString() => Member.Name + ": " + _representation;
+
+ #endregion
+
+ #region Private Methods
+
+ ///
+ /// Converts the member's value to a string representation, detecting collections and formatting them appropriately.
+ ///
+ /// A string representation of the value.
+ private string? ValueToString()
+ {
+ if (Value == null)
+ return "Null";
+
+ try
+ {
+ if (IsCollectionOfKnownTypeAndSize(out var elementType, out var size))
+ return $"{elementType!.Name}[{size}]";
+ }
+ catch (Exception)
+ {
+ return Value?.ToString();
+ }
+
+ return Value?.ToString();
+ }
+
+ ///
+ /// Determines whether the value is a collection of a known type and caches the collection elements.
+ ///
+ /// When this method returns, contains the element type if the value is a homogeneous collection; otherwise, .
+ /// When this method returns, contains the size of the collection if applicable; otherwise, 0.
+ /// if the value is a collection of a single known type; otherwise, .
+ private bool IsCollectionOfKnownTypeAndSize(out Type? elementType, out int size)
+ {
+ elementType = null;
+ size = 0;
+
+ if (Value is null or string)
+ return false;
+
+ if (Value is IEnumerable enumerable)
+ {
+ var list = enumerable.Cast