Commit: deca99a
Parent: 1bbc770

Select headers

Mårten Åsberg committed on 2026-04-05 at 11:50
Only plain PSObject properties
OutGridTree.Window/MainWindow.axaml.cs +76 -35
diff --git a/OutGridTree.Window/MainWindow.axaml.cs b/OutGridTree.Window/MainWindow.axaml.cs
index 0e7d977..47a752b 100644
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using Avalonia.Controls;
using Avalonia.Data;
@@ -15,6 +17,7 @@ internal sealed partial class MainWindow : Avalonia.Controls.Window
public MainWindow(RpcService rpcService)
{
this.rpcService = rpcService;
rpcService.HeadersReceived += OnHeadersReceived;
rpcService.RecordReceived += OnRecordReceived;
InitializeComponent();
@@ -22,6 +25,11 @@ internal sealed partial class MainWindow : Avalonia.Controls.Window
Table.ItemsSource = records;
}
private void OnHeadersReceived(IEnumerable<string> headers)
{
Dispatcher.Post(() => SetPsObjectHeaders(headers));
}
private void OnRecordReceived(object? record)
{
Dispatcher.Post(() => AddRecord(record));
@@ -29,55 +37,88 @@ internal sealed partial class MainWindow : Avalonia.Controls.Window
private void AddRecord(object? record)
{
if (record is not null && records.Count is 0)
if (record is not null && Table.Columns.Count is 0)
{
if (record is PSObject psObject)
{
foreach (var property in psObject.Properties)
{
var name = property.Name;
Table.Columns.Add(
new DataGridTextColumn()
{
Header = name,
Binding = CompiledBinding.Create<object, object>(
o => o,
converter: new FuncValueConverter<object, string?>(o =>
(o as PSObject)?.Properties[name].Value?.ToString()
)
),
}
);
}
SetPsObjectHeaders(psObject.Properties.Select(p => p.Name));
}
else
{
Table.Columns.Add(
new DataGridTextColumn()
{
Header = record switch
{
bool => "Boolean",
byte or sbyte or short or ushort or int or uint or long or ulong => "Integer",
float or double or decimal => "Number",
char => "Character",
string => "String",
_ => "Primitive",
},
Binding = CompiledBinding.Create<object, object>(
o => o,
converter: new FuncValueConverter<object, string?>(o => o?.ToString())
),
}
);
SetPrimitiveHeader(record.GetType());
}
}
records.Add(record);
}
private void SetPsObjectHeaders(IEnumerable<string> headers)
{
foreach (var header in headers)
{
Table.Columns.Add(
new DataGridTextColumn()
{
Header = header,
Binding = CompiledBinding.Create<object, object>(
o => o,
converter: new FuncValueConverter<object, string?>(o =>
(o as PSObject)?.Properties[header].Value?.ToString()
)
),
}
);
}
}
private void SetPrimitiveHeader(Type type)
{
var header = "Primitive";
if (type == typeof(bool))
{
header = "Boolean";
}
else if (
type == typeof(byte)
|| type == typeof(sbyte)
|| type == typeof(short)
|| type == typeof(ushort)
|| type == typeof(int)
|| type == typeof(uint)
|| type == typeof(long)
|| type == typeof(ulong)
)
{
header = "Integer";
}
else if (type == typeof(float) || type == typeof(double) || type == typeof(decimal))
{
header = "Number";
}
else if (type == typeof(char))
{
header = "Character";
}
else if (type == typeof(string))
{
header = "String";
}
Table.Columns.Add(
new DataGridTextColumn()
{
Header = header,
Binding = CompiledBinding.Create<object, object>(
o => o,
converter: new FuncValueConverter<object, string?>(o => o?.ToString())
),
}
);
}
protected override void OnClosed(EventArgs e)
{
rpcService.HeadersReceived -= OnHeadersReceived;
rpcService.RecordReceived -= OnRecordReceived;
base.OnClosed(e);
OutGridTree.Window/RpcService.cs +15 -2
diff --git a/OutGridTree.Window/RpcService.cs b/OutGridTree.Window/RpcService.cs
index 8ea27ec..23f6b67 100644
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Management.Automation;
@@ -9,6 +10,7 @@ namespace OutGridTree.Window;
internal sealed class RpcService
{
public event Action<IEnumerable<string>>? HeadersReceived;
public event Action<object?>? RecordReceived;
private NamedPipeClientStream? pipe;
@@ -33,8 +35,19 @@ internal sealed class RpcService
var reader = new StreamReader(pipe);
while (reader.ReadLine(cts.Token) is string line)
{
var record = PSSerializer.Deserialize(Encoding.UTF8.GetString(Convert.FromBase64String(line)));
RecordReceived?.Invoke(record);
if (line.Split(": ", 2) is not [var header, var body])
{
continue;
}
if (header is "HEADERS")
{
HeadersReceived?.Invoke(body.Split(','));
}
else if (header is "RECORD")
{
var record = PSSerializer.Deserialize(Encoding.UTF8.GetString(Convert.FromBase64String(body)));
RecordReceived?.Invoke(record);
}
}
}
OutGridTree/OutGridTree.cs +12 -2
diff --git a/OutGridTree/OutGridTree.cs b/OutGridTree/OutGridTree.cs
index ecdc804..f5a4c47 100644
@@ -10,7 +10,7 @@ namespace OutGridTree;
[Cmdlet(VerbsData.Out, "GridTree")]
[Alias("ogt")]
public sealed class OutGridTree : Cmdlet
public sealed class OutGridTree : PSCmdlet
{
[Parameter(ValueFromPipeline = true)]
public PSObject InputObject { get; set; } = AutomationNull.Value;
@@ -18,6 +18,9 @@ public sealed class OutGridTree : Cmdlet
[Parameter(Mandatory = true)]
public string WindowExe { get; set; } = "";
[Parameter]
public string[]? Headers { get; set; }
#nullable disable
private NamedPipeServerStream pipe;
private Process windowProcess;
@@ -43,6 +46,11 @@ public sealed class OutGridTree : Cmdlet
pipe.WaitForConnection();
writer = new(pipe);
if (MyInvocation.BoundParameters.ContainsKey(nameof(Headers)) && Headers is not null)
{
writer.WriteLine($"HEADERS: {string.Join(",", Headers)}");
}
}
protected override void ProcessRecord()
@@ -54,7 +62,9 @@ public sealed class OutGridTree : Cmdlet
}
try
{
writer.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(PSSerializer.Serialize(InputObject))));
writer.WriteLine(
$"RECORD: {Convert.ToBase64String(Encoding.UTF8.GetBytes(PSSerializer.Serialize(InputObject)))}"
);
}
catch (IOException)
{