Auch ich habe wie einige andere (hier bzw. hier) eine eigene Splash-Screen Komponente. Da ich natürlich (wie vermutlich die beiden Anderen auch) finde, meine eigene ist die komfortabelste :evil:, will ich sie euch nicht vorenthalten.
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
Hier nun der Source-Code mit einer kurzen Dokumentation:
Statische Methode zum Aufrufen des SplashScreens:
// Erzeugt eine neue Instanz von SplashScreen, zeigt die SplashScreen-Form an und ruft action in einem Worker-Thread mit der Instanz von SplashScreen als Parameter auf.
public static void ShowSplash(Action<SplashScreen> action);
// Erzeugt eine neue Instanz von SplashScreen, zeigt customSplash an und ruft action in einem Worker-Thread mit der Instanz von SplashScreen als Parameter auf.
public static void ShowSplash(ISplashScreenForm customSplash, Action<SplashScreen> action);
Aufrufbare Properties / Methoden innerhalb von action:
// Setzt den Statustext der aktuellen Operation
public String Status;
// Setzt den Titel der aktuellen Operation
public String Title;
// Setzt den Fortschritt der aktuellen Operation (Wert zwischen 0 und 100)
public Int32 Progress;
// Versetzt die Fortschrittsanzeige in den Marquee-Modus
public Boolean Marquee;
// Setzt den SplashScreen dauerhaft in den Vordergrund
public Boolean TopMost;
// Die Beschreibung unter dem Titel
public String Description;
// Der Name des Produkts
public String Product;
// Die Beschreibung des Produkts
public String ProductDescription;
// Copyright oder Version des Produkts
public String ProductCopyright;
// Bild oben links in der Ecke
public Image Image;
// Icon der Form
public Icon Icon;
// Setzt benutzerdefinierte Eigenschaften
public Object this[String key];
// Fügt einen Task hinzu, gibt die Task-ID zurück
public Int32 AddTask(Image image, String text);
// Ändert einen Task
public void UpdateTask(Int32 index, Image image, String text);
// Löscht einen Task
public void RemoveTask(Int32 index);
// Fügt einen neuen Job zu Queue hinzu.
public Guid EnqueueJob(Action<SplashScreen> action, JobMode jobMode, Guid waitFor);
// Führt alle Jobs aus.
public void RunJobs();
// Führt die Operation auf dem Gui-Thread aus. Ermöglicht es, Gui-Elemente innerhalb des SplashScreens zu erzeugen.
public Object InvokeOnGUIThread(Delegate method, params Object[] args)
Der SplashScreen schließt sich automatisch, sobald action durchgelaufen ist.
Weiterhin kann über ein Interface (ISplashScreenForm) eine eigene Form als SplashScreen verwendet werden:
using (var mySplash = new MyForm())
{
SplashScreen.ShowSplash(mySplash, (spl) =>
{
// Do some work here ...
});
}
Um das Disposing der eigenen Form muss sich selbst gekümmert werden, das Invoking auf dem UIThread wird vom SplashScreen übernommen.
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
Habe das Flackern beseitigt. Es lag wie ich vermutet habe an den TableLayoutPanels, die habe ich jetzt einfach weggelassen.
Gruß, Christian.
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
So. Heute habe ich noch Unterstützung für ein Job-System eingebaut.
Dokumentation und aktuelle Sources sowohl in den ersten zwei Posts als auch auf meiner Website.
Viel Spaß damit!
Gruß, Christian.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
Also Christian, ich bin wirklich begeistert von deiner Implementierung. Das scheint mir bis jetzt die flexibelste SplashScreen Komponente zu sein, die ich bislang gefunden hab...
Allerdings bin ich grossteils noch in .NET 2.0 unterwegs, und kenne mich deswegen überhaupt nicht mit diesen Lambda Expressions aus. Und nach 45 Minuten Sucherei im Web hab ich's jetzt aufgegeben. Ich krieg dein Beispiel einfach nicht umgebogen, damit es mit anonymen Methoden hinhaut.
Kanns einer mir bischen unter die Arme greifen, denn ich blick diese Lambda Expressions wirklich nicht.
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
die Komponenten geht doch aber unter .net 2.0 gar nicht.
Btw, kannst du die eigentliche Komponente in ein DLL Projekt packen (damit man das nicht immer wieder selber machen muss), gescheit versionieren und ein Changelog bei jeder neuen Version schreiben?
Danke Christian. Irgendwann kapier ich diese Lamda Expressions auch :-)
Zitat von MagicAndre1981
die Komponenten geht doch aber unter .net 2.0 gar nicht.
Warum sollte sie nicht gehen, wenn man die ganzen Lambda Ausdrücke durch anonyme Methoden ersetzt. Oder werden noch Klassen benutzt, die in 2.0 nicht enthalten sind?
Ich benutze einige Delegates (Action<W, U, R, S, T> etc.), aber die kann man leicht ersetzen.
Wenn du VS2008 hast, dann ist das var-Schlüsselwort kein Problem (mit VS2005 schon, leider).
@MagicAndre1981: Werd ich machen, sobald ich wieder zuhause bin.
Gruß, Christian.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
Ich habe den SplashScreen jetzt in eine eigene Bibliothek ausgelagert und das Zielframework auf .Net 2.0 umgestellt. Weiterhin habe ich ein Changelog eingeführt und ein paar kosmetische Veränderungen vorgenommen. Dokumentiert habe ich das projekt auch.
Gruß, Christian.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
ich hab ein kleines Problem mit Deiner Komponente. Ich möchte als einen Job unteranderem das Laden der MainForm durchführen lassen. Das Laden an sich funktioniert auch, jedoch funktionieren Timer nicht mehr, die ich z.B. verwende um die aktuelle Uhrzeit anzuzeigen. Die Eigenschaft Timer.Enabled ist zwar true, aber das Tick-Event wird nicht mehr ausgelöst. Woran könnte das liegen?
Geladen wir die Form mit der SplashScreenLibrary so:
Form1 mainForm = null;
using (JippoSplash splash = new JippoSplash())
{
SplashScreen.ShowSplash(splash, delegate(SplashScreen spl)
{
//Properties von spl setzen
spl.EnqueueJob(delegate(SplashScreen s)
{
int n = s.AddTask(Resources.bullet_go, "Hauptanwendung wird initialisiert.");
mainForm = new Form1();
s.UpdateTask(n, Resources.bullet_green, "Hauptanwendung wurde geladen.");
s.Progress += 50;
}, JobMode.Synchronous, Guid.Empty);
spl.RunJobs();
spl.Progress = 100;
spl.Status = "Fertig...";
Thread.Sleep(1000);
});
}
Application.Run(mainForm);
Das Problem ist, dass alles, was in SplashScreen.ShowSplash(splash, delegate(SplashScreen spl) { ... }); steht, in einem Hintergrund-Thread läuft. Wenn man nun GUI-Komponenten nicht im GUI-Thread (also dem Haupt-Thread) erzeugt, kann es zu solchen Probelmen kommen. Ich weis nicht, warum deine MainForm so lange braucht, um zu laden, aber wenn es irgendwelche von der GUI unabhängige Operationen sind, dann lagere diese in den SplashScreen aus. Danach erzeugst du die GUI (also deine MainForm) im GUI-Thread und übergibst ihr die im SplashScreen geladenen Daten. So war das eigentlich meinerseits gedacht.
Ein kleines Beispiel:
// Hier sind wir (normalerweise) im GUI-Thread
var list = new List<String>();
SplashScreen.ShowSplash((spl) =>
{
// Hier sind wir in einem Background-Worker (nennen wir ihn mal BG1)
spl.EnqueueJob((s) =>
{
// Wenn JobMode.Synchronous, dann sind wir hier in BG1 (s.o.)
// Wenn JobMode.Asynchronous, dann sind wir hier in einem weiteren Background-Worker
int n = s.AddTask(Resources.bullet_go, "Daten laden");
// Hier werden nur die Daten geladen. Dauert ziemlich lange ;-)
list.AddRange(HoleDatenAusDateiOderInternetOderSonstWoHer());
s.UpdateTask(n, Resources.bullet_green, "Daten geladen.");
s.Progress += 50;
}, JobMode.Synchronous, Guid.Empty);
// Hier sind wir in BG1
spl.RunJobs();
spl.Progress = 100;
spl.Status = "Fertig...";
Thread.Sleep(1000);
});
// Hier sind wir wieder im GUI-Thread
// Hier wird die MainForm erstellt und die Daten werden an die MainForm übergeben.
Application.Run(new MainForm(list));
Zusammenfassend: Alles, was GUI ist gehört in den GUI-Thread. Alles, was auf den SplashScreen selbst zugreift, wird automatisch von meiner Komponente auf dem GUI-Thread verlagert.
Hoffe, ich konnte dir helfen.
Gruß, Christian.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
Ich habe für das Problem (siehe vorherigen Post) jetzt eine Methode Object InvokeOnGuiThread(Delegate, Object[]) hinzugefügt. Diese führt den übergebenen Delegaten auf dem GUI-Thread aus.
Damit kann man auch GUI-Elemente im SplashScreen erzeugen. Nachteil: Der SplashScreen ist blockiert und reagiert nicht, solange die Operation auf dem GUI-Thread läuft.
Beispiel:
MainForm mainForm = null;
SplashScreen.ShowSplash((spl) =>
{
spl.EnqueueJob(delegate(SplashScreen s)
{
int n = s.AddTask(Resources.bullet_go, "Anwendung wird initialisiert.");
s.InvokeOnGUIThread(new MethodInvoker(() =>
{
// Hier sind wir jetzt im GUI-Thread.
// Hier kann man also Gui-Elemente gefahrlos erzeugen.
// Nachteil: Der SplashScreen ist blockiert und reagiert nicht mehr.
mainForm = new MainForm();
}));
s.UpdateTask(n, Resources.bullet_green, "Anwendung wurde geladen.");
s.Progress += 50;
}, JobMode.Synchronous, Guid.Empty);
spl.RunJobs();
spl.Progress = 100;
spl.Status = "Fertig...";
Thread.Sleep(1000);
});
Application.Run(mainForm);
Dieser Beitrag wurde 4 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
Hi, mir wurde gesagt, dass unter XP deine Komponente ein kleines Problem hat. Die Bereiche in denen die benutzerdefinierten Texte angezeigt werden sind nach dem Anzeigen des Splash-Screens kurz schwarz. Da ich nur Vista nutze, kann ich das nicht überprüfen. Kannst du mal nachsehen?
Auch das konnte ich reproduzieren (leider :evil: ).
Ich werde mich sobald es geht darum kümmern, allerdings geht es im Moment nicht so schnell. Habe an der Arbeit viel zu tun...
Gruß, Christian.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
Ich bin dem Flackern auf den Grund gegangen. Es liegt an der Kombination BackgroundImage + Controls darüber. Ich habe dann versucht, die SplashScreenForm komplett selbst zu zeichnen, aber das Flackern war trotz ControlStyles.OptimizedDoubleBuffer nicht ganz weg und die Transparenz funktionierte unter XP trotz ControlStyles.SupportsTransparentBackColor nicht mehr.
Deswegen und weil ich zur Zeit keine Zeit für das SplashScreen-Projekt habe und da man ja (falls das Flackern wirklich so extrem ist und stört) eine eigene Form als SplashScreen benutzen kann, habe ich mich dazu entschlossen, das Problem vorerst nicht zu beseitigen.
Gruß, Christian.
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"