Settings nach Avalonia - PropertyGrid durch kategorisierten Editor ersetzt

Der PropertyGrid-Ersatz ist EIN wiederverwendbares Steuerelement statt Handarbeit je Feld:
Controls/SettingsEditor zeigt ein beliebiges Einstellungsobjekt nach Richards Vorlage -
Kategorie-Ueberschrift, Beschriftung links, Feld rechts, Erklaerung klein darunter.

- SettingsModelBuilder liest die Attribute, die fuers PropertyGrid ohnehin gepflegt waren:
  [Category] gruppiert, [DisplayName] beschriftet, [Description] wird zum Hinweistext,
  [Browsable(false)] blendet aus (Watchdog-Token, Lizenzschluessel bleiben unsichtbar).
  Ergebnis fuer ServerSettings: 6 Abschnitte, 15 Felder - ohne eine Zeile Feld-Code.
- Layout-Regel gewahrt: WELCHE Felder es gibt, kommt als Daten; WIE ein Feld aussieht,
  steht deklarativ als DataTemplate je Feldtyp (Text/Zahl/Ja-Nein/Auswahl/Nur-Lese).
- Damit sind auch die drei restlichen PropertyGrid-Stellen (Account-Einstellungen,
  Master-Trader, ResolutionFarming) mit je einem Aufruf erledigt.

SettingsWindow: Server-Settings + Polymarket-Accounts, Master-Key erzeugen,
OpenRouter-Key/Watchdog-Token setzen, Test-Heartbeat. Rueckmeldungen laufen ueber die
Statuszeile statt ueber Dialoge - nur echte Entscheidungen bekommen einen Dialog
(neu: Views/DialogWindow fuer Hinweis/Rueckfrage/maskierte Eingabe, Avalonia hat keine MessageBox).

Nebenbei einen offenen Punkt der Linux-Analyse erledigt: Schluesseldateien (master.key,
openrouter.key) werden jetzt per File.SetUnixFileMode auf 600 gesetzt. Auf Linux legt
File.WriteAllText sonst mit ueblicher umask 644 an - weltweit lesbar.

Lizenzdialog bewusst NICHT portiert: haengt am alten LicenseLabrador-SDK, das mit der
Deploymentcenter-Anbindung (P3c) ohnehin ersetzt wird - waere Wegwerfarbeit.

Smoke-UI prueft jetzt zusaetzlich die Feldzahl des Editors: ein Fenster kann fehlerfrei
konstruieren und trotzdem leer sein, wenn die Attribute verlorengehen.

