Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
SplashScreen funktioniert nicht (richtig)
Froggie
myCSharp.de - Member



Dabei seit:
Beiträge: 323

Themenstarter:

SplashScreen funktioniert nicht (richtig)

beantworten | zitieren | melden

Ich habe dieses Forum durchsucht (nach SplashScreen, Splash und Screen) und auch einige verlinkte Threads durchgelesen und eigentlich (dachte ich zumindest) auch verstanden (bloss kein Application.DoEvents einsetzen).
Nun habe ich mal ein kleines Testprogramm erstellt und festgestellt, dass ich wohl doch einiges nicht verstanden habe.
Hier mal ein paar Auszüge meiner kreativen Ergüsse:

Program.cs


[STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            using (frmSplash splash = new frmSplash())
            {
                splash.Text = String.Empty;
                splash.ControlBox = false;
                splash.StartPosition = FormStartPosition.CenterScreen;
                splash.ShowInTaskbar = false;
                splash.TopMost = true;

                splash.Show();
                splash.Update();
                //Application.DoEvents();

                //Simulation einer längeren Initialisierung
                for (int i = 0; i < 299; i++)
                {
                    Thread.Sleep(1);
                }

                //Thread.Sleep(5000);
                splash.Close();
            }


            using (Form1 frmHaupt = new Form1())
            {
                frmHaupt.StartPosition = FormStartPosition.CenterScreen;

                Application.Run(frmHaupt);
            }
        }

frmSplash.cs


public partial class frmSplash : Form
    {
        private double myOpacity = 0.1;

        public frmSplash()
        {
            InitializeComponent();
        }

        private void timerFadeIn_Tick(object sender, EventArgs e)
        {
            myOpacity += 0.10;
            if (myOpacity ≥ 1)
            {
                this.Opacity = 1;
                timerFadeIn.Enabled = false;
                return;
            }
            this.Opacity = myOpacity;
            this.Update();
            //Application.DoEvents();
        }

        private void timerFadeOut_Tick(object sender, EventArgs e)
        {
            myOpacity-=0.10;
            if (myOpacity≤0.01)
            {
                timerFadeOut.Enabled = false;
                return;
            }
            this.Opacity = myOpacity;
        }

        private void frmSplash_Load(object sender, EventArgs e)
        {
            if (!SystemInformation.TerminalServerSession)
            {
                timerFadeIn.Interval = 5;
                timerFadeOut.Interval = 5;
                this.Opacity = myOpacity;
                timerFadeIn.Enabled = true;
                timerFadeOut.Enabled = false;
            }
        }

        private void frmSplash_FormClosing(object sender, FormClosingEventArgs e)
        {
            timerFadeOut.Enabled = true;
            timerFadeIn.Enabled = false;
        }
    }

Problem:
Der Splash wird angezeigt, aber nicht weiter aktualisiert. Konkret heißt das: die .Update Methoden zeigen keine Wirkung.
Nach ein wenig debugging ist mir aufgefallen, dass die Timer-Ticks gar nicht ausgeführt werden.

Ich habe das ganze auch noch mal als Anhang gepostet, damit ihr auch versteht was ich eigentlich meine/will. Das lässt sich halt schwer beschreiben.

Frage:
Welchen Hinweis oder Wink (mit dem Zaun) könnt ihr mir geben, so dass sich der SplashScreen richtig aufbaut bzw. was kann ich an meinem Splash besser/eleganter machen?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Froggie am .
Attachments
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Froggie,

die langlaufende Aktion muss in einen extra Thread. Siehe [FAQ] Warum blockiert mein GUI?.

herbivore
private Nachricht | Beiträge des Benutzers
Froggie
myCSharp.de - Member



Dabei seit:
Beiträge: 323

Themenstarter:

beantworten | zitieren | melden

EDIT
Ich habe festgestellt, dass nicht einmal das Shown-Event des Splash ausgelöst wurde.
Weiterhin konnte ich beobachten, dass das Tick-Event des FadeIn-Timers nicht einmal aufgerufen wird.
Weiß jemand wieso?
Im Anhang ist ein aktualisiertes Projekt.

