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:
@@ -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>
|
||||
@@ -0,0 +1,26 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using PolyTrader.App.Avalonia.ViewModels;
|
||||
|
||||
namespace PolyTrader.App.Avalonia.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Zeigt ein beliebiges Einstellungsobjekt als kategorisiertes Formular. Ersetzt das
|
||||
/// WinForms-PropertyGrid an allen vier Stellen (Server-Settings, Account-Einstellungen,
|
||||
/// Master-Trader, ResolutionFarming) – ein Aufruf je Fenster, kein Feld-Code.
|
||||
///
|
||||
/// Änderungen wirken direkt auf dem übergebenen Objekt; das Speichern (Datei/DB) bleibt
|
||||
/// Sache des jeweiligen Fensters – genau wie zuvor beim PropertyGrid.
|
||||
/// </summary>
|
||||
public partial class SettingsEditor : UserControl
|
||||
{
|
||||
public SettingsEditor() => AvaloniaXamlLoader.Load(this);
|
||||
|
||||
/// <summary>Setzt das anzuzeigende Objekt (oder <c>null</c>, um zu leeren).</summary>
|
||||
public void Show(object? target)
|
||||
{
|
||||
var list = this.FindControl<ItemsControl>("sections")!;
|
||||
list.ItemsSource = target == null ? null : SettingsModelBuilder.Build(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user