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:
co-authored by
Claude Opus 4.8
parent
4caba5bfd1
commit
76007db93f
@@ -62,10 +62,15 @@ namespace PolyTrader.Modules.CopyTrading
|
|||||||
Title = "Master-Trader",
|
Title = "Master-Trader",
|
||||||
Group = "CopyTrading",
|
Group = "CopyTrading",
|
||||||
Order = 100,
|
Order = 100,
|
||||||
CreateForm = () => new MasterTradersView(
|
CreateForm = () =>
|
||||||
|
{
|
||||||
|
var view = new MasterTradersView();
|
||||||
|
view.Initialize(
|
||||||
services.GetRequiredService<ITrackedTraderRepository>(),
|
services.GetRequiredService<ITrackedTraderRepository>(),
|
||||||
services.GetRequiredService<TradingState>(),
|
services.GetRequiredService<TradingState>(),
|
||||||
services.GetRequiredService<CopyTradingState>())
|
services.GetRequiredService<CopyTradingState>());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
host.RegisterView(new ModuleView
|
host.RegisterView(new ModuleView
|
||||||
@@ -74,10 +79,15 @@ namespace PolyTrader.Modules.CopyTrading
|
|||||||
Title = "Geschlossene Copytrades",
|
Title = "Geschlossene Copytrades",
|
||||||
Group = "CopyTrading",
|
Group = "CopyTrading",
|
||||||
Order = 110,
|
Order = 110,
|
||||||
CreateForm = () => new ClosedTradesView(
|
CreateForm = () =>
|
||||||
|
{
|
||||||
|
var view = new ClosedTradesView();
|
||||||
|
view.Initialize(
|
||||||
services.GetRequiredService<ICopyTradeLogRepository>(),
|
services.GetRequiredService<ICopyTradeLogRepository>(),
|
||||||
services.GetRequiredService<TradingState>(),
|
services.GetRequiredService<TradingState>(),
|
||||||
services.GetRequiredService<CopyTradingState>())
|
services.GetRequiredService<CopyTradingState>());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
host.RegisterView(new ModuleView
|
host.RegisterView(new ModuleView
|
||||||
@@ -86,10 +96,15 @@ namespace PolyTrader.Modules.CopyTrading
|
|||||||
Title = "Copytrading-Account-Einstellungen",
|
Title = "Copytrading-Account-Einstellungen",
|
||||||
Group = "CopyTrading",
|
Group = "CopyTrading",
|
||||||
Order = 120,
|
Order = 120,
|
||||||
CreateForm = () => new AccountSettingsView(
|
CreateForm = () =>
|
||||||
|
{
|
||||||
|
var view = new AccountSettingsView();
|
||||||
|
view.Initialize(
|
||||||
services.GetRequiredService<ICopyTradingAccountSettingsRepository>(),
|
services.GetRequiredService<ICopyTradingAccountSettingsRepository>(),
|
||||||
services.GetRequiredService<TradingState>(),
|
services.GetRequiredService<TradingState>(),
|
||||||
services.GetRequiredService<CopyTradingState>())
|
services.GetRequiredService<CopyTradingState>());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,28 +15,34 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class AccountSettingsView : Form
|
public partial class AccountSettingsView : Form
|
||||||
{
|
{
|
||||||
private readonly ICopyTradingAccountSettingsRepository _repo;
|
private ICopyTradingAccountSettingsRepository? _repo;
|
||||||
private readonly TradingState _state;
|
private TradingState? _state;
|
||||||
private readonly CopyTradingState _copyState;
|
private CopyTradingState? _copyState;
|
||||||
|
|
||||||
private CopyTradingAccountSettings? _current;
|
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();
|
InitializeComponent();
|
||||||
|
|
||||||
cmbAccounts.SelectedIndexChanged += (_, _) => LoadSelected();
|
cmbAccounts.SelectedIndexChanged += (_, _) => LoadSelected();
|
||||||
btnSave.Click += (_, _) => Save();
|
btnSave.Click += (_, _) => Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Injiziert die Abhängigkeiten (nach der DI-Auflösung) und füllt die Auswahl.</summary>
|
||||||
|
public void Initialize(ICopyTradingAccountSettingsRepository repo, TradingState state, CopyTradingState copyState)
|
||||||
|
{
|
||||||
|
_repo = repo;
|
||||||
|
_state = state;
|
||||||
|
_copyState = copyState;
|
||||||
PopulateAccounts();
|
PopulateAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateAccounts()
|
private void PopulateAccounts()
|
||||||
{
|
{
|
||||||
|
if (_state == null) return;
|
||||||
|
|
||||||
var items = _state.Accounts.Values
|
var items = _state.Accounts.Values
|
||||||
.OrderBy(a => a.AccountId)
|
.OrderBy(a => a.AccountId)
|
||||||
.Select(a => new AccountItem(a.AccountId, string.IsNullOrEmpty(a.Name) ? $"#{a.AccountId}" : $"{a.Name} (#{a.AccountId}){(a.IsDemo ? " · Demo" : "")}"))
|
.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()
|
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 };
|
_current = _repo.Get(item.Id) ?? new CopyTradingAccountSettings { AccountId = item.Id };
|
||||||
pgSettings.SelectedObject = _current;
|
pgSettings.SelectedObject = _current;
|
||||||
lblHint.Text = $"Einstellungen für Account #{item.Id}.";
|
lblHint.Text = $"Einstellungen für Account #{item.Id}.";
|
||||||
@@ -60,7 +66,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
|
|
||||||
private void Save()
|
private void Save()
|
||||||
{
|
{
|
||||||
if (_current == null) return;
|
if (_current == null || _repo == null || _copyState == null) return;
|
||||||
_repo.Upsert(_current);
|
_repo.Upsert(_current);
|
||||||
_copyState.AccountSettings[_current.AccountId] = _current;
|
_copyState.AccountSettings[_current.AccountId] = _current;
|
||||||
lblHint.Text = $"Gespeichert für Account #{_current.AccountId} um {DateTime.Now:HH:mm:ss}.";
|
lblHint.Text = $"Gespeichert für Account #{_current.AccountId} um {DateTime.Now:HH:mm:ss}.";
|
||||||
|
|||||||
@@ -15,16 +15,13 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ClosedTradesView : Form
|
public partial class ClosedTradesView : Form
|
||||||
{
|
{
|
||||||
private readonly ICopyTradeLogRepository _tradeLog;
|
private ICopyTradeLogRepository? _tradeLog;
|
||||||
private readonly TradingState _state;
|
private TradingState? _state;
|
||||||
private readonly CopyTradingState _copyState;
|
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();
|
InitializeComponent();
|
||||||
|
|
||||||
colEntry.DefaultCellStyle.Format = "F3";
|
colEntry.DefaultCellStyle.Format = "F3";
|
||||||
@@ -36,12 +33,21 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
colClosedAt.DefaultCellStyle.Format = "dd.MM.yyyy HH:mm";
|
colClosedAt.DefaultCellStyle.Format = "dd.MM.yyyy HH:mm";
|
||||||
|
|
||||||
btnRefresh.Click += (_, _) => LoadData();
|
btnRefresh.Click += (_, _) => LoadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Injiziert die Abhängigkeiten (nach der DI-Auflösung) und lädt die Daten.</summary>
|
||||||
|
public void Initialize(ICopyTradeLogRepository tradeLog, TradingState state, CopyTradingState copyState)
|
||||||
|
{
|
||||||
|
_tradeLog = tradeLog;
|
||||||
|
_state = state;
|
||||||
|
_copyState = copyState;
|
||||||
LoadData();
|
LoadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
|
if (_tradeLog == null) return;
|
||||||
|
|
||||||
var rows = _tradeLog.Find(_ => true)
|
var rows = _tradeLog.Find(_ => true)
|
||||||
.OrderByDescending(t => t.ClosedAt)
|
.OrderByDescending(t => t.ClosedAt)
|
||||||
.Select(t => new ClosedTradeRow
|
.Select(t => new ClosedTradeRow
|
||||||
@@ -80,14 +86,14 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
private string ResolveAccount(int accountId, bool isDemo)
|
private string ResolveAccount(int accountId, bool isDemo)
|
||||||
{
|
{
|
||||||
string suffix = isDemo ? " (Demo)" : "";
|
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 acc.Name + suffix;
|
||||||
return $"#{accountId}{suffix}";
|
return $"#{accountId}{suffix}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ResolveTrader(int traderId)
|
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 t.DisplayName;
|
||||||
return traderId > 0 ? $"#{traderId}" : "Unbekannt";
|
return traderId > 0 ? $"#{traderId}" : "Unbekannt";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,16 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MasterTradersView : Form
|
public partial class MasterTradersView : Form
|
||||||
{
|
{
|
||||||
private readonly ITrackedTraderRepository _repo;
|
private ITrackedTraderRepository? _repo;
|
||||||
private readonly TradingState _state;
|
private TradingState? _state;
|
||||||
private readonly CopyTradingState _copyState;
|
private CopyTradingState? _copyState;
|
||||||
|
|
||||||
private BindingList<TrackedTrader> _binding = new();
|
private BindingList<TrackedTrader> _binding = new();
|
||||||
private TrackedTrader? _current;
|
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();
|
InitializeComponent();
|
||||||
|
|
||||||
colWinrate.DefaultCellStyle.Format = "F1";
|
colWinrate.DefaultCellStyle.Format = "F1";
|
||||||
@@ -40,12 +37,21 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
tsDelete.Click += (_, _) => DeleteCurrent();
|
tsDelete.Click += (_, _) => DeleteCurrent();
|
||||||
tsRefresh.Click += (_, _) => LoadData();
|
tsRefresh.Click += (_, _) => LoadData();
|
||||||
grid.SelectionChanged += (_, _) => OnSelectionChanged();
|
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();
|
LoadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
|
if (_repo == null) return;
|
||||||
|
|
||||||
var traders = _repo.GetAll().OrderBy(t => t.Id).ToList();
|
var traders = _repo.GetAll().OrderBy(t => t.Id).ToList();
|
||||||
_binding = new BindingList<TrackedTrader>(traders);
|
_binding = new BindingList<TrackedTrader>(traders);
|
||||||
grid.DataSource = _binding;
|
grid.DataSource = _binding;
|
||||||
@@ -68,6 +74,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
pgDetail.SelectedObject = trader;
|
pgDetail.SelectedObject = trader;
|
||||||
|
|
||||||
clbAccounts.Items.Clear();
|
clbAccounts.Items.Clear();
|
||||||
|
if (_state == null) return;
|
||||||
foreach (var acc in _state.Accounts.Values.OrderBy(a => a.AccountId))
|
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" : "")}";
|
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()
|
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();
|
_current.AssignedAccountIds = clbAccounts.CheckedItems.Cast<AccountItem>().Select(a => a.Id).ToHashSet();
|
||||||
|
|
||||||
@@ -106,7 +113,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
|||||||
|
|
||||||
private void DeleteCurrent()
|
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;
|
var id = _current.Id;
|
||||||
if (MessageBox.Show($"Master-Trader #{id} ({_current.DisplayName}) wirklich löschen?",
|
if (MessageBox.Show($"Master-Trader #{id} ({_current.DisplayName}) wirklich löschen?",
|
||||||
"Löschen bestätigen", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
|
"Löschen bestätigen", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
|
||||||
|
|||||||
Reference in New Issue
Block a user