Вызов метода в потоке GUI из потока таймеров
В моем приложении я использую таймер для проверки обновлений в ленте RSS. Если новые элементы найдены, я выскакиваю в настраиваемое диалоговое окно для информирования пользователя. Когда я запускаю проверку вручную, все отлично работает, но когда автоматическая проверка запускается в событии Elapsed таймеров, пользовательский диалог не отображается.
Прежде всего, это вопрос? (Я предполагаю, что это потому, что как ручная, так и автоматическая проверка используют один и тот же код).
Когда я запускаю автоматическую проверку, должен ли я вызывать метод, который запускает проверку, из обработчика событий Timers Elapsed?
Есть ли что-то, что мне нужно сделать в моем пользовательском диалоговом классе?
Изменить: это приложение 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
,
РЕДАКТИРОВАТЬ:
После перехода на Forms.Timer начальное тестирование выглядит хорошо (но никаких новых элементов пока не существует, поэтому пользовательский диалог еще не виден). Я добавил немного кода для вывода идентификатора потока в файл при вызове метода обновления. При использовании Timers.Timer идентификатор потока не был потоком GUI, но при использовании Forms.Timer идентификатор потока совпадает с GUI.
4 ответа
Какой таймер вы используете? System.Windows.Forms.Timer автоматически запускает событие в потоке пользовательского интерфейса. Если вы используете другой, вам нужно будет использовать Control.Invoke для вызова метода в потоке пользовательского интерфейса.
Вы должны использовать Forms.Timer здесь, или, если вы используете другие виды таймеров, сериализовать вызовы к UI с .Invoke()
Является ли ваше приложение WPF-приложением? Если это так, вы должны делегировать работу из фонового потока в Dispatcher, связанный с потоком пользовательского интерфейса.
Разместите некоторый код, чтобы вы могли получить более качественную помощь и взглянуть на класс Dispatcher http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx
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);
}