EDIT ENDE

  1. Ich habe mir das zwar durchgelesen gehabt, aber irgendwie habe ich es erst jetzt verstanden.
  2. Ich habe das nun in einen anderen Thread ausgelagert, aber der Splash wird immer noch nicht aktualisiert.
Der SplashScreen ist immer noch wie oben implementiert.

Ich hatte versucht einen Screenshot zu erstellen, aber da der Splash durchsichtig ist, sieht man nix (oder Cropper kommt damit nicht klar).

Program.cs


public class Program
    {
        frmSplash splash;
        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Program program = new Program();
            program.splash = new frmSplash();

            program.splash.Text = String.Empty;
            program.splash.ControlBox = false;
            program.splash.StartPosition = FormStartPosition.CenterScreen;
            program.splash.ShowInTaskbar = false;
            program.splash.TopMost = true;

            program.splash.Show();
            program.splash.Update();

            //HintergrundThread erstellen
            ParameterizedThreadStart threadstart = new ParameterizedThreadStart(program.longRunning);
            Thread worker = new Thread(threadstart);
            worker.IsBackground = true;
            //Wie bekomme ich einen Thread aus dem ThreadPool?
            bool test = worker.IsThreadPoolThread;

            worker.Start(9999);

            //warten bis HintergrundThread erstellt wurde
            while (!worker.IsAlive)
            {
                Thread.Sleep(1);
            }

            //warten bis HintergrundThread fertig ist
            worker.Join();

            //SplashScreen schließen
            program.splash.Close();

            //Hauptformular anzeigen
            using (Form1 frmHaupt = new Form1())
            {
                frmHaupt.StartPosition = FormStartPosition.CenterScreen;

                Application.Run(frmHaupt);
            }
        }

        private void longRunning(object parameter)
        {
            for (int i = 0; i < (int)parameter; i++)
            {
                Debug.WriteLine("Bin zurzeit bei: " + i.ToString());
                Thread.Sleep(1);
            }
        }
    }

Frage(n):
Gibt es noch einen Hinweis warum der Splashscreen nicht richtig angezeigt wird? Nicht richtig angezeigt heißt, dass der FadeIn Effekt nur 1mal aufgrufen wird.

Der von mir erstellte Thread ist ja KEIN Thread aus dem ThreadPool. Ich muss allerdings warten bis der Thread fertig ist. Gibt es diese Möglichkeit auch mit Threads aus dem Pool?
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Froggie am .
Attachments
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Froggie,

warum Thread.Join nicht funktioniert, steht in [FAQ] Warum blockiert mein GUI?

Ich kann nur nochmal sagen, alles was du brauchst, steht in der FAQ. Mach es so und es wir funktionieren.

herbivore
private Nachricht | Beiträge des Benutzers
Atomroflman
myCSharp.de - Member



Dabei seit:
Beiträge: 266
Herkunft: Hamburg

beantworten | zitieren | melden

Du versuchst deinen Splash ein- und aus-faden zu lassen oder?

Ich habe schon einen Splash der ganau das tut... Ich werde den Code heute abend mal linken wenn du so lange warten kannst...

Ich habe das aber auch nur mit nem Timer gelöst, also ohne neuen Thread aufmachen zu müssen...

Bis dahin...
Von all den Sachen, die mir verloren gegangen, hab ich am meisten an meinem Verstand gehangen... MfG...
private Nachricht | Beiträge des Benutzers
Froggie
myCSharp.de - Member



Dabei seit:
Beiträge: 323

Themenstarter:

beantworten | zitieren | melden

Erstmal vielen Dank für die Hilfe!

Ich bin gerade am Umbauen meines Testprojektes. Bis jetzt habe ich den Splashscreen immer normal über die .Show-Methode angezeigt. Werde das jetzt testen, wie das aussieht, wenn ich den SplashScreen mit Application.Run(Splash) aufrufe.
Das soll deutlich einfacher gehen.
ABER:
Meines Wissens nach wird so ein weiterer GUI-Thread erstellt. Und genau das wollte ich ja verhindern. Aber wenn es nicht anders bzw. das andere zu kompliziert ist, dann mache ich das halt mit 2 GUI-Threads.
Hat jemand berechtigte Einwände dagegen?
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Froggie,

es ist nicht nötig und nicht sinnvoll zwei GUI-Thread zu verwenden.

Application.Run ist natürlich erforderlich, aber es gibt keinen Grund das Application.Run nicht im Haupt-Thread zu machen. Es muss ja nur die langlaufenden Aktion und nicht die Erzeugung und Anzeige des Splash-Screens im Worker-Thread erfolgen. Du solltest dazuwischen klar trennen.

Obwohl alles was ich jetzt schreibe, aus der FAQ hervorgeht, hier mal alles auf einen Blick: im Haupt-Thread das Splash-Fenster erzeugen, den Worker-Thread starten und Application.Run für das Splash aufrufen. An Ende des Worker-Threads, wie in der FAQ gezeigt, das Splash-Fenster schließen. Anschließend im Haupt-Thread ein zweites Application.Run für das eigentliche (Haupt-)Form. Fertig!

herbivore
private Nachricht | Beiträge des Benutzers
Atomroflman
myCSharp.de - Member



Dabei seit:
Beiträge: 266
Herkunft: Hamburg

beantworten | zitieren | melden

BTW: was soll das denn??



                //Simulation einer längeren Initialisierung
                for (int i = 0; i < 299; i++)
                {
                    Thread.Sleep(1);
                }

Das wäre doch der Teil den du in dan anderen Thread auslagern könntest...
Von all den Sachen, die mir verloren gegangen, hab ich am meisten an meinem Verstand gehangen... MfG...
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 9.972

beantworten | zitieren | melden

Warum schaut eigentlich niemand mal, was das Framework diesbezüglich anbietet?

Seit FW2 bietet WindowsFormsApplicationBase schon solche sachen an.
SplashScreenunterstützung, Abfangen von Mehrfachstart, Start und Stop Behandlung usw.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo FZelle,
Zitat
Warum schaut eigentlich niemand mal, was das Framework diesbezüglich anbietet?
der vollqualifiziere Klassenname lautet: Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.

Die Gründe könnten also sein:
  • Microsoft statt System: sprich weniger portabel.
  • VisualBasic statt CSharp: Sicher kann man in .NET sprachübergreifend programmieren, aber wenn die Klassen tatsächlich von allgemeiner Bedeutung sind, dann sollte man das nicht durch ein VisualBasic im Namespace verschleiern.
  • Die Untersützung ist nicht oder wenig nützlich oder aber umständlich: Kann ich nicht beurteilen.
  • Die Unterstützung ist unbekannt: so war das bei mir. Vermutlich ist sie bei C#-Programmierer generell deutlich weniger bekannt als bei VB-Programmieren.

herbivore
private Nachricht | Beiträge des Benutzers
Khalid
myCSharp.de - Experte

Avatar #avatar-2534.gif


Dabei seit:
Beiträge: 3.511
Herkunft: Hannover

beantworten | zitieren | melden


@FZelle:
Hi,

laut Doku befindet sich diese Klasse in der Assembly Microsoft.VisualBasic. Da ist sie aber nicht drin?! Wollte mir das Ding mal mittels Reflector anschauen. Ich referenziere auf "Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac". Liegt die doch woanders?
"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)
private Nachricht | Beiträge des Benutzers
Froggie
myCSharp.de - Member



Dabei seit:
Beiträge: 323

Themenstarter:

beantworten | zitieren | melden

Zitat von herbivore
... Application.Run für das Splash aufrufen. ... Anschließend im Haupt-Thread ein zweites Application.Run für das eigentliche (Haupt-)Form...

Ich denke jedes Application.Run erzeugt einen neuen GUI-Thread. Dann würde ich hier ja wieder 2 GUI-Threads haben.
Habe ich das falsch verstanden mit dem Application.Run?

