Нарисуйте изображение на форме из отдельной темы - PullRequest
2 голосов
/ 10 января 2010

В настоящее время я работаю над приложением Windows.Forms. Это в основном простая проблема с обнаружением движения.

У меня есть кнопка на форме, которая при нажатии запускает фоновый рабочий, который выполняет следующие действия:

  1. Получить изображение с диска
  2. Создание нового растрового изображения для использования в качестве буфера.
  3. Выполнить обнаружение движения
  4. Из результатов обнаружения движения обновите буфер (используя поверхность рисования буфера)
  5. Запустить событие изменения прогресса с аргументом, состоящим из клона буфера, в основном (sender as BackgroundWorker).ReportProgress((Bitmap)buffer.Clone())

В событии Progress Changed я затем рисую буфер на экране.

if (!PnlImage.IsDisposed)
            PnlImage.CreateGraphics().DrawImageUnscaled(buffer, 0, 0);

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

РЕДАКТИРОВАТЬ: С тех пор я обновил программу для использования .NET Framework 4, и мы больше не используем BackgroundWorker. Вместо этого мы теперь используем пространства имен System.Threading.Tasks и используем Invoke для обновления фонового изображения изнутри задачи.

Спасибо за все ответы.

Ответы [ 4 ]

2 голосов
/ 10 января 2010

Я полагаю, что корень любых проблем, с которыми вы можете столкнуться, заключается в том, что любые обновления GUI должны выполняться в потоке пользовательского интерфейса. Вы не можете безопасно обновить пользовательский интерфейс из другого потока. Итак, в основном вам нужно сделать что-то вроде следующего (я просто меняю цвет фона в качестве примера, но вы можете делать все что угодно):

    private void SomethingCalledFromBackgroundThread()
    {
        panel1.Invoke(new DoUpdatePanel(UpdatePanel), Color.Blue);
    }

    private delegate void DoUpdatePanel(Color aColor);

    private void UpdatePanel(Color aColor)
    {
        panel1.BackColor = aColor;
    }

============ Обновление =======>

@ Эш, ты неправильно описал мой ответ. Я не говорил звонить Invoke изнутри ProgressChanged. @Jean помните, что ReportProgress / ProgressChanged запускается асинхронно - вот почему вы делаете клон своего изображения. В этом нет необходимости, если вы используете Invoke из фонового потока, а не ReportProgress.

1 голос
/ 11 января 2010

Использование события ProgressChanged - это нормально. Что не хорошо, так это рисование прямо на экране. Ваше изображение исчезнет, ​​когда вы свернете и восстановите форму. Обходной путь прост:

 PnlImage.BackgroundImage = buffer;
1 голос
/ 10 января 2010

События ProgressChanged и RunWorkerCompleted позволяют напрямую обновлять пользовательский интерфейс. Только обработчик событий DoWork вы не должны получать доступ от. См. MSDN :

Вы должны быть осторожны, чтобы не манипулировать любые объекты пользовательского интерфейса в вашем Обработчик событий DoWork. Вместо, общаться с пользовательским интерфейсом через ProgressChanged и События RunWorkerCompleted.

Это одно из основных преимуществ использования BackgroundWorker по сравнению с созданием собственного потока. Поэтому TheObjectGuy не верен, вам не нужно использовать BeginInvoke / Invoke в ProgressChanged.

Пока ваше изображение не слишком большое, клонирование не должно вызывать серьезных проблем с производительностью. Если у вас есть проблемы, запустите несколько тестов производительности с большими изображениями.

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

1 голос
/ 10 января 2010

Я не уверен, является ли это строго правдой, но я уверен, что вы не можете выполнять перекрестные операции GUI / Control в отдельном потоке, поскольку это обрабатывается по умолчанию в выделенном потоке GUI.

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

...