Может ли таймер вызвать событие меню? - PullRequest
0 голосов
/ 29 июня 2009

У меня есть приложение C # Windows Form, которое содержит меню с этим событием:

private void createMenuItem_Click(object sender, EventArgs e)
    {
        canvas.Layer.RemoveAllChildren();
        canvas.Controls.Clear();
        createDock();
    }

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

Мой таймер выглядит так:

private void transfer_timer()
 {
  System.Timers.Timer Clock = new System.Timers.Timer();
  Clock.Elapsed += new ElapsedEventHandler(createMenuItem_Click); 
  Clock.Interval = timer_interval;
  Clock.Start();
 }

Когда я делаю это, получаю сообщение об ошибке:

createDock - недопустимая операция между потоками: доступ к элементу управления '' осуществляется из потока, отличного от потока, в котором он был создан.

Что я делаю не так?

Ответы [ 5 ]

3 голосов
/ 29 июня 2009

Не делай этого. :) Фактор это больше похоже на это ...

private void createMenuItem_Click(object sender, EventArgs e)
{
  DoCanvasWork(); // pick a good name :)        
}

private void transfer_timer() {
  System.Timers.Timer Clock = new System.Timers.Timer();
  Clock.Elapsed += new ElapsedEventHandler(Clock_Tick);
  Clock.Interval = timer_interval;  Clock.Start(); 
}

private void Clock_Tick( object sender, EventArgs e )
{
  BeginInvoke( new MethodInvoker(DoCanvasWork) );
}

private void DoCanvasWork()
{
  canvas.Layer.RemoveAllChildren();
  canvas.Controls.Clear();
  createDock();
}

Это даст вам гораздо более понятный и гораздо более понятный код. Ваш таймер не выбирает меню, он выполняет ту же работу, что и при выборе меню.

За комментарий: Пожалуйста. Рад помочь! Вот хороший учебник по межпоточному маршалингу (краткое чтение, хорошие примеры). Но в основном BeginInvoke принимает делегата ( MethodInvoker ) и выполняет его асинхронно в потоке, в котором был создан элемент управления. В этом случае это неблокирующее, запускающее и забывающее сообщение между потоками (т.е. я не жду возврата и не вызываю EndInvoke для получения возврата). Если вы действительно хотите углубиться в это, Книга Криса Селлса по Winforms - отличный ресурс.

3 голосов
/ 29 июня 2009

Элементы пользовательского интерфейса имеют сходство потоков. Как правило, их методы можно вызывать только из созданного потока.

Вы можете использовать метод Invoke в элементе управления для выполнения многопоточного вызова. Invoke выполнит маршалинг вызова и выполнит его в потоке пользовательского интерфейса.

2 голосов
/ 29 июня 2009

Это потому, что System.Timers.Timer использует другой поток, и вы не можете манипулировать GUI из другого потока.

Самое простое решение - использовать вместо него System.Windows.Forms.Timer.

1 голос
/ 29 июня 2009

Поскольку сообщение об ошибке, которое вы получили, пытается объяснить, что созданный вами объект Timer использует другой поток для выполнения обратного вызова. Windows.Forms (или Win32 в этом отношении) не могут справиться с этим, это объясняется более подробно здесь . Один из предложенных вариантов - использовать `System.Windows.Forms.Timer. Или используйте шаблон Control.InvokeRequired, Control.Invoke, как описано в приведенной ссылке.

0 голосов
/ 29 июня 2009

Вам нужно использовать System.Windows.Forms.Timer. Он всегда будет запускать свои события в потоке пользовательского интерфейса, тогда как System.Timers.Timer - нет, вызывая исключение.

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