📄 OutGridTree.Window/MainWindow.axaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Interactivity;

namespace OutGridTree.Window;

internal sealed partial class MainWindow : Avalonia.Controls.Window
{
    private readonly RpcService rpcService;
    private readonly ObservableCollection<Row?> records = [];

    public MainWindow(RpcService rpcService)
    {
        this.rpcService = rpcService;
        rpcService.TitleReceived += OnTitleReceived;
        rpcService.OutputModeReceived += OnOutputModeReceived;
        rpcService.HeadersReceived += OnHeadersReceived;
        rpcService.RecordReceived += OnRecordReceived;

        InitializeComponent();

        Table.ItemsSource = records;
    }

    private void OnTitleReceived(string title)
    {
        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));
    }

    private void SetHeaders(IEnumerable<string> headers)
    {
        foreach (var (i, header) in headers.Select((h, i) => (i, h)))
        {
            Table.Columns.Add(
                new DataGridTextColumn()
                {
                    Header = header,
                    Binding = CompiledBinding.Create<Row?, Row?>(
                        r => r,
                        converter: new FuncValueConverter<Row?, string?>(r => r?.Headers.ElementAtOrDefault(i))
                    ),
                }
            );
        }
    }

    private void OnRecordReceived(Row? record)
    {
        Dispatcher.Post(() => AddRecord(record));
    }

    private void AddRecord(Row? record)
    {
        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;

        base.OnClosed(e);
    }
}