Вызов метода в потоке GUI из потока таймеров - PullRequest
9 голосов
/ 18 октября 2010

В моем приложении я использую таймер для проверки обновлений в ленте RSS. Если новые элементы найдены, я выскакиваю в настраиваемое диалоговое окно для информирования пользователя. Когда я запускаю проверку вручную, все отлично работает, но когда автоматическая проверка запускается в событии Истекшее время, пользовательское диалоговое окно не отображается.

Прежде всего, это проблема? (Я предполагаю, что это потому, что как при ручной, так и при автоматической проверке используется один и тот же код).

Когда я запускаю автоматическую проверку, должен ли я вызывать метод, запускающий проверку, из обработчика событий Timers Elapsed?

Есть ли что-то, что мне нужно сделать в моем пользовательском диалоговом классе?

Edit: это приложение winforms.

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

public class MainForm : System.Windows.Forms.Form
{
    //This is the object that does most of the work.
    ObjectThatDoesWork MyObjectThatDoesWork = new ObjectThatDoesWork(); 
    MyObjectThatDoesWork.NewItemsFound += new NewItemsFoundEventHandler(Found_New_Items);

    private void Found_New_Items(object sender, System.EventArgs e)
    {
        //Display custom dialog to alert user.
    }

    //Method that doesn't really exist in my class, 
    // but shows that the main form can call Update for a manual check.
    private void Button_Click(object sender, System.EventArgs e)
    {
        MyObjectThatDoesWork.Update();
    }

    //The rest of MainForm with boring main form stuff
}


public class ObjectThatDoesWork
{
    System.Timers.Timer timer;

    public ObjectThatDoesWork()
    {
        timer = new System.Timers.Timer();
        timer.Interval = 600000;
        timer.AutoReset = true;
        timer.Elapsed += new new System.Timers.ElapsedEventHandler(TimeToWork);
        timer.Start();
    }

    private void TimeToWork(object sender, System.Timers.ElapsedEventArgs e)
    {
        Update();
    }

    public void Update()
    {
        //Check for updates and raise an event if new items are found.
        //The event is consumed by the main form.
        OnNewItemsFound(this);
    }

    public delgate void NewItemsFoundEventHandler(object sender, System.EventArgs e);
    public event NewItemsFoundEventHandler NewItemsFound;
    protected void OnNewItemsFound(object sender)
    {
        if(NewItemsFound != null)
        {
            NewItemsFound(sender, new System.EventArgs());
        }
    }
}

После прочтения некоторых комментариев и ответов я думаю, что моя проблема в том, что я использую System.Timers.Timer, а не System.Windows.Forms.Timer.

EDIT:

После перехода на Forms.Timer начальное тестирование выглядит хорошо (но никаких новых элементов еще не существует, поэтому пользовательский диалог еще не виден). Я добавил немного кода для вывода идентификатора потока в файл при вызове метода обновления. При использовании Timers.Timer идентификатор потока не был потоком GUI, но при использовании Forms.Timer идентификатор потока совпадает с GUI.

Ответы [ 4 ]

18 голосов
/ 18 октября 2010

Какой таймер вы используете?System.Windows.Forms.Timer автоматически запускает событие в потоке пользовательского интерфейса.Если вы используете другой, вам нужно будет использовать Control.Invoke для вызова метода в потоке пользовательского интерфейса.

1 голос
/ 18 октября 2010

Вы должны использовать Forms.Timer здесь, или, если вы используете другие виды таймеров, сериализовать вызовы пользовательского интерфейса с .Invoke()

0 голосов
/ 03 февраля 2014
    private static System.Threading.SynchronizationContext _UI_Context;
    //call this function once from the UI thread
    internal static void init_CallOnUIThread()
    {
        _UI_Context = System.Threading.SynchronizationContext.Current;
    }
    public static void CallOnUIThread(Action action, bool asynchronous = false)
    {
        if (!asynchronous)
            _UI_Context.Send((o) =>
            {
                action();
            }, null);
        else
            _UI_Context.Post((o) =>
            {
                action();
            }, null);
    }
0 голосов
/ 18 октября 2010

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

Разместите некоторый код, чтобы вы могли получить более качественную помощь и взглянуть на класс Dispatcher http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...