domingo, 29 de agosto de 2010

[WinForms] - Abrir formulario modal en el evento Load

 

Introducción

En algunas situaciones puede ser necesario realizar la apertura de alguna ventana nueva en forma modal desde un lugar algo particular, como es el evento Load del formulario.

Cualquier proceso que bloque la terminación completa de este evento impedirá que se muestre el formulario que se esta abriendo hasta tanto no se cierre el que se encuentra visualmente activo.

Por ejemplo, si en el código utilizan algunas líneas como estas:

private void Form2_Load(object sender, EventArgs e)
{
    Form3 frm = new Form3();
    frm.ShowDialog();
}

notaran el efecto que se comenta, en donde el Form2 no se visualiza, pero si el Form3, recién cuando este ultimo es cerrado el evento Load termina y se despliega el Form2.

Para evitar este efecto hay algunas técnicas que pueden aplicarse, pero básicamente lo que buscan es realizar la apertura del formulario modal un tiempo después de concluir el evento Load.

 

Utilizando las API de Windows

Mediante el uso de un mensaje a las API se puede enviar un mensajes al proceso de Windows, atapándolo y lanzando allí la ventana.

public partial class Form2 : Form
{
    
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);


    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {
        PostMessage(this.Handle, 7000, 0, 0);
    }


    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 7000)
        {
            Form3 frm = new Form3();
            frm.ShowDialog();

            m.Result = (IntPtr)0;
            return;
        }

        base.WndProc(ref m);
    }

}
[C#]
 

Utilizando el Timer

Esta otra alternativa declara en muy pocas líneas un objeto Timer, en donde el uso de métodos anónimos permite definir el cuerpo del evento Tick que será lanzado luego de 1 ms, mas que suficiente para que el evento Load termine de ejecutarse.

 

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {

        Timer timer = new Timer();
        timer.Interval = 1;
        timer.Tick += delegate(object s, EventArgs eventarg)
        {
            ((Timer)s).Stop();
            Form3 frm = new Form3();
            frm.ShowDialog();
        };
        timer.Start();

    }
}

La idea es esta alternativa es mostrar además que no es necesario definir evento en métodos separados que harían engorrosa esta implementación, aquí en un bloque de unas pocas líneas se logra el efecto deseado.

[C#]
 

Conclusión

El efecto que debe lograrse es el no bloqueo del evento Load del formulario, estas dos técnicas lo logran, pero seguramente se preguntaran porque no se han usando Thread.

El problema surge porque lo Thread generan un hilo independiente evitando que los formularios actúen como modales, si el Form3 es abierto dentro de un nuevo hilo este ya no seria modal, sino que se abriría como una ventana común a la cual se le aplico el método Show()

8 comentarios:

  1. Hola Leandro, he visto tu articulo y me parece excelente, solo que no hayo como aplicarlo en mi codigo, tengo un Form.ShowDialog(), y quiero que mi proceso siga pero no lo hace .

    public PDFViewer()
    {
    InitializeComponent();

    }

    private void PDFViewer_Load(object sender, EventArgs e)
    {

    this.PDFViewer2.RefreshReport();
    }

    private void PDFViewer2_Print(object sender, Microsoft.Reporting.WinForms.ReportPrintEventArgs e)
    {
    this.PDFViewer2.Show();
    }
    }}


    entra al metodo load pero no conitnua

    ResponderEliminar
    Respuestas
    1. hola
      A que proceso haces referencia ? en el codigo que has puesto no veo ninguno. Ademas no veo donde creas la instancoa del form de previo de pdf que estas mostando
      saludos

      Eliminar
    2. Hola Leandro, disculpa la demora, mira este es mi codigo

      public void visualizaFac(Boolean v)
      {
      try
      {
      pdfviewer = new Forms.PDFViewer();
      pdfviewer.Refresh();
      pdfviewer.PDFViewer2.Clear();
      pdfviewer.PDFViewer2.LocalReport.Refresh();

      pdfviewer.PDFViewer2.LocalReport.ReportPath = Path.Combine(directorioPrincipal, @"\Fac.rdlc");
      pdfviewer.PDFViewer2.LocalReport.EnableExternalImages = true;
      pdfviewer.PDFViewer2.LocalReport.DataSources.Add(new ReportDataSource("Conceptos"));

      pdfviewer.PDFViewer2.SetDisplayMode(DisplayMode.PrintLayout);
      pdfviewer.PDFViewer2.LocalReport.SetParameters(lista);
      pdfviewer.PDFViewer2.LocalReport.DataSources.Clear();
      pdfviewer.PDFViewer2.LocalReport.DataSources.Add(repdata);
      pdfviewer.PDFViewer2.ZoomMode = Microsoft.Reporting.WinForms.ZoomMode.PageWidth;
      pdfviewer.PDFViewer2.RefreshReport();

      if (v)
      {
      try
      {


      pdfviewer.PDFViewer2.LocalReport.Render("Image", deviceInfo);
      pdfviewer.DialogResult = pdfviewer.ShowDialog();

      }
      catch (Exception e)
      {
      MessageBox.Show(e.Message);
      }
      }
      }
      catch (Exception e)
      {
      throw new Exception("Error en visualizer archivo:\r\n" + e.Message);
      }
      }

      Eliminar
    3. hola
      si usas un ShowDialog() el codigo se detendra alli hasta tanto cierres el form, por eso es que se llama modal,sino deberias usar simplemente el Show() pero no ser un form modal y deberas djuntar el evento closing del form para detectar cuando se cierre
      saludos

      Eliminar
    4. Hola Leandro, por consiguiente si uso ShowDialog(), no hay alguna manera de que mi codigo continue hasta que yo cierre el form?.
      Y una duda cuando uso el Show(), no se muestra mi reporte se queda trabado, tienes alguna idea de porque hace eso?
      Gracias y Saludos!!

      Eliminar
    5. si usas el showdialog() el codigo no continua hasta que cierres el form, es asi como funciona
      la verdad es que no se que sera un reporte trabado, podrias poner un breakpoint en el codigo y evaluar si la ejecucion pasa por el codigo que asigna datos al reporte

      Eliminar
    6. Hola Leandro, ya solucione mi problema, hice una aplicacion a la cual le paso argumentos y con eso logro abrir mi form varias veces.
      Saludos.

      Eliminar