Modul-Views: parameterloser Ctor + Initialize() (Designer-öffenbar)

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 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-06 10:15:04 +02:00
co-authored by Claude Opus 4.8
parent 4caba5bfd1
commit 76007db93f
4 changed files with 76 additions and 42 deletions
@@ -17,19 +17,16 @@ namespace PolyTrader.Modules.CopyTrading.Ui
/// </summary>
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<TrackedTrader> _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();
}
/// <summary>Injiziert die Abhängigkeiten (nach der DI-Auflösung) und lädt die Trader.</summary>
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<TrackedTrader>(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<AccountItem>().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)