Verifiziert: Solution baut, 442 Tests gruen, --smoke-ui gruen (5 Fenster + Editor-Pruefung),
Linux-Publish laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-06 20:55:47 +02:00
co-authored by Claude Opus 5
parent 0b8728b25f
commit 4ba8149e64
9 changed files with 873 additions and 1 deletions
@@ -0,0 +1,124 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:PolyTrader.App.Avalonia.ViewModels"
x:Class="PolyTrader.App.Avalonia.Controls.SettingsEditor">
<!--
Ersatz für das WinForms-PropertyGrid. Aufbau nach Vorgabe:
Kategorie-Überschrift (fett), darunter je Feld eine Zeile aus Beschriftung links und
Steuerelement rechts; ein etwaiger Erklärungstext steht klein unter dem Feld.
Vollständig deklarativ: WELCHE Felder es gibt, liefert das Datenmodell
(SettingsModelBuilder liest Category/DisplayName/Description/Browsable vom Einstellungs-
objekt). WIE ein Feld aussieht, steht hier — je Feldtyp ein DataTemplate. Damit bleibt die
Layout-Regel gewahrt und alle Einstellungsfenster sehen automatisch gleich aus.
-->
<UserControl.Resources>
<!-- Einheitliche Beschriftungsspalte: sorgt für die saubere Flucht aller Felder. -->
<x:Double x:Key="LabelWidth">210</x:Double>
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="TextBlock.sectionTitle">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="0,16,0,8" />
</Style>
<Style Selector="TextBlock.fieldLabel">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,0,12,0" />
</Style>
<Style Selector="TextBlock.fieldHint">
<Setter Property="FontSize" Value="11" />
<Setter Property="Foreground" Value="#777777" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="Margin" Value="0,2,0,0" />
</Style>
<Style Selector="Grid.fieldRow">
<Setter Property="Margin" Value="0,0,0,8" />
</Style>
</UserControl.Styles>
<ScrollViewer>
<ItemsControl Name="sections" Margin="16,0,16,16">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:SettingsSection">
<StackPanel>
<TextBlock Classes="sectionTitle" Text="{Binding Title}" />
<ItemsControl ItemsSource="{Binding Fields}">
<ItemsControl.DataTemplates>
<!-- Freitext -->
<DataTemplate DataType="vm:TextSettingsField">
<Grid Classes="fieldRow" ColumnDefinitions="210,*">
<TextBlock Grid.Column="0" Classes="fieldLabel" Text="{Binding Label}" />
<StackPanel Grid.Column="1">
<TextBox Text="{Binding Value, Mode=TwoWay}" IsEnabled="{Binding IsEditable}" />
<TextBlock Classes="fieldHint" Text="{Binding Description}"
IsVisible="{Binding HasDescription}" />
</StackPanel>
</Grid>
</DataTemplate>
<!-- Ganzzahl -->
<DataTemplate DataType="vm:IntSettingsField">
<Grid Classes="fieldRow" ColumnDefinitions="210,*">
<TextBlock Grid.Column="0" Classes="fieldLabel" Text="{Binding Label}" />
<StackPanel Grid.Column="1">
<TextBox Text="{Binding Value, Mode=TwoWay}" IsEnabled="{Binding IsEditable}"
MaxWidth="160" HorizontalAlignment="Left" />
<TextBlock Classes="fieldHint" Text="{Binding Description}"
IsVisible="{Binding HasDescription}" />
</StackPanel>
</Grid>
</DataTemplate>
<!-- Ja/Nein -->
<DataTemplate DataType="vm:BoolSettingsField">
<Grid Classes="fieldRow" ColumnDefinitions="210,*">
<TextBlock Grid.Column="0" Classes="fieldLabel" Text="{Binding Label}" />
<StackPanel Grid.Column="1">
<CheckBox IsChecked="{Binding Value, Mode=TwoWay}" IsEnabled="{Binding IsEditable}" />
<TextBlock Classes="fieldHint" Text="{Binding Description}"
IsVisible="{Binding HasDescription}" />
</StackPanel>
</Grid>
</DataTemplate>
<!-- Auswahl -->
<DataTemplate DataType="vm:ChoiceSettingsField">
<Grid Classes="fieldRow" ColumnDefinitions="210,*">
<TextBlock Grid.Column="0" Classes="fieldLabel" Text="{Binding Label}" />
<StackPanel Grid.Column="1">
<ComboBox ItemsSource="{Binding Options}"
SelectedItem="{Binding Value, Mode=TwoWay}"
IsEnabled="{Binding IsEditable}"
HorizontalAlignment="Stretch" />
<TextBlock Classes="fieldHint" Text="{Binding Description}"
IsVisible="{Binding HasDescription}" />
</StackPanel>
</Grid>
</DataTemplate>
<!-- Reine Anzeige -->
<DataTemplate DataType="vm:ReadOnlySettingsField">
<Grid Classes="fieldRow" ColumnDefinitions="210,*">
<TextBlock Grid.Column="0" Classes="fieldLabel" Text="{Binding Label}" />
<StackPanel Grid.Column="1">
<SelectableTextBlock Text="{Binding Value}" VerticalAlignment="Center"
Foreground="#444444" />
<TextBlock Classes="fieldHint" Text="{Binding Description}"
IsVisible="{Binding HasDescription}" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.DataTemplates>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</UserControl>