InvokeRequired имеет значение true для PictureBox. Как с этим бороться? - PullRequest
1 голос
/ 13 сентября 2010

У меня был еще вопрос на моих вызовах PictureBox, дающий мне 3 вида ошибок, некоторые отличные ответы пришли, в частности, от Конрад Фрикс .Так что это заставило меня выяснить, где моя проблема, но теперь, чтобы решить ее, я не уверен на 100%.

По сути, у меня есть таймер Windows Form, который проверяет, является ли какое-либо событие истинным, если оно есть, то он сообщает системе, что необходимо отправить некоторые данные через 2 секунды после того, как указанное событие (значение) превысило некоторый порог..

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

new Bitmap(myPicBox.Image); 

и т.д ...

Я где-то читал, что интервал таймера должен быть не менее 50. Установите это значение из 33. Я обнаружил, что могу сделать picCapture.InvokeRequired, чтобы посмотреть, действительно ли он умрет.Я знаю, что мне нужно использовать делегата, но я когда-либо использовал его только для того, чтобы что-то установить ... не для того, чтобы получить изображение ... не знаю, как это настроить ... Я знаю, что на самом деле вызывает его, именно этокомбинация кода:

private void timer1_Tick(object sender, EventArgs e)
    {
          if(someCOnditionTrue)
          {

                    TimerCallback tc = new TimerCallback(sendDataFast); //only 
                       //doing all this so i can have the method run two seconds after     
                       // the condition is detected to be true.
                    System.Threading.Timer t = new System.Threading.Timer(tc, null, 2000, Timeout.Infinite);
          }
   }



    void sendDataFast(Object stateObject)
    {

        //using this so the execution is not haulted while the sending of data takes place.
        EmergencyDelegate delEmergency =
                     new EmergencyDelegate(mic.sendEmergencyData);

        Image imgclone;

        if (picCapture.InvokeRequired)
        {                 
            Console.WriteLine("HFS Batman! its going to die ");
        }
        lock (lockObject2) //i admit no clue what im doing here and doesn't seem to help.
        {
            Image img = picCapture.Image;
            imgclone = (Image)img.Clone();
        }
        delEmergency.BeginInvoke(imgclone, null, null); //deep in the call to
        //sendEmergencyData i get the **ParameterNotValid** almost everytime.

        imgclone.Dispose(); //to free memory?


    }

Согласно моему предыдущему вопросу, больше не возникает проблем с памятью или других ошибок в событии timer1_tick ... (ошибка нехватки памяти была одна).

Я думаю, что самая большая проблема заключается в том, как я могу обработать picCapture.InvokeRequired, когда мне нужны данные изображения?Я уверен, что это вызов таймера потоков внутри timer1_click, который я делаю, который вызывает это ....

Ответы [ 3 ]

1 голос
/ 13 сентября 2010

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

В вашем случае, если изображение PictureBox не меняется, я бы посоветовал вам сделать клон изображения заранее и использовать его. В противном случае вам нужно использовать Control.Invoke.

1 голос
/ 13 сентября 2010

У вас слишком много тем, чтобы довести это до хорошего конца. И Timer, и метод BeginInvoke () делегата будут использовать поток пула потоков. Проблема в том, что свойство PictureBox.Image является лишь частично поточно-ориентированным. Он может быть доступен только одному потоку за раз. Ваш код умрет с исключением, когда изображение будет нарисовано потоком пользовательского интерфейса в то же самое время, когда ваш код вызывает метод Clone ().

Ваш оператор блокировки не решает проблему, PictureBox обращается к свойству Image без использования той же самой блокировки. Я настоятельно рекомендую сначала избавиться от потоков, используйте System.Windows.Forms.Timer вместо System.Threading.Timer. Это событие Tick возникает в потоке пользовательского интерфейса. Это, однако, сделает поток пользовательского интерфейса не отвечающим во время выполнения события, это зависит от того, сколько времени это займет, заметно ли это для пользователя. Больше, чем, скажем, 100 миллисекунд становятся проблемой.

Единственный другой подход - попытаться сделать потокобезопасным элемент управления PictureBox. Это возможно в некоторой степени. Добавьте новый класс в ваш проект и вставьте код, показанный ниже. Компиляция. Перетащите новый элемент управления из верхней части панели инструментов на форму, заменив существующий PB. Помните, что это только частичное решение, отображение анимированного GIF или использование свойства ImageLocation по-прежнему будут бомбить. Используйте предоставленный метод Clone вместо вызова Clone для свойства Image.

using System;
using System.Drawing;
using System.Windows.Forms;

class MyPictureBox : PictureBox {
    private object locker = new object();
    public new Image Image {
        get { return base.Image; }
        set { lock (locker) { base.Image = value; } }
    }
    public Image Clone() {
        lock (locker) {
            return (this.Image != null) ? (Image)this.Image.Clone() : null;
        }
    }
    protected override void OnPaint(PaintEventArgs pe) {
        lock (locker) {
            base.OnPaint(pe);
        }
    }
}
1 голос
/ 13 сентября 2010

Как следует из названия, InvokeRequired означает, что вам нужно позвонить Invoke (или BeginInvoke) при доступе к элементу управления.

Обратите внимание, что это Control.Invoke /Control.BeginInvoke, не Invoke/BeginInvoke, которые присутствуют в делегатах ... хотя вам понадобится делегат для вызова Invoke /BeginInvoke, просто чтобы добавить больше путаницы к миксу.

См. Раздел Windows Forms моего учебного курса по потокам для получения дополнительной информации.Общий урок может быть с обновлением, но я думаю, что это нормально.В других ситуациях вы также можете рассмотреть возможность использования BackgroundWorker, но я не думаю, что это может быть актуально для вас в данном конкретном случае.

...