Nach meinem Wissensstand wären das dann insgesamt 3 Threads:
- ein Thread wird sowieso vom Framework für jede Applikation berietgestellt
- ein GUI-Thread durch Application.Run für den Splash
- ein GUI-Thread durch Application.Run für das Hauptform
private Nachricht | Beiträge des Benutzers
Atomroflman
myCSharp.de - Member



Dabei seit:
Beiträge: 266
Herkunft: Hamburg

beantworten | zitieren | melden

Du brauchst keinen neuen Thread aufzumachen...
Ausser du willst im Hintergrund noch irgendwelche Sachen laden...

Nimm dir nen Timer mit nem Intervall von 50ms und tue rein:


private bool FadedIn = false;

// timerevent
if (this.Opacity < 1 && !FadedIn)
{
this.Opacty += 0.1;
}
else if (this.Opacity ≥ 1&& !FadedIn)
{
FadedIn = true;
// etl. wenn du auf ein ereignis warten willst bevor du raus fadest
Timer.enabled = true;
}
else if (this.Opacity > 0 && FadedIn)
{
this.Opacity -=0.1;
}
Von all den Sachen, die mir verloren gegangen, hab ich am meisten an meinem Verstand gehangen... MfG...
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.320

beantworten | zitieren | melden

Hallo Khalid,

die gesuchte Klasse findest sich unter 'Microsoft.VisualBasic.ApplicationServices' in der von dir genannten 'Microsoft.VisualBasic.dll'.

Ups: das hatte herbivore ja schon geschrieben...
Ich habe sie jedenfalls mit dem Reflektor anschauen können.

Und ich sehe es auch so wie herbivore, daß mir die VisualBasic-Klassen in C# eher befremdlich vorkommen -)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am .
private Nachricht | Beiträge des Benutzers
Khalid
myCSharp.de - Experte

Avatar #avatar-2534.gif


Dabei seit:
Beiträge: 3.511
Herkunft: Hannover

beantworten | zitieren | melden


Komisch. Nehme ich die MS.VB Assembly aus dem GAC, ist da fast nichts drin. Nehme ich die direkt aus dem Frameworkordner aus dem Windowsordner, ist alles drin. Naja, jetzt hab ichs jedenfalls.

Danke.
"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Froggie,
Zitat
Ich denke jedes Application.Run erzeugt einen neuen GUI-Thread.
nein, beide Application.Run würden ja - nacheinander - im selben Thread ausgeführt. Meinem Vorschlag folgend im Haupt-Thread. Application.Run erzeugt selbst keinen (weiteren/neuen) Thread, sondern führt alle Aktionen in dem Thread aus, in dem es aufgerufen wurde.
Zitat
Habe ich das falsch verstanden mit dem Application.Run?
Anscheinend.


Hallo Atomroflman,
Zitat
Du brauchst keinen neuen Thread aufzumachen...
Ausser du willst im Hintergrund noch irgendwelche Sachen laden...
für das reine Ein-/Ausblenden hättest du recht, aber es geht hier doch um langwierige Initialisierungen, die dann natürlich in einen extra Thread ausgelagert werden müssen.

herbivore
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 9.972

beantworten | zitieren | melden

@herbivore :
Die geschichte hinter WindowsFormsApplicationBase ist, das es schon in der IDE
bei VB.NET Projekten direkt erreichbar ist, und dann von VS direkt als die startklasse
erstellt wird.

Das hat überhaupt nichts mit VB Compatibility oder ähnlichem zu tun.
Genausowenig wie die BigInter klassen im J#.
private Nachricht | Beiträge des Benutzers
Atomroflman
myCSharp.de - Member



Dabei seit:
Beiträge: 266
Herkunft: Hamburg

beantworten | zitieren | melden

Zitat
Du brauchst keinen neuen Thread aufzumachen...
Ausser du willst im Hintergrund noch irgendwelche Sachen laden...

Deswegen schrieb ich das...
Von all den Sachen, die mir verloren gegangen, hab ich am meisten an meinem Verstand gehangen... MfG...
private Nachricht | Beiträge des Benutzers