UI Slice 5: Menueleiste (Fenster nebeneinander), sicheres Beenden, Modul-Aktivierung
- Fenster-Menue: WindowMenu fuellt die oberste MenuStrip mit Top-Level-Eintraegen nebeneinander (mit Icon) statt Untermenue "Fenster"; ModuleView.Icon zentral in der App zugewiesen (AssignMenuIcons). Kein miFenster mehr im Launcher-Designer. - Sicheres Beenden: ShutdownConfirmDialog (10s-Timer sperrt "Jetzt beenden", Abbrechen jederzeit) via IModuleUiHost.RequestShutdown(). Nur der Launcher (Hauptprozess) bietet "Beenden"; andere Fenster nur "Fenster schliessen" (kein App-Shutdown, Module laufen weiter). Launcher-Schliessen-X routet ueber dieselbe Abfrage. - Modul-Aktivierung (restart-basiert): ServerSettings.DisabledModules, in Program.Main vor der DI-Registrierung gefiltert -> deaktivierte Module werden nicht geladen. Dashboard-Tab "Module" zeigt Status + schaltet um (Hinweis: greift nach Neustart). Optionaler IPolyTraderModule.GetActivationBlocker fuer "nicht aktivierbar"-Info. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
886de3a85b
commit
039bc240f8
+56
-7
@@ -27,6 +27,9 @@ internal static class Program
|
||||
{
|
||||
public static IHost? AppHost { get; private set; }
|
||||
|
||||
/// <summary>Pfad der (gitignorierten) Server-Settings-Datei – Quelle u.a. für die Modul-Aktivierung.</summary>
|
||||
private const string ServerSettingsPath = "server_settings.xml";
|
||||
|
||||
[STAThread]
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
@@ -62,13 +65,21 @@ internal static class Program
|
||||
|
||||
ApplicationConfiguration.Initialize();
|
||||
|
||||
var modules = new System.Collections.Generic.List<IPolyTraderModule>
|
||||
// Server-Settings früh laden (VOR der DI-Registrierung), damit deaktivierte Module gar nicht
|
||||
// erst geladen werden. Dieselbe Instanz wird als Singleton weitergereicht (eine Quelle).
|
||||
var serverSettings = PolyTraderSharp.Models.ServerSettings.Load(ServerSettingsPath);
|
||||
|
||||
// Alle bekannten Module; „modules" enthält nur die aktiven (nicht in DisabledModules).
|
||||
var allModules = new System.Collections.Generic.List<IPolyTraderModule>
|
||||
{
|
||||
new CopyTradingModule(),
|
||||
new ResolutionFarmingModule(),
|
||||
new SupervisorModule(),
|
||||
new AccountingModule()
|
||||
};
|
||||
var disabledModules = new System.Collections.Generic.HashSet<string>(
|
||||
serverSettings.DisabledModules, StringComparer.OrdinalIgnoreCase);
|
||||
var modules = allModules.Where(m => !disabledModules.Contains(m.Name)).ToList();
|
||||
|
||||
AppHost = Host.CreateDefaultBuilder()
|
||||
// Config immer neben der EXE suchen (nicht im Arbeitsverzeichnis), damit die App
|
||||
@@ -87,7 +98,7 @@ internal static class Program
|
||||
};
|
||||
services.Configure<DatabaseOptions>(context.Configuration.GetSection(DatabaseOptions.SectionName));
|
||||
services.AddCorePersistence(databaseOptions);
|
||||
services.AddSingleton((IServiceProvider sp) => ServerSettings.Load("server_settings.xml"));
|
||||
services.AddSingleton(serverSettings);
|
||||
services.AddSingleton<TradingState>();
|
||||
services.AddSingleton(delegate(IServiceProvider sp)
|
||||
{
|
||||
@@ -148,10 +159,14 @@ internal static class Program
|
||||
try
|
||||
{
|
||||
// Trade-Nummerierung fortsetzen: höchste bestehende TradeId serverseitig lesen
|
||||
// (M3: kein Full-Table-Load mehr über Find(_=>true).Max()).
|
||||
var copyState = AppHost.Services.GetRequiredService<CopyTradingState>();
|
||||
var tradeLog = AppHost.Services.GetRequiredService<ICopyTradeLogRepository>();
|
||||
copyState.TotalCopyTrades = tradeLog.GetMaxTradeId();
|
||||
// (M3: kein Full-Table-Load mehr über Find(_=>true).Max()). Nur wenn CopyTrading aktiv ist –
|
||||
// sonst sind dessen Services (CopyTradingState/…) gar nicht registriert.
|
||||
if (modules.Any(m => m is CopyTradingModule))
|
||||
{
|
||||
var copyState = AppHost.Services.GetRequiredService<CopyTradingState>();
|
||||
var tradeLog = AppHost.Services.GetRequiredService<ICopyTradeLogRepository>();
|
||||
copyState.TotalCopyTrades = tradeLog.GetMaxTradeId();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -223,9 +238,17 @@ internal static class Program
|
||||
CreateForm = () =>
|
||||
{
|
||||
var view = new PolyTraderSharp.Ui.Views.DashboardView();
|
||||
var config = viewServices.GetRequiredService<Microsoft.Extensions.Configuration.IConfiguration>();
|
||||
// Alle Module (auch deaktivierte) fürs Dashboard: läuft-Status = ist in dieser Session geladen.
|
||||
var moduleInfos = allModules
|
||||
.Select(m => new PolyTraderSharp.Ui.Views.ModuleActivationInfo(
|
||||
m.Name, modules.Contains(m), m.GetActivationBlocker(config)))
|
||||
.ToList();
|
||||
view.Initialize(
|
||||
viewServices.GetRequiredService<PolyTrader.Core.Persistence.ITradeLogRepository>(),
|
||||
viewServices.GetRequiredService<TradingState>());
|
||||
viewServices.GetRequiredService<TradingState>(),
|
||||
moduleInfos,
|
||||
ServerSettingsPath);
|
||||
return view;
|
||||
}
|
||||
});
|
||||
@@ -235,11 +258,37 @@ internal static class Program
|
||||
module.RegisterUi(uiHost, viewServices);
|
||||
}
|
||||
|
||||
// Menü-Icons zentral zuweisen: Die App kennt alle Fenster-Ressourcen; Core und Module
|
||||
// referenzieren sie nicht. So erscheint jedes Fenster mit Icon in der obersten Menüleiste.
|
||||
AssignMenuIcons(uiHost);
|
||||
|
||||
var launcher = AppHost.Services.GetRequiredService<PolyTraderSharp.Ui.LauncherForm>();
|
||||
Application.Run(launcher);
|
||||
AppHost.StopAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Weist den registrierten Views (Core + Module) ihr Menü-Icon aus den App-Ressourcen zu –
|
||||
/// gemappt über die stabile View-ID. Bereits gesetzte Icons bleiben erhalten.
|
||||
/// </summary>
|
||||
private static void AssignMenuIcons(PolyTraderSharp.Ui.ShellUiHost uiHost)
|
||||
{
|
||||
var map = new System.Collections.Generic.Dictionary<string, System.Drawing.Image>
|
||||
{
|
||||
["core.dashboard"] = Properties.Resources.dashboard,
|
||||
["core.settings"] = Properties.Resources.setting_tools,
|
||||
["core.terminal"] = Properties.Resources.error_log,
|
||||
["core.jobs"] = Properties.Resources.system_time,
|
||||
["accounting.main"] = Properties.Resources.coins_in_hand,
|
||||
["copytrading.main"] = Properties.Resources.cross_reference,
|
||||
["resolutionfarming.main"] = Properties.Resources.file_start_workflow,
|
||||
["supervisor.main"] = Properties.Resources.emotion_batman,
|
||||
};
|
||||
foreach (var view in uiHost.Views)
|
||||
if (view.Icon == null && map.TryGetValue(view.Id, out var img))
|
||||
view.Icon = img;
|
||||
}
|
||||
|
||||
private static void RunConfigMigrationFromJson(string folder)
|
||||
{
|
||||
var config = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
|
||||
|
||||
Reference in New Issue
Block a user