Commit: b46c8ba
Parent: 759a42a

Output selected records

Mårten Åsberg committed on 2026-04-09 at 14:59
OutGridTree.Window/MainWindow.axaml +31 -24
diff --git a/OutGridTree.Window/MainWindow.axaml b/OutGridTree.Window/MainWindow.axaml
index 00a1097..a605357 100644
@@ -12,28 +12,35 @@
<c:IsLeafConverter x:Key="isLeafConverter"/>
<c:PsObjectPropertiesConverter x:Key="psObjectPropertiesConverter"/>
</Window.Resources>
<DataGrid Name="Table" AutoGenerateColumns="False" IsReadOnly="True"
GridLinesVisibility="All" BorderThickness="1"
SelectionMode="Extended" RowDetailsVisibilityMode="VisibleWhenSelected"
CanUserSortColumns="True" CanUserReorderColumns="True" CanUserResizeColumns="True">
<DataGrid.RowDetailsTemplate>
<DataTemplate x:DataType="{x:Type w:Row}">
<TreeView ItemsSource="{Binding Entry.Properties}">
<TreeView.ItemTemplate>
<TreeDataTemplate x:DataType="{x:Type ps:PSPropertyInfo}" ItemsSource="{Binding Value, Converter={StaticResource psObjectPropertiesConverter}}">
<Grid ColumnDefinitions="Auto,Auto" ColumnSpacing="10">
<TextBlock Text="{Binding Name}" Padding="2" />
<TextBox Text="{Binding Value}"
Grid.Column="1"
IsVisible="{Binding $parent.DataContext.Value, Converter={StaticResource isLeafConverter}}"
IsReadOnly="True"
BorderBrush="{x:Null}"
Padding="5,2" />
</Grid>
</TreeDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
<Grid RowDefinitions="*,Auto">
<DataGrid Name="Table" AutoGenerateColumns="False" IsReadOnly="True"
GridLinesVisibility="All" BorderThickness="1"
Grid.Row="0"
SelectionMode="Extended" RowDetailsVisibilityMode="VisibleWhenSelected"
CanUserSortColumns="True" CanUserReorderColumns="True" CanUserResizeColumns="True">
<DataGrid.RowDetailsTemplate>
<DataTemplate x:DataType="{x:Type w:Row}">
<TreeView ItemsSource="{Binding Entry.Properties}">
<TreeView.ItemTemplate>
<TreeDataTemplate x:DataType="{x:Type ps:PSPropertyInfo}" ItemsSource="{Binding Value, Converter={StaticResource psObjectPropertiesConverter}}">
<Grid ColumnDefinitions="Auto,Auto" ColumnSpacing="10">
<TextBlock Text="{Binding Name}" Padding="2" />
<TextBox Text="{Binding Value}"
Grid.Column="1"
IsVisible="{Binding $parent.DataContext.Value, Converter={StaticResource isLeafConverter}}"
IsReadOnly="True"
BorderBrush="{x:Null}"
Padding="5,2" />
</Grid>
</TreeDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
<StackPanel Name="Buttons" Grid.Row="1" Orientation="Horizontal" Spacing="10" HorizontalAlignment="Right" IsVisible="False">
<Button Content="OK" Click="OnOkClick"/>
<Button Content="Cancel" Click="OnCancelClick"/>
</StackPanel>
</Grid>
</Window>
OutGridTree.Window/MainWindow.axaml.cs +32 -0
diff --git a/OutGridTree.Window/MainWindow.axaml.cs b/OutGridTree.Window/MainWindow.axaml.cs
index ae80449..4b55a39 100644
@@ -5,6 +5,7 @@ using System.Linq;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Interactivity;
namespace OutGridTree.Window;
@@ -17,6 +18,7 @@ internal sealed partial class MainWindow : Avalonia.Controls.Window
{
this.rpcService = rpcService;
rpcService.TitleReceived += OnTitleReceived;
rpcService.OutputModeReceived += OnOutputModeReceived;
rpcService.HeadersReceived += OnHeadersReceived;
rpcService.RecordReceived += OnRecordReceived;
@@ -30,6 +32,27 @@ internal sealed partial class MainWindow : Avalonia.Controls.Window
Dispatcher.Post(() => Title = title);
}
private void OnOutputModeReceived(OutputMode mode)
{
Dispatcher.Post(() => SetOutputMode(mode));
}
private void SetOutputMode(OutputMode mode)
{
if (mode is OutputMode.None)
{
return;
}
Table.SelectionMode = mode switch
{
OutputMode.Single => DataGridSelectionMode.Single,
OutputMode.Multiple => DataGridSelectionMode.Extended,
_ => DataGridSelectionMode.Single,
};
Buttons.IsVisible = true;
}
private void OnHeadersReceived(IEnumerable<string> headers)
{
Dispatcher.Post(() => SetHeaders(headers));
@@ -62,9 +85,18 @@ internal sealed partial class MainWindow : Avalonia.Controls.Window
records.Add(record);
}
private void OnOkClick(object? sender, RoutedEventArgs args)
{
rpcService.SendSelected(Table.SelectedItems.OfType<Row?>().Select(records.IndexOf));
Close();
}
private void OnCancelClick(object? sender, RoutedEventArgs args) => Close();
protected override void OnClosed(EventArgs e)
{
rpcService.TitleReceived -= OnTitleReceived;
rpcService.OutputModeReceived -= OnOutputModeReceived;
rpcService.HeadersReceived -= OnHeadersReceived;
rpcService.RecordReceived -= OnRecordReceived;
OutGridTree.Window/OutputMode.cs +8 -0
diff --git a/OutGridTree.Window/OutputMode.cs b/OutGridTree.Window/OutputMode.cs
new file mode 100644
index 0000000..70246c7
@@ -0,0 +1,8 @@
namespace OutGridTree.Window;
internal enum OutputMode
{
None,
Single,
Multiple,
}
OutGridTree.Window/RpcService.cs +19 -1
diff --git a/OutGridTree.Window/RpcService.cs b/OutGridTree.Window/RpcService.cs
index 1661dd0..36a1420 100644
@@ -11,6 +11,7 @@ namespace OutGridTree.Window;
internal sealed class RpcService
{
public event Action<string>? TitleReceived;
public event Action<OutputMode>? OutputModeReceived;
public event Action<IEnumerable<string>>? HeadersReceived;
public event Action<Row?>? RecordReceived;
@@ -20,7 +21,7 @@ internal sealed class RpcService
public void Start(string pipeName)
{
pipe = new(".", pipeName, PipeDirection.In);
pipe = new(".", pipeName, PipeDirection.InOut);
thread = new(Run);
thread.Start();
}
@@ -44,6 +45,10 @@ internal sealed class RpcService
{
TitleReceived?.Invoke(body);
}
else if (header is "OUTPUT_MODE")
{
OutputModeReceived?.Invoke(Enum.Parse<OutputMode>(body));
}
else if (header is "HEADERS")
{
var headers = JsonSerializer.Deserialize<string[]>(body);
@@ -65,6 +70,19 @@ internal sealed class RpcService
}
}
public void SendSelected(IEnumerable<int> selectedIndices)
{
if (pipe is null)
{
return;
}
cts.Cancel();
var writer = new StreamWriter(pipe);
writer.WriteLine($"SELECT: {JsonSerializer.Serialize(selectedIndices)}");
writer.Flush();
}
public void Stop()
{
cts.Cancel();
OutGridTree/OutGridTree.cs +39 -2
diff --git a/OutGridTree/OutGridTree.cs b/OutGridTree/OutGridTree.cs
index a260c9a..596921e 100644
@@ -28,6 +28,10 @@ public sealed class OutGridTree : PSCmdlet
private bool hasSentHeaders = false;
private ColumnFormatter[]? columnFormats;
[Parameter]
public OutputMode OutputMode { get; set; } = OutputMode.None;
private readonly List<PSObject> receivedObjects = [];
#nullable disable
private NamedPipeServerStream pipe;
private Process windowProcess;
@@ -38,7 +42,7 @@ public sealed class OutGridTree : PSCmdlet
protected override void BeginProcessing()
{
var pipeName = Path.GetTempFileName();
pipe = new(pipeName, PipeDirection.Out);
pipe = new(pipeName, PipeDirection.InOut);
windowProcess = Process.Start(
new ProcessStartInfo()
@@ -63,6 +67,11 @@ public sealed class OutGridTree : PSCmdlet
writer.WriteLine($"TITLE: {MyInvocation.Line}");
}
if (MyInvocation.BoundParameters.ContainsKey(nameof(OutputMode)) && OutputMode is not OutputMode.None)
{
writer.WriteLine($"OUTPUT_MODE: {OutputMode}");
}
if (MyInvocation.BoundParameters.ContainsKey(nameof(Headers)) && Headers is not null)
{
writer.WriteLine($"HEADERS: {JsonSerializer.Serialize(Headers)}");
@@ -77,6 +86,12 @@ public sealed class OutGridTree : PSCmdlet
TerminateDueToWindowClosed();
return;
}
if (OutputMode is not OutputMode.None)
{
receivedObjects.Add(InputObject);
}
try
{
if (!hasSentHeaders)
@@ -174,11 +189,33 @@ public sealed class OutGridTree : PSCmdlet
protected override void EndProcessing()
{
// TODO: Wait for window to close
if (pipe.IsConnected)
{
writer.Flush();
}
if (OutputMode is not OutputMode.None)
{
var selectedIndices = ReceiveSelectedIndices();
WriteObject(selectedIndices.Select(i => receivedObjects[i]), enumerateCollection: true);
}
}
private int[] ReceiveSelectedIndices()
{
var reader = new StreamReader(pipe);
while (reader.ReadLine() is string line)
{
var split = line.Split([": "], 2, StringSplitOptions.None);
if (split.Length is not 2 || split[0] is not "SELECT")
{
continue;
}
return JsonSerializer.Deserialize<int[]>(split[1]) ?? [];
}
return [];
}
protected override void StopProcessing()
OutGridTree/OutputMode.cs +8 -0
diff --git a/OutGridTree/OutputMode.cs b/OutGridTree/OutputMode.cs
new file mode 100644
index 0000000..3342fea
@@ -0,0 +1,8 @@
namespace OutGridTree;
public enum OutputMode
{
None,
Single,
Multiple,
}