Copytrading-Views auf Designer-Muster umgestellt
Die drei Modul-Views wurden von komplett code-first (alle Controls im Konstruktor) auf das Standard-WinForms-Designer-Muster umgestellt (je X.cs + X.Designer.cs mit InitializeComponent), damit sie im Designer geöffnet und bearbeitet werden können: - ClosedTradesView, AccountSettingsView, MasterTradersView: alle wichtigen Steuerelemente (Panels, DataGridView mit expliziten Spalten via AutoGenerateColumns=false, PropertyGrid, ToolStrip, GroupBox, CheckedListBox, ComboBox, Buttons, Labels, Splitter) sind jetzt Designer-Felder. - Konsistent mit den Core-Views (DashboardView-Muster): Layout im Designer, Zellformate/Event-Wiring/Datenbindung im Code. Verifiziert: --smoke-ui grün (3 Accounts / 32 Trader; alle Views + Launcher OK). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f1451b547c
commit
4caba5bfd1
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence;
|
||||
@@ -14,18 +13,14 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
/// (PropertyGrid) und Account-Zuweisung (welche Accounts diesen Trader kopieren).
|
||||
/// Persistiert über das Repo und hält den Hot-Path-State
|
||||
/// (<see cref="CopyTradingState.Traders"/>) synchron.
|
||||
/// Layout im Designer (MasterTradersView.Designer.cs), Daten/Logik hier.
|
||||
/// </summary>
|
||||
public class MasterTradersView : Form
|
||||
public partial class MasterTradersView : Form
|
||||
{
|
||||
private readonly ITrackedTraderRepository _repo;
|
||||
private readonly TradingState _state;
|
||||
private readonly CopyTradingState _copyState;
|
||||
|
||||
private readonly DataGridView _grid = new();
|
||||
private readonly PropertyGrid _detail = new();
|
||||
private readonly CheckedListBox _accounts = new();
|
||||
private readonly Label _hint = new();
|
||||
|
||||
private BindingList<TrackedTrader> _binding = new();
|
||||
private TrackedTrader? _current;
|
||||
|
||||
@@ -35,66 +30,16 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
_state = state;
|
||||
_copyState = copyState;
|
||||
|
||||
Text = "Master-Trader";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Size = new Size(1180, 640);
|
||||
MinimumSize = new Size(820, 460);
|
||||
InitializeComponent();
|
||||
|
||||
colWinrate.DefaultCellStyle.Format = "F1";
|
||||
colPnl.DefaultCellStyle.Format = "F2";
|
||||
|
||||
// Toolbar
|
||||
var toolbar = new ToolStrip { GripStyle = ToolStripGripStyle.Hidden };
|
||||
var tsNew = new ToolStripButton("Neu");
|
||||
var tsSave = new ToolStripButton("Speichern");
|
||||
var tsDelete = new ToolStripButton("Löschen");
|
||||
var tsRefresh = new ToolStripButton("Aktualisieren");
|
||||
tsNew.Click += (_, _) => AddNew();
|
||||
tsSave.Click += (_, _) => SaveCurrent();
|
||||
tsDelete.Click += (_, _) => DeleteCurrent();
|
||||
tsRefresh.Click += (_, _) => LoadData();
|
||||
toolbar.Items.AddRange(new ToolStripItem[]
|
||||
{
|
||||
tsNew, tsSave, tsDelete, new ToolStripSeparator(), tsRefresh
|
||||
});
|
||||
|
||||
// Liste links
|
||||
_grid.Dock = DockStyle.Fill;
|
||||
_grid.ReadOnly = true;
|
||||
_grid.AllowUserToAddRows = false;
|
||||
_grid.AllowUserToDeleteRows = false;
|
||||
_grid.RowHeadersVisible = false;
|
||||
_grid.MultiSelect = false;
|
||||
_grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
_grid.AutoGenerateColumns = true;
|
||||
_grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||
_grid.SelectionChanged += (_, _) => OnSelectionChanged();
|
||||
|
||||
// Detail rechts: PropertyGrid + Account-Zuweisung
|
||||
_detail.Dock = DockStyle.Fill;
|
||||
_detail.ToolbarVisible = false;
|
||||
_detail.PropertySort = PropertySort.Categorized;
|
||||
|
||||
var accBox = new GroupBox { Text = "Zugewiesene Accounts (kopieren diesen Trader)", Dock = DockStyle.Bottom, Height = 190, Padding = new Padding(8) };
|
||||
_accounts.Dock = DockStyle.Fill;
|
||||
_accounts.CheckOnClick = true;
|
||||
accBox.Controls.Add(_accounts);
|
||||
|
||||
var right = new Panel { Dock = DockStyle.Right, Width = 460, Padding = new Padding(6, 0, 0, 0) };
|
||||
right.Controls.Add(_detail);
|
||||
right.Controls.Add(accBox);
|
||||
|
||||
var split = new Splitter { Dock = DockStyle.Right, Width = 5 };
|
||||
|
||||
var status = new Panel { Dock = DockStyle.Bottom, Height = 26 };
|
||||
_hint.Dock = DockStyle.Fill;
|
||||
_hint.TextAlign = ContentAlignment.MiddleLeft;
|
||||
_hint.ForeColor = Color.DimGray;
|
||||
_hint.Padding = new Padding(8, 0, 0, 0);
|
||||
status.Controls.Add(_hint);
|
||||
|
||||
Controls.Add(_grid);
|
||||
Controls.Add(split);
|
||||
Controls.Add(right);
|
||||
Controls.Add(status);
|
||||
Controls.Add(toolbar);
|
||||
grid.SelectionChanged += (_, _) => OnSelectionChanged();
|
||||
|
||||
LoadData();
|
||||
}
|
||||
@@ -103,63 +48,39 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
var traders = _repo.GetAll().OrderBy(t => t.Id).ToList();
|
||||
_binding = new BindingList<TrackedTrader>(traders);
|
||||
_grid.DataSource = _binding;
|
||||
FormatColumns();
|
||||
grid.DataSource = _binding;
|
||||
if (traders.Count > 0)
|
||||
_grid.CurrentCell = _grid.Rows[0].Cells[0];
|
||||
grid.CurrentCell = grid.Rows[0].Cells[0];
|
||||
else
|
||||
ClearDetail();
|
||||
_hint.Text = $"{traders.Count} Master-Trader geladen.";
|
||||
}
|
||||
|
||||
private void FormatColumns()
|
||||
{
|
||||
void Hide(string n) { if (_grid.Columns[n] is { } c) c.Visible = false; }
|
||||
void Head(string n, string h) { if (_grid.Columns[n] is { } c) c.HeaderText = h; }
|
||||
void Fmt(string n, string f) { if (_grid.Columns[n] is { } c) c.DefaultCellStyle.Format = f; }
|
||||
|
||||
Hide(nameof(TrackedTrader.Description));
|
||||
Hide(nameof(TrackedTrader.Reasoning));
|
||||
Hide(nameof(TrackedTrader.IsHidden));
|
||||
Hide(nameof(TrackedTrader.WinningTrades));
|
||||
|
||||
Head(nameof(TrackedTrader.Id), "#");
|
||||
Head(nameof(TrackedTrader.WalletAddress), "Wallet");
|
||||
Head(nameof(TrackedTrader.DisplayName), "Name");
|
||||
Head(nameof(TrackedTrader.Category), "Kategorie");
|
||||
Head(nameof(TrackedTrader.IsActive), "Aktiv");
|
||||
Head(nameof(TrackedTrader.TotalTrades), "Trades (7T)");
|
||||
Head(nameof(TrackedTrader.Winrate30t), "Winrate %");
|
||||
Head(nameof(TrackedTrader.TotalPnl), "PnL (7T)");
|
||||
Fmt(nameof(TrackedTrader.Winrate30t), "F1");
|
||||
Fmt(nameof(TrackedTrader.TotalPnl), "F2");
|
||||
lblHint.Text = $"{traders.Count} Master-Trader geladen.";
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
if (_grid.CurrentRow?.DataBoundItem is TrackedTrader t)
|
||||
if (grid.CurrentRow?.DataBoundItem is TrackedTrader t)
|
||||
BindDetail(t);
|
||||
}
|
||||
|
||||
private void BindDetail(TrackedTrader trader)
|
||||
{
|
||||
_current = trader;
|
||||
_detail.SelectedObject = trader;
|
||||
pgDetail.SelectedObject = trader;
|
||||
|
||||
_accounts.Items.Clear();
|
||||
clbAccounts.Items.Clear();
|
||||
foreach (var acc in _state.Accounts.Values.OrderBy(a => a.AccountId))
|
||||
{
|
||||
string label = string.IsNullOrEmpty(acc.Name) ? $"#{acc.AccountId}" : $"{acc.Name} (#{acc.AccountId}){(acc.IsDemo ? " · Demo" : "")}";
|
||||
int idx = _accounts.Items.Add(new AccountItem(acc.AccountId, label));
|
||||
_accounts.SetItemChecked(idx, trader.AssignedAccountIds.Contains(acc.AccountId));
|
||||
int idx = clbAccounts.Items.Add(new AccountItem(acc.AccountId, label));
|
||||
clbAccounts.SetItemChecked(idx, trader.AssignedAccountIds.Contains(acc.AccountId));
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearDetail()
|
||||
{
|
||||
_current = null;
|
||||
_detail.SelectedObject = null;
|
||||
_accounts.Items.Clear();
|
||||
pgDetail.SelectedObject = null;
|
||||
clbAccounts.Items.Clear();
|
||||
}
|
||||
|
||||
private void AddNew()
|
||||
@@ -167,25 +88,25 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
int nextId = _binding.Count > 0 ? _binding.Max(t => t.Id) + 1 : 1;
|
||||
var trader = new TrackedTrader { Id = nextId, DisplayName = $"Neuer Trader {nextId}" };
|
||||
_binding.Add(trader);
|
||||
_grid.CurrentCell = _grid.Rows[_binding.Count - 1].Cells[0];
|
||||
_hint.Text = $"Neuer Master-Trader #{nextId} – Felder ausfüllen und Speichern.";
|
||||
grid.CurrentCell = grid.Rows[_binding.Count - 1].Cells[0];
|
||||
lblHint.Text = $"Neuer Master-Trader #{nextId} – Felder ausfüllen und Speichern.";
|
||||
}
|
||||
|
||||
private void SaveCurrent()
|
||||
{
|
||||
if (_current == null) { _hint.Text = "Kein Trader ausgewählt."; return; }
|
||||
if (_current == null) { lblHint.Text = "Kein Trader ausgewählt."; return; }
|
||||
|
||||
_current.AssignedAccountIds = _accounts.CheckedItems.Cast<AccountItem>().Select(a => a.Id).ToHashSet();
|
||||
_current.AssignedAccountIds = clbAccounts.CheckedItems.Cast<AccountItem>().Select(a => a.Id).ToHashSet();
|
||||
|
||||
_repo.Upsert(_current);
|
||||
_copyState.Traders[_current.Id] = _current;
|
||||
_grid.Refresh();
|
||||
_hint.Text = $"Gespeichert: #{_current.Id} {_current.DisplayName} ({_current.AssignedAccountIds.Count} Account(s)) um {DateTime.Now:HH:mm:ss}.";
|
||||
grid.Refresh();
|
||||
lblHint.Text = $"Gespeichert: #{_current.Id} {_current.DisplayName} ({_current.AssignedAccountIds.Count} Account(s)) um {DateTime.Now:HH:mm:ss}.";
|
||||
}
|
||||
|
||||
private void DeleteCurrent()
|
||||
{
|
||||
if (_current == null) { _hint.Text = "Kein Trader ausgewählt."; return; }
|
||||
if (_current == null) { lblHint.Text = "Kein Trader ausgewählt."; return; }
|
||||
var id = _current.Id;
|
||||
if (MessageBox.Show($"Master-Trader #{id} ({_current.DisplayName}) wirklich löschen?",
|
||||
"Löschen bestätigen", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
|
||||
@@ -195,7 +116,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
_copyState.Traders.TryRemove(id, out _);
|
||||
_binding.Remove(_current);
|
||||
ClearDetail();
|
||||
_hint.Text = $"Master-Trader #{id} gelöscht.";
|
||||
lblHint.Text = $"Master-Trader #{id} gelöscht.";
|
||||
}
|
||||
|
||||
private sealed record AccountItem(int Id, string Label)
|
||||
|
||||
Reference in New Issue
Block a user