Pregunta

Quiero una pantalla de presentación para mostrar la aplicación mientras se está cargando.Tengo un formulario con un sistema de control de bandeja atado a ella.Quiero que la pantalla de presentación para mostrar mientras este formulario se carga, que lleva un poco de tiempo, ya que es el acceso a una API de servicios web para rellenar algunos desplegables.También quiero hacer algunas pruebas básicas para las dependencias antes de la carga (es decir, el servicio web está disponible, el archivo de configuración es legible).Como cada fase de la puesta en marcha va, quiero actualizar a la pantalla de presentación con el progreso.

He estado leyendo mucho en el hilo, pero me pierdo en donde este debe ser controlado desde el main() método?).Yo también soy no se cómo Application.Run() funciona, es aquí donde los hilos de esta debe ser creado a partir de?Ahora, si el formulario con la bandeja del sistema de control es la "vida" de forma, si el splash vienen de allí?No se no se carga hasta que el formulario es completado todos modos?

Yo no estoy buscando un código de hoja, más de un algoritmo de enfoque, así que puedo resolver esto de una vez por todas :)

¿Fue útil?

Solución

Así, para una aplicación ClickOnce que he desplegado en el pasado, se utilizó la Microsoft.VisualBasic espacio de nombres para manejar la pantalla de presentación de roscado.Puede hacer referencia y el uso de la Microsoft.VisualBasic asamblea de C# en .NET 2.0 y ofrece un buen montón de servicios.

  1. Tienen la principal forma de heredar de Microsoft.VisualBasic.WindowsFormsApplicationBase
  2. Reemplazar el "OnCreateSplashScreen" método así:

    protected override void OnCreateSplashScreen()
    {
        this.SplashScreen = new SplashForm();
        this.SplashScreen.TopMost = true;
    }
    

Muy sencillo, muestra su SplashForm (la que usted necesita para crear), mientras que la carga que está pasando, luego se cierra automáticamente una vez que el formulario principal se ha completado la carga.

Esto realmente hace las cosas simples, y la VisualBasic.WindowsFormsApplicationBase es, por supuesto, bien probado por Microsoft y tiene un montón de funcionalidades que pueden hacer su vida mucho más fácil en Winforms, incluso en una aplicación que es 100% de C#.

Al final del día, todo IL y bytecode de todos modos, así que ¿por qué no usarlo?

Otros consejos

El truco es crear un subproceso independiente responsable de pantalla de presentación de la muestra.
Cuando se ejecuta la aplicación .net crea el hilo principal y cargas especificadas (principal) del formulario.Para ocultar el trabajo duro puede ocultar formulario principal hasta que la carga se hace.

Suponiendo que Form1 - es su forma principal y SplashForm es de nivel superior, borderles agradable formulario de presentación:

private void Form1_Load(object sender, EventArgs e)
{
    Hide();
    bool done = false;
    ThreadPool.QueueUserWorkItem((x) =>
    {
        using (var splashForm = new SplashForm())
        {
            splashForm.Show();
            while (!done)
                Application.DoEvents();
            splashForm.Close();
        }
    });

    Thread.Sleep(3000); // Emulate hardwork
    done = true;
    Show();
}

Después de buscar por todo Google y por LO tanto para soluciones, este es mi favorito:http://bytes.com/topic/c-sharp/answers/277446-winform-startup-splash-screen

FormSplash.cs:

public partial class FormSplash : Form
{
    private static Thread _splashThread;
    private static FormSplash _splashForm;

    public FormSplash() {
        InitializeComponent();
    }

    /// <summary>
    /// Show the Splash Screen (Loading...)
    /// </summary>
    public static void ShowSplash()
    {
        if (_splashThread == null)
        {
            // show the form in a new thread
            _splashThread = new Thread(new ThreadStart(DoShowSplash));
            _splashThread.IsBackground = true;
            _splashThread.Start();
        }
    }

    // called by the thread
    private static void DoShowSplash()
    {
        if (_splashForm == null)
            _splashForm = new FormSplash();

        // create a new message pump on this thread (started from ShowSplash)
        Application.Run(_splashForm);
    }

    /// <summary>
    /// Close the splash (Loading...) screen
    /// </summary>
    public static void CloseSplash()
    {
        // need to call on the thread that launched this splash
        if (_splashForm.InvokeRequired)
            _splashForm.Invoke(new MethodInvoker(CloseSplash));

        else
            Application.ExitThread();
    }
}

Programa.cs:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        // splash screen, which is terminated in FormMain
        FormSplash.ShowSplash();

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        // this is probably where your heavy lifting is:
        Application.Run(new FormMain());
    }
}

FormMain.cs

    ...

    public FormMain()
    {
        InitializeComponent();            

        // bunch of database access, form loading, etc
        // this is where you could do the heavy lifting of "loading" the app
        PullDataFromDatabase();
        DoLoadingWork();            

        // ready to go, now close the splash
        FormSplash.CloseSplash();
    }

