Reputation: 476
I created a Timer event handler per the code below in a class object.:
public class MyTimerClass
{
private Timer _timeoutTimer;
private void Constructor()
{
_timeoutTimer = new Timer(TimerHandler, null, 0, 1000);
}
private void TimerHandler()
{
if (Something)
LogMessage(LogLevel.Error, "Timeout Waiting...");
}
}
I created a LogMessageHandler event with delegate in the same class object to handle the timer event, and other log events:
public delegate void LogMessageHandler(LogLevel logLevel, string message);
public event LogMessageHandler OnLogMessage;
private void LogMessage(LogLevel logLevel, string message)
{
if (OnLogMessage != null)
OnLogMessage(logLevel, message);
}
In another class, I would like to handle the log message derived for the timer. Here is my subscription to the OnLogMessage event and the class that handles the thread:
void InitializeMyTimerClass()
{
try
{
_myTimerClass = new MyTimerClass();
_myTimerClass.OnLogMessage += new LogMessageHandler(UpdateLogMessage);
}
catch (Exception ex)
{
_dialog.ShowException(ex.Message);
}
}
private void UpdateLogMessage(LogLevel newLogLevel, string message)
{
TaskScheduler schedulerForLog = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => TrackResponseMessage.Add(FormatLogLevelToString(newLogLevel) + ": " + message),
CancellationToken.None, TaskCreationOptions.None, schedulerForLog);
}
When I run the code and the timer event occurs, I put a break point where the TaskScheduler is created: TaskScheduler schedulerForLog = TaskScheduler.FromCurrentSynchronizationContext(); The LogLevel and string parameters are passed from MyTimerClass successfully. However, I get a InvalidOperationException when the TaskScheduler attempts to get the current synchronization context. It appears the SynchronizationContext from the timer thread is not acceptable for the TaskScheduler.
Question: Is the timer event passed in a separate thread? What is the best way to handle the timer thread in this case? Can someone provide demo code? ...Thanks!
Upvotes: 0
Views: 1291
Reputation: 2387
If your problem is a cross-thread invalid operation, you can use the Application.Current.Dispatcher to invoke the process you want to run in the main thread of the application to avoid the issue:
private void UpdateLogMessage(LogLevel newLogLevel, string message)
{
Application.Current.Dispatcher.BeginInvoke(new Action(()=>{
TaskScheduler schedulerForLog = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => TrackResponseMessage.Add(FormatLogLevelToString(newLogLevel) + ": " + message),
CancellationToken.None, TaskCreationOptions.None, schedulerForLog);
});
}
If the main thread is not the thread you need then you need to get a hold of the dispatcher for the thread you want and invoke from there.
Upvotes: 2