none
System.InvalidOperationException: 'No se puede mostrar un cuadro de diálogo que se creó en un subproceso diferente.' RRS feed

  • Pregunta

  • Buenas noche.

    Estoy desarrollando un proyecto en c# wpf, donde necesito convertir un pdf en word. He utilizado la librería SautinSoft.PdfFocus. Cuando ejecuto el programa me deja elegir el pdf guardado en mi pc pero luego se detiene el progama y m sale el siguiente error

    System.InvalidOperationException: 'No se puede mostrar un cuadro de diálogo que se creó en un subproceso diferente.'

    Mi código es el siguiente.

      private readonly BackgroundWorker worker = new BackgroundWorker();
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            Boolean x = false;
            private void Word_Click(object sender, RoutedEventArgs e)
            {
                worker.DoWork += worker_DoWork;

                worker.RunWorkerCompleted += worker_RunWorkerCompleted;
                worker.RunWorkerAsync();
            }

            private void worker_DoWork(object sender, DoWorkEventArgs e)
            {
                
                MessageBox.Show("Choose the pdf to convert");
                Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();
                dialog.Title = "Choose PDF";
                dialog.Filter = "Archivos de Pdf|*.pdf";
                Nullable<bool> result = dialog.ShowDialog();
                if (result==true)
                {
                    x = true;
                    SautinSoft.PdfFocus f = new SautinSoft.PdfFocus();

                    f.Serial = "XXXXX";

                    f.OpenPdf(dialog.FileName);

                    MessageBox.Show("Now you have to choose where you want to save the word document");

                    if (f.PageCount > 0)

                    {

                        saveFileDialog.Filter = "Archivos Word|*.docx";
                        saveFileDialog.Title = "Guardar archivo";
                        saveFileDialog.FileName = "ArchivoPdfCRG";
                        if (saveFileDialog.ShowDialog() == true)   // esta es la línea donde sale el erro
                        {
                            var path = string.Empty;
                            path = saveFileDialog.FileName;
                            this.Dispatcher.Invoke(() =>
                            {

                               
                            });
                            f.ToWord(path);
                        }




                    }



                }

                else
                {
                    x = false;
                    MessageBox.Show("Usted ha cancelado la operación.");
                }




            



                

               

            }

    jueves, 26 de agosto de 2021 1:22

Respuestas

  • El problema proviene de que tienes interacciones con la pantalla dentro del DoWork del BackgroundWorker.

    El DoWork se ejecuta en un hilo distinto, y en aplicaciones de escritorio no es lícito que se interactúe con la interfaz de usuario desde un hilo distinto al que la creó. Esto se debe a que sus estructuras internas no tienen bloqueos y se pueden corromper si se manipula desde un hilo distinto. Esto da lugar a fallos intermitentes y difíciles de reproducir y depurar en el programa que así lo hace. Para evitarlo, WPF tiene controles en algunos sitios de forma que si detecta que estás haciendo esto te levanta la excepción de "... subproceso diferente". Pero incluso aunque encuentres manera de saltarte estos controles, no deberías hacerlo debido a ese problema de que se corromperá y fallará impredeciblemente el programa.

    Entonces, ¿qué hay que hacer? Pues todas las interacciones con el usuario tienen que hacerse fuera del DoWork. Primero recaba todos los datos que requieras del usuario, por ejemplo, si tienes que presentar un mensaje o llamar al OpenFileDialog, haz esto en el código principal, antes de lanzar el DoWork. Después ejecutas el Dowork, que en su inerior no debe contener ni llamar a nada que presente ningún dato ni mensaje ni ventana en pantalla. Si tienes que mostrar una indicación de progreso, puedes usar el evento ProgressChanged del BackGroundWorker, que se dispara en el hilo principal en lugar del de background. Y si luego al final tienes que mostrar un mensaje al usuario, muestra el mensaje en el evento RunWorkerCompleted, que ocurre en el hilo principal. No lo muestres desde dentro del propio DoWork.

    En otras palabras, tu metodo worker_DoWork solo deberia contener la linea f.ToWord(path). Todo lo demas hay que hacerlo fuera del DoWork.
    jueves, 26 de agosto de 2021 7:40
    Moderador

Todas las respuestas

  • El problema proviene de que tienes interacciones con la pantalla dentro del DoWork del BackgroundWorker.

    El DoWork se ejecuta en un hilo distinto, y en aplicaciones de escritorio no es lícito que se interactúe con la interfaz de usuario desde un hilo distinto al que la creó. Esto se debe a que sus estructuras internas no tienen bloqueos y se pueden corromper si se manipula desde un hilo distinto. Esto da lugar a fallos intermitentes y difíciles de reproducir y depurar en el programa que así lo hace. Para evitarlo, WPF tiene controles en algunos sitios de forma que si detecta que estás haciendo esto te levanta la excepción de "... subproceso diferente". Pero incluso aunque encuentres manera de saltarte estos controles, no deberías hacerlo debido a ese problema de que se corromperá y fallará impredeciblemente el programa.

    Entonces, ¿qué hay que hacer? Pues todas las interacciones con el usuario tienen que hacerse fuera del DoWork. Primero recaba todos los datos que requieras del usuario, por ejemplo, si tienes que presentar un mensaje o llamar al OpenFileDialog, haz esto en el código principal, antes de lanzar el DoWork. Después ejecutas el Dowork, que en su inerior no debe contener ni llamar a nada que presente ningún dato ni mensaje ni ventana en pantalla. Si tienes que mostrar una indicación de progreso, puedes usar el evento ProgressChanged del BackGroundWorker, que se dispara en el hilo principal en lugar del de background. Y si luego al final tienes que mostrar un mensaje al usuario, muestra el mensaje en el evento RunWorkerCompleted, que ocurre en el hilo principal. No lo muestres desde dentro del propio DoWork.

    En otras palabras, tu metodo worker_DoWork solo deberia contener la linea f.ToWord(path). Todo lo demas hay que hacerlo fuera del DoWork.
    jueves, 26 de agosto de 2021 7:40
    Moderador
  • Hola Joshytano,

    ¿Alguna novedad sobre la consulta realizada?

    ¿Ha sido útil la respuesta brindada por Alberto?

    Gracias por usar los foros de MSDN.

    Eric Ruiz

    ____________________________

    Por favor recuerde "Marcar como respuesta" las respuestas que hayan resuelto su problema, es una forma común de reconocer a aquellos que han ayudado, y hace que sea más fácil para los otros visitantes encontrar la solución más tarde.

    Si tiene algún cumplido o reclamo sobre el soporte de MSDN siéntase en la libertad de contactar MSDNFSF@microsoft.com.

    jueves, 26 de agosto de 2021 16:34
    Moderador
  • gracias era eso mismo...saque del método  worker_DoWork  y funciono todo bien....muchas gracias
    jueves, 26 de agosto de 2021 18:29
  • Si me fue útil ...de hecho soluciono mi problema...gracias
    jueves, 26 de agosto de 2021 18:31