Neues Projekt src/PolyTrader.App.Avalonia (net10.0, Avalonia 12.1.1, LiveCharts2 2.0.5) - laeuft unter Windows und Linux aus derselben Quelle. Enthalten: - Program.cs mit bewusst getrenntem Aufbau: BuildHost() stellt Persistenz, Dienste und Module ohne jeden UI-Bezug zusammen, erst Main haengt Avalonia daran. Damit ist der kopflose Linux-Betrieb (--headless, Stufe L2) ohne Umbau erreichbar - der Schalter ist bereits drin. - AvaloniaUiHost als IModuleUiHost: gleiche Semantik wie die WinForms-Shell (ein Fenster je View, offene nach vorn holen, alles maximiert). - Fenster-Menueleiste vollstaendig DEKLARATIV (Controls/WindowMenuBar.axaml + ItemsSource auf WindowMenuModel.Entries). Loest die alte Fassung ab, die menu.Items zur Laufzeit leerte und neu befuellte - genau der Punkt, den die neue Layout-Regel verbietet. - ViewIcons fuer Avalonia: dieselben Schluessel und dieselben PNGs wie zuvor, Core und Module bleiben unveraendert. - LauncherWindow, JobsWindow, ShutdownConfirmWindow (inkl. der 10-Sekunden-Sperre). - --smoke-ui als Nachfolger der WinForms-Konstruktionspruefung; startet den Host bewusst NICHT, damit ein reiner UI-Test nicht die Trading-Engine gegen echte Endpunkte anwirft. Dabei aufgeraeumt: - JobManager.Jobs: BindingList -> ObservableCollection. BindingList implementiert kein INotifyCollectionChanged; neu registrierte Jobs waeren in Avalonia unsichtbar geblieben. - StartupHydrationService aufgeteilt in CoreStateHydrationService (Core: Accounts + Demo-Positionen) und CopyTradingHydrationService (Modul: Settings + Trader). Behebt einen latenten Fehler: bei deaktiviertem Copytrading-Modul waeren die Accounts gar nicht mehr hydriert worden, obwohl sie zum Core gehoeren. Verifiziert: Solution baut, 442 Tests gruen, --smoke-ui gruen, die App laeuft real mit Fenster und allen Trading-Diensten (Market-Sync, Master-Trader-Analyse, RF-Scanner), und publisht fuer linux-x64. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
42 lines
1.6 KiB
C#
42 lines
1.6 KiB
C#
using System.Threading.Tasks;
|
||
using Avalonia.Controls;
|
||
using Avalonia.Interactivity;
|
||
using Avalonia.Markup.Xaml;
|
||
using PolyTrader.Core.Modularity;
|
||
using PolyTraderSharp.Models;
|
||
using PolyTraderSharp.Services;
|
||
|
||
namespace PolyTrader.App.Avalonia.Views
|
||
{
|
||
/// <summary>
|
||
/// Hintergrund-Jobs (JobManager). Verhalten wie bisher: „Run Now" löst den ManualTrigger aus,
|
||
/// „Aktiv" schaltet den Job über die Bindung. Layout vollständig in JobsWindow.axaml.
|
||
/// </summary>
|
||
public partial class JobsWindow : Window
|
||
{
|
||
public JobsWindow() => AvaloniaXamlLoader.Load(this);
|
||
|
||
public JobsWindow(IModuleUiHost host, JobManager jobManager) : this()
|
||
{
|
||
this.FindControl<Controls.WindowMenuBar>("menuBar")!.Attach(host, "core.jobs", this);
|
||
|
||
var grid = this.FindControl<DataGrid>("gridJobs")!;
|
||
grid.ItemsSource = jobManager.Jobs;
|
||
|
||
this.FindControl<Button>("btnRefresh")!.Click += (_, _) =>
|
||
{
|
||
// Die Zeilen aktualisieren sich über INotifyPropertyChanged von selbst; der Knopf
|
||
// erzwingt lediglich ein Neuzeichnen (wie das frühere dgvJobs.Refresh()).
|
||
grid.InvalidateVisual();
|
||
};
|
||
}
|
||
|
||
/// <summary>Manuellen Lauf anstoßen – bewusst im Hintergrund, damit die Oberfläche nicht blockiert.</summary>
|
||
private void OnRunNowClick(object? sender, RoutedEventArgs e)
|
||
{
|
||
if (sender is Button { DataContext: JobStatusRow job } && job.ManualTriggerAction != null)
|
||
_ = Task.Run(() => job.ManualTriggerAction.Invoke());
|
||
}
|
||
}
|
||
}
|