📄 ui/src/Views/MainWindow.axaml.cs
using System;
using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using Cfa.Ui.ViewModels;
using Nodify;

namespace Cfa.Ui.Views;

public sealed partial class MainWindow : Window
{
    private MainViewModel? model;

    public MainWindow()
    {
        AvaloniaXamlLoader.Load(this);
        DataContextChanged += OnDataContextChanged;
        Closed += (_, _) =>
        {
            if (model is not null)
            {
                model.PropertyChanged -= OnModelChanged;
            }
        };
    }

    private void OnDataContextChanged(object? sender, EventArgs args)
    {
        if (model is not null)
        {
            model.PropertyChanged -= OnModelChanged;
        }
        model = DataContext as MainViewModel;
        if (model is not null)
        {
            model.PropertyChanged += OnModelChanged;
        }
    }

    private void OnModelChanged(object? sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == nameof(MainViewModel.Scene))
        {
            Dispatcher.UIThread.Post(() => FitGraph(this, new RoutedEventArgs()), DispatcherPriority.Loaded);
        }
    }

    private void FitGraph(object? sender, RoutedEventArgs args)
    {
        var editor = this.FindControl<NodifyEditor>("Editor")!;
        editor.UpdateLayout();
        if (model?.Scene is { } scene)
        {
            var horizontal = Math.Max(Math.Abs(scene.Bounds.Left), Math.Abs(scene.Bounds.Right));
            var vertical = Math.Max(Math.Abs(scene.Bounds.Top), Math.Abs(scene.Bounds.Bottom));
            editor.FitToScreen(new Avalonia.Rect(-horizontal, -vertical, horizontal * 2, vertical * 2));
        }
    }
}