Сведения о вопросе

SOON

02:34, 7th August, 2020

Теги

Выбрали компактный рамках/нарезание резьбы - MessageBox отображается над другими элементами управления после того, как опция

Просмотров: 585   Ответов: 3

Я работаю над приложением, которое захватывает и устанавливает кучу обновлений с внешнего сервера,и мне нужна помощь с потоковой обработкой. Пользователь выполняет этот процесс:

  • Нажимает кнопку
  • Метод проверяет наличие обновлений, возвращается счетчик.
  • Если больше 0, то спросите пользователя, если они хотят установить с помощью MessageBox.Show().
  • Если да, то он проходит через цикл и вызывает BeginInvoke() в методе run() каждого обновления, чтобы запустить его в фоновом режиме.
  • В моем классе обновления есть некоторые события, которые используются для обновления индикатора выполнения и т. д.

Обновления индикатора выполнения в порядке, но MessageBox не полностью очищается от экрана, потому что цикл обновления начинается сразу после нажатия пользователем кнопки да (см. снимок экрана ниже).

  • Что я должен сделать, чтобы сделать messagebox исчезнуть мгновенно до начала цикла обновления?
  • Должен ли я использовать потоки вместо BeginInvoke()?
  • Должен ли я выполнять начальную проверку обновления в отдельном потоке и вызывать MessageBox.Show() из этого потока?

Код

// Button clicked event handler code...
DialogResult dlgRes = MessageBox.Show(
    string.Format("There are {0} updates available.\n\nInstall these now?", 
    um2.Updates.Count), "Updates Available", 
    MessageBoxButtons.YesNo, 
    MessageBoxIcon.Question, 
    MessageBoxDefaultButton.Button2
);

if (dlgRes == DialogResult.Yes)
{
    ProcessAllUpdates(um2); 
}

// Processes a bunch of items in a loop
private void ProcessAllUpdates(UpdateManager2 um2)
{
    for (int i = 0; i < um2.Updates.Count; i++)
    {
        Update2 update = um2.Updates[i];

        ProcessSingleUpdate(update);

        int percentComplete = Utilities.CalculatePercentCompleted(i, um2.Updates.Count);

        UpdateOverallProgress(percentComplete);
    }
}

// Process a single update with IAsyncResult
private void ProcessSingleUpdate(Update2 update)
{
    update.Action.OnStart += Action_OnStart;
    update.Action.OnProgress += Action_OnProgress;
    update.Action.OnCompletion += Action_OnCompletion;

    //synchronous
    //update.Action.Run();

    // async
    IAsyncResult ar = this.BeginInvoke((MethodInvoker)delegate() { update.Action.Run(); });
}

Скриншот

Windows Mobile Bug



  Сведения об ответе

lool

00:35, 5th August, 2020

Ваш UI не обновляется, потому что вся работа происходит в потоке пользовательского интерфейса. Ваш призыв к:

this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); }) 

это говорит вызвать update.Action.Run() в потоке, который создал "this" (ваша форма), который является потоком пользовательского интерфейса.

Application.DoEvents()

это действительно даст потоку UI шанс перерисовать экран, но я бы хотел создать новый делегат и вызвать BeginInvoke на этом.

Это приведет к выполнению функции update.Action.Run() в отдельном потоке, выделенном из пула потоков. Затем вы можете продолжать проверять IAsyncResult до тех пор, пока обновление не будет завершено, запрашивая объект update для его выполнения после каждой проверки (потому что вы не можете позволить другому потоку обновить прогресс bar/UI),, а затем вызвать Application.DoEvents().

Вы также должны позвонить EndInvoke() после этого, иначе вы можете в конечном итоге утечка ресурсов

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


  Сведения об ответе

ASER

09:16, 6th August, 2020

@ John Sibly

Вы можете обойтись без вызова EndInvoke, когда имеете дело с WinForms без каких-либо негативных последствий.

Единственное задокументированное исключение из правила, о котором я знаю, находится в формах Windows, где вам официально разрешено звонить Control.BeginInvoke, не беспокоясь о вызове Control.EndInvoke.

Однако во всех других случаях, когда вы имеете дело с асинхронным шаблоном Begin/End, вы должны предположить, что он будет протекать, как вы и сказали.


  Сведения об ответе

ЯЯ__4

07:00, 2nd August, 2020

А вы пробовали поставить а

Application.DoEvents()

здесь

if (dlgRes == DialogResult.Yes)
{
   Application.DoEvents(); 
   ProcessAllUpdates(um2); 
}


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться