Avalonia-Grundgeruest: plattformneutrale App laeuft (Shell + erstes Fenster)
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>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:shell="using:PolyTrader.App.Avalonia.Shell"
|
||||
x:Class="PolyTrader.App.Avalonia.Controls.WindowMenuBar"
|
||||
x:DataType="shell:WindowMenuModel">
|
||||
|
||||
<!--
|
||||
Gemeinsame Fenster-Menüleiste, die auf JEDEM PolyTrader-Fenster oben sitzt.
|
||||
Alle Fenster stehen nebeneinander (nicht in einem Untermenü versteckt), das aktuelle
|
||||
fett, offene mit Haken. Die rechte Aktion ist kontextabhängig.
|
||||
|
||||
Vollständig deklarativ: die Einträge kommen als Datenmodell aus WindowMenuModel.Entries,
|
||||
hier wird nur beschrieben, wie ein Eintrag aussieht. Kein Aufbau zur Laufzeit im Code.
|
||||
(Avalonia kennt kein ToolStripItemAlignment.Right — die rechte Ausrichtung entsteht
|
||||
dadurch, dass der letzte Eintrag im DockPanel rechts angedockt wird.)
|
||||
-->
|
||||
<Border Background="#F3F3F3" BorderBrush="#DDDDDD" BorderThickness="0,0,0,1" Padding="4,2">
|
||||
<ItemsControl ItemsSource="{Binding Entries}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="shell:WindowMenuEntry">
|
||||
<Button Command="{Binding Command}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="8,4"
|
||||
Margin="0,0,2,0">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Image Source="{Binding Icon}"
|
||||
Width="20" Height="20"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding Icon, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<TextBlock Text="{Binding CheckMark}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="#2E7D32" />
|
||||
<TextBlock Text="{Binding Title}"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="{Binding FontWeight}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,30 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using PolyTrader.App.Avalonia.Shell;
|
||||
using PolyTrader.Core.Modularity;
|
||||
|
||||
namespace PolyTrader.App.Avalonia.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Code-Behind der Fenster-Menüleiste: nur Verdrahtung, kein Layout (siehe Layout-Regel).
|
||||
/// Jedes Fenster ruft <see cref="Attach"/> auf und bekommt damit dieselbe Leiste.
|
||||
/// </summary>
|
||||
public partial class WindowMenuBar : UserControl
|
||||
{
|
||||
private WindowMenuModel? _model;
|
||||
|
||||
public WindowMenuBar() => AvaloniaXamlLoader.Load(this);
|
||||
|
||||
/// <summary>
|
||||
/// Verbindet die Leiste mit der Shell. <paramref name="currentViewId"/> ist <c>null</c> für den
|
||||
/// Launcher (rechte Aktion „Beenden"), sonst die View-ID (rechte Aktion „Fenster schließen").
|
||||
/// Die Event-Registrierung wird beim Entladen wieder gelöst – kein Leak.
|
||||
/// </summary>
|
||||
public void Attach(IModuleUiHost host, string? currentViewId, Window owner)
|
||||
{
|
||||
_model = new WindowMenuModel(host, currentViewId, owner.Close);
|
||||
DataContext = _model;
|
||||
owner.Closed += (_, _) => _model?.Detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user