He tenido problemas con el Microsoft.VisualBasic solución -- Trabajado encontrar en XP, pero en Terminal server de Windows 2003 Server, el formulario principal se muestran (después de la pantalla) en el fondo, y la barra de tareas parpadeará.Y la llegada de la ventana de primer plano y centrarse en el código es un conjunto de otros, la lata de gusanos que usted puede buscar en Google/ASÍ que para.

Esta es una vieja cuestión, pero yo seguía viniendo a través de ella cuando se trata de encontrar un hilo de pantalla de presentación de la solución para WPF, que podría incluir la animación.

Aquí es lo que en última instancia armado:

App.XAML:

<Application Startup="ApplicationStart" …

App.XAML.cs:

void ApplicationStart(object sender, StartupEventArgs e)
{
        var thread = new Thread(() =>
        {
            Dispatcher.CurrentDispatcher.BeginInvoke ((Action)(() => new MySplashForm().Show()));
            Dispatcher.Run();
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.IsBackground = true;
        thread.Start();

        // call synchronous configuration process
        // and declare/get reference to "main form"

        thread.Abort();

        mainForm.Show();
        mainForm.Activate();
  }

Recomiendo llamar Activate(); directamente después de la última Show(); en la respuesta proporcionada por aku.

Citando a MSDN:

La activación de un formulario trae a la si este es el activo aplicación, o que parpadea en la ventana título si este no es el activo aplicación.El formulario debe ser visible para que este método tiene ningún efecto.

Si no activa el formulario principal, puede ser mostrada detrás de otras ventanas abiertas, lo que le hace parecer un poco tonto.

Creo que el uso de algún método como aku o Chico es el camino a seguir, pero un par de cosas a tomar distancia de los ejemplos concretos:

  1. La premisa básica sería mostrar la presentación en un subproceso independiente tan pronto como sea posible.Esa es la manera en que yo lo lean, similar a lo que aku ilustrado, ya que es la forma en que estoy más familiarizado.Yo no era consciente de la VB en función del Tipo mencionado.Y, a pesar de que es un VB la biblioteca, que está a la derecha, es toda IL en la final.Por lo tanto, incluso si se siente sucio no es del todo malo!:) Creo que usted querrá estar seguro de que VB proporciona un subproceso independiente en el que anulan o crear uno usted mismo -- definitivamente de investigación que.

  2. Suponiendo que crear otro hilo para mostrar este splash, usted querrá tener cuidado de cruz subproceso de interfaz de usuario actualizaciones.Menciono esto porque usted ha mencionado la actualización de los avances.Básicamente, para estar seguro, usted necesita llamar a una función de actualización (que se crea) en el formulario de presentación uso de un delegado.Pasa que el delegado de la Invocar la función en la pantalla de presentación del objeto de formulario.De hecho, si usted llama a la presentación del formulario directamente en el progreso de la actualización/elementos de interfaz de usuario en la misma, se obtendrá una excepción siempre que se ejecutan en el .Net 2.0 CLR.Como regla general, cualquier elemento de interfaz de usuario en un formulario debe ser actualizado por el hilo que se ha creado-que es lo que Forma.Invocar asegura.

Por último, me gustaría probable la opción de crear el splash (si no se utiliza la VB sobrecarga) en el método main de tu código.Para mí esto es mejor que tener la principal forma de realizar la creación del objeto a ser tan estrechamente unida a ella.Si usted toma este enfoque, me gustaría sugerir la creación de una sencilla interfaz de la pantalla de presentación implementa -- algo así como IStartupProgressListener -- que recibe de inicio de las actualizaciones de progreso a través de una función miembro.Esto le permitirá cambiar fácilmente en/fuera de clase según sea necesario, y muy bien desacopla el código.El formulario de presentación también se puede saber cuando se cierre en sí mismo si usted notifique cuando el inicio es completa.

Una forma sencilla es el uso de algo así como main():

<STAThread()> Public Shared Sub Main()

    splash = New frmSplash
    splash.Show()

    ' Your startup code goes here...

    UpdateSplashAndLogMessage("Startup part 1 done...")

    ' ... and more as needed...

    splash.Hide()
    Application.Run(myMainForm)
End Sub

Cuando el .NET CLR se inicia su aplicación, se crea un 'principal' hilo y comienza a ejecutar su main() en ese hilo.La Aplicación.Ejecutar(myMainForm) en la final de hace dos cosas:

  1. Inicia el Windows 'mensaje de la bomba", que utiliza el hilo de ejecución principal() como la interfaz gráfica de usuario hilo.
  2. Designa su principal forma' como el 'apagado de la forma" para la aplicación.Si el usuario cierra esa forma, luego de la Aplicación.Ejecutar() termina y el control vuelve a su main(), donde se puede hacer cualquier cierre desea.

No hay necesidad de generar un hilo para cuidar de la ventana de inicio, y de hecho esto es una mala idea, porque entonces tendría que usar hilo-técnicas de seguridad para actualizar el splash contenido de main().

Si usted necesita otros hilos para hacer operaciones en segundo plano en su aplicación, usted puede generar desde main().Sólo recuerde para establecer el Hilo.IsBackground a Verdadero, por lo que se va a morir cuando el principal / GUI subproceso termina.De lo contrario, usted tendrá que hacer arreglos para terminar el resto de hilos del mismo, o se va a mantener la aplicación viva (pero sin GUI) cuando el hilo principal termina.

He publicado un artículo en la pantalla de presentación de incorporación en la aplicación en codeproject.Es multiproceso y que pueden ser de su interés

Sin embargo, Otra Pantalla de presentación en C#

private void MainForm_Load(object sender, EventArgs e)
{
     FormSplash splash = new FormSplash();
     splash.Show();
     splash.Update();
     System.Threading.Thread.Sleep(3000);
     splash.Hide();
}

Tengo esto de la Internet en algún lugar, pero no puede encontrarla de nuevo.Simple pero a la vez efectiva.

Me gusta Aku respuesta mucho, pero el código de C# 3.0 y ya que utiliza una función lambda.Para las personas que necesitan utilizar el código en C# 2.0, este es el código que uso anónimo de delegado en lugar de la función lambda.Usted necesita un nivel superior llamado winform formSplash con FormBorderStyle = None.El TopMost = True parámetro de la forma es importante, porque la pantalla de presentación podría parecer que aparece y luego desaparece rápidamente si no superior.Yo también elegir StartPosition=CenterScreen por lo que se ve como lo que es un profesional de la app haría con una pantalla de presentación.Si usted quiere un efecto más, usted puede utilizar el TrasparencyKey propiedad para hacer la irregularidad de la forma de la pantalla de presentación.

private void formMain_Load(object sender, EventArgs e)
  {

     Hide();
     bool done = false;
     ThreadPool.QueueUserWorkItem(delegate
     {
       using (formSplash splashForm = new formSplash())
       {
           splashForm.Show();
           while (!done)
              Application.DoEvents();
           splashForm.Close();
       }
     }, null);

     Thread.Sleep(2000);
     done = true;
     Show();
  }

No estoy de acuerdo con las otras respuestas recomendar WindowsFormsApplicationBase.En mi experiencia, puede retrasar su aplicación.Para ser precisos, mientras se ejecuta el formulario del constructor en paralelo con la pantalla de bienvenida, que posponer su formulario de Muestra del evento.

Considere la posibilidad de una aplicación (sin splashs de la pantalla) con un constructor que toma 1 segundo y un controlador de eventos en la Muestra que se toma de 2 segundos.Esta aplicación es útil después de 3 segundos.

Pero supongamos que usted instale una pantalla de presentación mediante WindowsFormsApplicationBase.Usted podría pensar MinimumSplashScreenDisplayTime de 3 segundos es sensible y no afecta al rendimiento de tu aplicación.Pero, lo intente, la aplicación tardará 5 segundos en cargar.


class App : WindowsFormsApplicationBase
{
    protected override void OnCreateSplashScreen()
    {
        this.MinimumSplashScreenDisplayTime = 3000; // milliseconds
        this.SplashScreen = new Splash();
    }

    protected override void OnCreateMainForm()
    {
        this.MainForm = new Form1();
    }
}

y

public Form1()
{
    InitializeComponent();
    Shown += Form1_Shown;
    Thread.Sleep(TimeSpan.FromSeconds(1));
}

void Form1_Shown(object sender, EventArgs e)
{
    Thread.Sleep(TimeSpan.FromSeconds(2));
    Program.watch.Stop();
    this.textBox1.Text = Program.watch.ElapsedMilliseconds.ToString();
}

Conclusión:no uso WindowsFormsApplicationBase si tu aplicación tiene un controlador en el Slown evento.Usted puede escribir mejor código que se ejecuta el chapoteo en paralelo al constructor y la Muestra de eventos.

En realidad mutlithreading aquí no es necesario.

Deje que su negocio de la lógica de generar un evento cuando desea actualizar la pantalla de presentación.

Luego deje que su forma de actualización de la pantalla de presentación en consecuencia en el método enganchado a eventhandler.

Para diferenciar las actualizaciones puede bomberos de diferentes eventos o proporcionar datos en una clase heredada de EventArgs.

De esta manera usted puede tener bonito el cambio de la pantalla de presentación sin ningún tipo de subprocesamiento múltiple dolor de cabeza.

En realidad, con esto usted puede incluso apoyar, por ejemplo, gif imagen en un formulario de presentación.En orden para que funcione, llame a la Aplicación.DoEvents() en el controlador:

private void SomethingChanged(object sender, MyEventArgs e)
{
    formSplash.Update(e);
    Application.DoEvents(); //this will update any animation
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top