Проблемы с Backgroundworker, графический интерфейс завис - PullRequest
0 голосов
/ 05 декабря 2011

Я использую фоновый рабочий под формой, и когда я нажимаю кнопку, он должен сгенерировать документ, но графический интерфейс зависает, я не знаю, почему это происходит, потому что я чувствую, что правильно использую фонового работника.Может кто-нибудь поможет в этом?

  private void btn_GenerateRevDoc_Click(object sender, EventArgs e)
    {
        DOC_GenerateVersDocBackgroundWorker = new BackgroundWorker();
        DOC_GenerateVersDocBackgroundWorker.WorkerReportsProgress = true;
        DOC_GenerateVersDocBackgroundWorker.WorkerSupportsCancellation = true;

        DOC_GenerateVersDocBackgroundWorker.DoWork += new DoWorkEventHandler(DOC_GenerateVersDocBackgroundWorker_DoWork);
        DOC_GenerateVersDocBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(DOC_GenerateVersDocBackgroundWorker_ProgressChanged);
        DOC_GenerateVersDocBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(DOC_GenerateVersDocBackgroundWorker_RunWorkerCompleted);
        System.Threading.Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
        if (Db.docVersionHistory != null && Db.docVersionHistory.Count > 0)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "Export Review To";
            sfd.Filter = "Word files (*.doc)|*.doc|All files (*.*)|*.*";
            sfd.FilterIndex = 1;
            sfd.FileName = "";

            if (sfd.ShowDialog() == DialogResult.OK)
            {


                if (!DOC_GenerateVersDocBackgroundWorker.IsBusy)
                    DOC_GenerateVersDocBackgroundWorker.RunWorkerAsync(sfd.FileName);
            }
        }
        else
        {
            MessageBox.Show("No Review Records were found!");
        }

    }
    void DOC_GenerateVersDocBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        if (this.InvokeRequired)
        {
            Invoke(new MethodInvoker(delegate
                     {

                         DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));

                     }));
        }
        else
        {
            DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));

        }
    }

Ответы [ 5 ]

1 голос
/ 05 декабря 2011

Вы не совсем понимаете, как предполагается использовать BackgroundWorker и что делает метод Invoke.

Метод Invoke вызывает код, вызываемый в потоке пользовательского интерфейса.Поэтому не пропускайте метод DocumentsNavigator.GenerateWordRevisionHistoryDoc через Invoke.RunWorkerAsync в порядке.Я не знаю, что такое типы versionsList и Db, но если они являются объектами пользовательского интерфейса, вам может потребоваться скопировать нужные значения в новую переменную.Например, если versionsList является ListBox, вы должны скопировать выбранные значения в новый string[] и использовать это string[] в качестве параметра для вашего метода.

Вот что вы думаете, что выхотел сделать:

  • Создать новый фоновый работник

  • инициализировать фоновый работник

  • отключитьКнопка btn_GenerateRevDoc

  • Показать SaveFileDialog

  • Запустить BackgroundWorker (RunWorkerAsync)

  • В случае события ProgressChanged, если вы отображаете индикатор выполнения или что-то в этом роде, вы можете обновить его, на этот раз вам придется пройти через метод Invoke.

  • А на событии RunWorkerCompleted покажите окно сообщения или что-то еще, и снова включите кнопку btn_GenerateRevDoc

О, и эта строка должна быть абсолютно удалена:

System.Threading.Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
0 голосов
/ 05 декабря 2011

Проблема в том, что вы запускаете код, который вешает GUI в рабочем потоке, но вы делаете это методом Invoke.

Метод Invoke запускает код в потоке графического интерфейса и поэтому зависает.

Если вам абсолютно необходимо вызвать DocumentsNavigator.GenerateWordRevisionHistoryDoc в потоке графического интерфейса, я не вижу, как вы можете сделать этот вызов, не повесив графический интерфейс.

Попробуйте переосмыслить свой код, чтобы вам не приходилось запускать какой-либо код в BackgroungWorker в методе Invoke.

0 голосов
/ 05 декабря 2011

когда я нажимаю кнопку, это должно сгенерировать документ, но графический интерфейс зависает

из вашего кода. Я вижу, что вы должны ввести имя файла и нажать кнопку ОК.Есть ли где-нибудь диалоговое окно сохранения?

Попробуйте написать тот же код без использования фонового рабочего.Это все еще висит?Кроме того, заметил, что условие if (!DOC_GenerateVersDocBackgroundWorker.IsBusy) не имеет смысла, так как вы создаете новый фоновый работник при каждом нажатии кнопки

0 голосов
/ 05 декабря 2011

Вы делаете что-то небезопасное.

вместо Invoke попробуйте

if (this.InvokeRequired)         
{             this.BeginInvoke(new MethodInvoker(delegate                      
   { 
0 голосов
/ 05 декабря 2011

Внутри вашего фонового работника вы снова перенаправляете всю работу в поток пользовательского интерфейса, поэтому ваш пользовательский интерфейс зависает

 if (this.InvokeRequired)
        {
            //this executes the work on UI thread
            Invoke(new MethodInvoker(delegate
                     {

                         DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));

                     }));
        }
        else
        {
//it will also be executed on UI thread     
   DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));

        }
    }
...