Беда с таймерами и потоками - PullRequest
4 голосов
/ 31 января 2012

Я - обучающийся на примерах C # -кодер, который не очень продвинут, поэтому эта проблема ставит меня в тупик, независимо от количества информации в Интернете.

По сути, я создаю программу, которая по таймеру периодически опрашивает веб-сайт, чтобы получить некоторую информацию. Во время этого процесса создается элемент управления WebBrowser для перехода к информации (необходимой для аутентификации). Программа запускает эту серию событий при запуске, а затем использует System.Timers.Timer, установленный на каждые 10 минут (меньше, конечно, для отладки), чтобы выполнять ту же серию событий, когда мое событие Timer.Elapsed запускает этот процесс, я получаю а:

ThreadStateException с описанием как Элемент управления ActiveX '8856f961-340a-11d0-a96b-00c04fd705a2' не может быть создан, поскольку текущий поток не находится в однопоточной квартире.

Вот уменьшенная версия моей программы.

private void Form1_Load(object sender, EventArgs e)
        {
            GetDataFromWebBrowser();
            Set_Auto_Refresh_Timer();
        }

private void Set_Auto_Refresh_Timer()
        {
            System.Timers.Timer TimerRefresh = new System.Timers.Timer(10000);
            TimerRefresh.Elapsed += new System.Timers.ElapsedEventHandler(TimerRefresh_Elapsed);
            TimerRefresh.AutoReset = true;
            TimerRefresh.Start();
        }    

private void TimerRefresh_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            GetDataFromWebBrowser();
        }

private void GetDataFromWebBrowser()
        {
            WebBrowser wb = new WebBrowser();  <--This is where the error is thrown.

            ...get web data...

        }

Я думаю, у меня достаточно кода, чтобы нарисовать картину Как вы можете видеть, при создании другого WebBrowser выдает ошибку.

Я действительно в замешательстве, и я только начинаю царапать поверхность по Threading, поэтому, наверное, я и так в замешательстве.

// Решение для меня / Я закончил тем, что удалил создание WebBrowser из метода, а также сделал его статическим, чтобы просто повторно использовать элемент управления WebBrowser. Я также поменял свой System.Timers.Timer на System.Threading.Timer. Казалось бы, решить проблему.

Ответы [ 3 ]

7 голосов
/ 31 января 2012

Документация MSDN для WebBrowser гласит:

Класс WebBrowser может использоваться только в потоках, настроенных на однопотоковый режим (STA). Чтобы использовать этот класс, убедитесь, что ваш метод Main помечен атрибутом [STAThread] .

Кроме того, измените System.Timers.Timer на System.Windows.Forms.Timer, если вы хотите регулярно взаимодействовать с элементами управления пользовательского интерфейса. В качестве альтернативы, установите для свойства SynchronizingObject вашего System.Timers.Timer родительский элемент управления, чтобы заставить таймер вызывать вызовы в нужном потоке. Все элементы управления WinForms могут быть доступны только из одного и того же потока пользовательского интерфейса.

В BCL .NET есть три типа таймеров, каждый из которых действует по-разному. Проверьте эту статью MSDN для сравнения: Сравнение классов таймеров в библиотеке классов .NET Framework (веб-архив) или в этой таблице краткого сравнения .

3 голосов
/ 31 января 2012

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

Как показано ниже:

private WebClient webClient;
private void Form1_Load(object sender, EventArgs e)
        {
            GetDataFromWebBrowser();
            Set_Auto_Refresh_Timer();
            this.webClient = new WebClient();
        }

private void Set_Auto_Refresh_Timer()
        {
            System.Timers.Timer.TimerRefresh = new System.Timers.Timer(10000);
            TimerRefresh.Elapsed += new System.Timers.ElapsedEventHandler(TimerRefresh_Elapsed);
            TimerRefresh.AutoReset = true;
            TimerRefresh.Start();
        }    

private void Set_Auto_Refresh_Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            GetDataFromWebBrowser();
        }

private void GetDataFromWebBrowser()
        {
            ...perform required work with webClient...
            ...get web data...

        }
0 голосов
/ 31 января 2012

Как сказал Groo, вы должны использовать System.Windows.Forms.Timer , или, если вы действительно хотите выполнять свою работу в другом потоке, вы должны использовать метод Invoke для выполнения любых вещей, связанных с пользовательским интерфейсом:

private void GetWebData()
{
     ...get web data...
}

private void ShowWebData()
{
    WebBrowser wb = new WebBrowser();
    // other UI stuff
}

private void TimerRefresh_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    GetDataFromWebBrowser();
}

private void GetDataFromWebBrowser()
{
    GetWebData();

    if (this.InvokeRequired)
        this.Invoke(new Action(ShowWebData));
    else
        ShowWebData();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...