From 76007db93fdc9b1815c8be4125c6effd48b7a8d0 Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 6 Jul 2026 10:15:04 +0200 Subject: [PATCH] =?UTF-8?q?Modul-Views:=20parameterloser=20Ctor=20+=20Init?= =?UTF-8?q?ialize()=20(Designer-=C3=B6ffenbar)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der VS-WinForms-Designer braucht einen parameterlosen Konstruktor, um eine Form zu instanziieren. Die drei Views hatten nur einen DI-Ctor -> Designer hätte sie nicht öffnen können. Umgestellt auf das Core-View-Muster (DashboardView): - Parameterloser Ctor: InitializeComponent() + Event-Wiring. - Initialize(deps): Abhängigkeiten setzen + Daten laden. - Felder nullable + Null-Guards in den Handlern. - CopyTradingModule.RegisterUi: new View() + view.Initialize(...) statt DI-Ctor. Verifiziert: Build grün, --smoke-ui grün (3 Accounts / 32 Trader, alle Views OK). Co-Authored-By: Claude Opus 4.8 --- .../CopyTradingModule.cs | 39 +++++++++++++------ .../Ui/AccountSettingsView.cs | 26 ++++++++----- .../Ui/ClosedTradesView.cs | 26 ++++++++----- .../Ui/MasterTradersView.cs | 27 ++++++++----- 4 files changed, 76 insertions(+), 42 deletions(-) diff --git a/src/PolyTrader.Modules.CopyTrading/CopyTradingModule.cs b/src/PolyTrader.Modules.CopyTrading/CopyTradingModule.cs index 8e83513..5155931 100644 --- a/src/PolyTrader.Modules.CopyTrading/CopyTradingModule.cs +++ b/src/PolyTrader.Modules.CopyTrading/CopyTradingModule.cs @@ -62,10 +62,15 @@ namespace PolyTrader.Modules.CopyTrading Title = "Master-Trader", Group = "CopyTrading", Order = 100, - CreateForm = () => new MasterTradersView( - services.GetRequiredService(), - services.GetRequiredService(), - services.GetRequiredService()) + CreateForm = () => + { + var view = new MasterTradersView(); + view.Initialize( + services.GetRequiredService(), + services.GetRequiredService(), + services.GetRequiredService()); + return view; + } }); host.RegisterView(new ModuleView @@ -74,10 +79,15 @@ namespace PolyTrader.Modules.CopyTrading Title = "Geschlossene Copytrades", Group = "CopyTrading", Order = 110, - CreateForm = () => new ClosedTradesView( - services.GetRequiredService(), - services.GetRequiredService(), - services.GetRequiredService()) + CreateForm = () => + { + var view = new ClosedTradesView(); + view.Initialize( + services.GetRequiredService(), + services.GetRequiredService(), + services.GetRequiredService()); + return view; + } }); host.RegisterView(new ModuleView @@ -86,10 +96,15 @@ namespace PolyTrader.Modules.CopyTrading Title = "Copytrading-Account-Einstellungen", Group = "CopyTrading", Order = 120, - CreateForm = () => new AccountSettingsView( - services.GetRequiredService(), - services.GetRequiredService(), - services.GetRequiredService()) + CreateForm = () => + { + var view = new AccountSettingsView(); + view.Initialize( + services.GetRequiredService(), + services.GetRequiredService(), + services.GetRequiredService()); + return view; + } }); } diff --git a/src/PolyTrader.Modules.CopyTrading/Ui/AccountSettingsView.cs b/src/PolyTrader.Modules.CopyTrading/Ui/AccountSettingsView.cs index 250259c..8b87c80 100644 --- a/src/PolyTrader.Modules.CopyTrading/Ui/AccountSettingsView.cs +++ b/src/PolyTrader.Modules.CopyTrading/Ui/AccountSettingsView.cs @@ -15,28 +15,34 @@ namespace PolyTrader.Modules.CopyTrading.Ui /// public partial class AccountSettingsView : Form { - private readonly ICopyTradingAccountSettingsRepository _repo; - private readonly TradingState _state; - private readonly CopyTradingState _copyState; + private ICopyTradingAccountSettingsRepository? _repo; + private TradingState? _state; + private CopyTradingState? _copyState; private CopyTradingAccountSettings? _current; - public AccountSettingsView(ICopyTradingAccountSettingsRepository repo, TradingState state, CopyTradingState copyState) + // Parameterloser Konstruktor für den WinForms-Designer. + public AccountSettingsView() { - _repo = repo; - _state = state; - _copyState = copyState; - InitializeComponent(); cmbAccounts.SelectedIndexChanged += (_, _) => LoadSelected(); btnSave.Click += (_, _) => Save(); + } + /// Injiziert die Abhängigkeiten (nach der DI-Auflösung) und füllt die Auswahl. + public void Initialize(ICopyTradingAccountSettingsRepository repo, TradingState state, CopyTradingState copyState) + { + _repo = repo; + _state = state; + _copyState = copyState; PopulateAccounts(); } private void PopulateAccounts() { + if (_state == null) return; + var items = _state.Accounts.Values .OrderBy(a => a.AccountId) .Select(a => new AccountItem(a.AccountId, string.IsNullOrEmpty(a.Name) ? $"#{a.AccountId}" : $"{a.Name} (#{a.AccountId}){(a.IsDemo ? " · Demo" : "")}")) @@ -52,7 +58,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui private void LoadSelected() { - if (cmbAccounts.SelectedItem is not AccountItem item) return; + if (_repo == null || cmbAccounts.SelectedItem is not AccountItem item) return; _current = _repo.Get(item.Id) ?? new CopyTradingAccountSettings { AccountId = item.Id }; pgSettings.SelectedObject = _current; lblHint.Text = $"Einstellungen für Account #{item.Id}."; @@ -60,7 +66,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui private void Save() { - if (_current == null) return; + if (_current == null || _repo == null || _copyState == null) return; _repo.Upsert(_current); _copyState.AccountSettings[_current.AccountId] = _current; lblHint.Text = $"Gespeichert für Account #{_current.AccountId} um {DateTime.Now:HH:mm:ss}."; diff --git a/src/PolyTrader.Modules.CopyTrading/Ui/ClosedTradesView.cs b/src/PolyTrader.Modules.CopyTrading/Ui/ClosedTradesView.cs index 1146c45..c5c39c1 100644 --- a/src/PolyTrader.Modules.CopyTrading/Ui/ClosedTradesView.cs +++ b/src/PolyTrader.Modules.CopyTrading/Ui/ClosedTradesView.cs @@ -15,16 +15,13 @@ namespace PolyTrader.Modules.CopyTrading.Ui /// public partial class ClosedTradesView : Form { - private readonly ICopyTradeLogRepository _tradeLog; - private readonly TradingState _state; - private readonly CopyTradingState _copyState; + private ICopyTradeLogRepository? _tradeLog; + private TradingState? _state; + private CopyTradingState? _copyState; - public ClosedTradesView(ICopyTradeLogRepository tradeLog, TradingState state, CopyTradingState copyState) + // Parameterloser Konstruktor für den WinForms-Designer. + public ClosedTradesView() { - _tradeLog = tradeLog; - _state = state; - _copyState = copyState; - InitializeComponent(); colEntry.DefaultCellStyle.Format = "F3"; @@ -36,12 +33,21 @@ namespace PolyTrader.Modules.CopyTrading.Ui colClosedAt.DefaultCellStyle.Format = "dd.MM.yyyy HH:mm"; btnRefresh.Click += (_, _) => LoadData(); + } + /// Injiziert die Abhängigkeiten (nach der DI-Auflösung) und lädt die Daten. + public void Initialize(ICopyTradeLogRepository tradeLog, TradingState state, CopyTradingState copyState) + { + _tradeLog = tradeLog; + _state = state; + _copyState = copyState; LoadData(); } private void LoadData() { + if (_tradeLog == null) return; + var rows = _tradeLog.Find(_ => true) .OrderByDescending(t => t.ClosedAt) .Select(t => new ClosedTradeRow @@ -80,14 +86,14 @@ namespace PolyTrader.Modules.CopyTrading.Ui private string ResolveAccount(int accountId, bool isDemo) { string suffix = isDemo ? " (Demo)" : ""; - if (_state.Accounts.TryGetValue(accountId, out var acc) && !string.IsNullOrEmpty(acc.Name)) + if (_state != null && _state.Accounts.TryGetValue(accountId, out var acc) && !string.IsNullOrEmpty(acc.Name)) return acc.Name + suffix; return $"#{accountId}{suffix}"; } private string ResolveTrader(int traderId) { - if (_copyState.Traders.TryGetValue(traderId, out var t) && !string.IsNullOrEmpty(t.DisplayName)) + if (_copyState != null && _copyState.Traders.TryGetValue(traderId, out var t) && !string.IsNullOrEmpty(t.DisplayName)) return t.DisplayName; return traderId > 0 ? $"#{traderId}" : "Unbekannt"; } diff --git a/src/PolyTrader.Modules.CopyTrading/Ui/MasterTradersView.cs b/src/PolyTrader.Modules.CopyTrading/Ui/MasterTradersView.cs index c995956..09e8350 100644 --- a/src/PolyTrader.Modules.CopyTrading/Ui/MasterTradersView.cs +++ b/src/PolyTrader.Modules.CopyTrading/Ui/MasterTradersView.cs @@ -17,19 +17,16 @@ namespace PolyTrader.Modules.CopyTrading.Ui /// public partial class MasterTradersView : Form { - private readonly ITrackedTraderRepository _repo; - private readonly TradingState _state; - private readonly CopyTradingState _copyState; + private ITrackedTraderRepository? _repo; + private TradingState? _state; + private CopyTradingState? _copyState; private BindingList _binding = new(); private TrackedTrader? _current; - public MasterTradersView(ITrackedTraderRepository repo, TradingState state, CopyTradingState copyState) + // Parameterloser Konstruktor für den WinForms-Designer. + public MasterTradersView() { - _repo = repo; - _state = state; - _copyState = copyState; - InitializeComponent(); colWinrate.DefaultCellStyle.Format = "F1"; @@ -40,12 +37,21 @@ namespace PolyTrader.Modules.CopyTrading.Ui tsDelete.Click += (_, _) => DeleteCurrent(); tsRefresh.Click += (_, _) => LoadData(); grid.SelectionChanged += (_, _) => OnSelectionChanged(); + } + /// Injiziert die Abhängigkeiten (nach der DI-Auflösung) und lädt die Trader. + public void Initialize(ITrackedTraderRepository repo, TradingState state, CopyTradingState copyState) + { + _repo = repo; + _state = state; + _copyState = copyState; LoadData(); } private void LoadData() { + if (_repo == null) return; + var traders = _repo.GetAll().OrderBy(t => t.Id).ToList(); _binding = new BindingList(traders); grid.DataSource = _binding; @@ -68,6 +74,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui pgDetail.SelectedObject = trader; clbAccounts.Items.Clear(); + if (_state == null) return; 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" : "")}"; @@ -94,7 +101,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui private void SaveCurrent() { - if (_current == null) { lblHint.Text = "Kein Trader ausgewählt."; return; } + if (_current == null || _repo == null || _copyState == null) { lblHint.Text = "Kein Trader ausgewählt."; return; } _current.AssignedAccountIds = clbAccounts.CheckedItems.Cast().Select(a => a.Id).ToHashSet(); @@ -106,7 +113,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui private void DeleteCurrent() { - if (_current == null) { lblHint.Text = "Kein Trader ausgewählt."; return; } + if (_current == null || _repo == null || _copyState == 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)