Setup:
Win10 .NET 4.7.1/VS2017 .NET 4.5/ C#
Level:
Beginner/Intermediate/new to threading
Objective:
1: A selenium web automation class that is triggered by a timer class so that the web automation class can exchange data with a javascript site at specific times.
2: Should be possible to migrate solution from WebForms to .NET library (dll).
Problem:
Step 1. Timer class sends time event to method in Web class to login to internet site = working.
Step 2. Web automation class (WinForms/GUI) tries to retrieve data from the method that is triggered by timer class event = Exception: "Calling thread cannot access this object because a different thread owns it." (as translated from swe).
I admit I´m confused by the terminology in the area of threading that is new to me. Also, I understand some multithreading techniques are only valid for WinForms. Since my objective is to migrate the solution to a dll these are not an option for me. I´ve played around with Invoke(), but as I understand it´s limited to use in WinForms. Guidance is highly appreciated!
WEB AUTOMATION CLASS:
private EdgeDriver driver;
private SeleniumHelper helper;
private WebAutomationTimer timer;
private double account;
public double Account { get => this.account; set => this.account = value; }
public Form1()
{
InitializeComponent();
timer = new WebAutomationTimer(02, 36, 00, 02, 38, 00);
timer.OnLoginTime += Timer_OnLoginTime;
timer.OnLogoutTime += Timer_OnLogoutTime;
}
private void Timer_OnLoginTime()
{
Login();
}
private void Timer_OnLogoutTime()
{
Logout();
}
public bool Login()
{
try
{
// working login code
UpdateLabels();
}
catch (Exception e)
{
}
}
private void UpdateLabels()
{
// EXCEPTION !!!
lblAccount.Text = GetAccount();
// EXCEPTION !!!
}
TIMER CLASS:
class WebAutomationTimer
{
public event TimerEvent OnLoginTime;
public event TimerEvent OnLogoutTime;
//public event TimerEvent OnSecond;
private System.Timers.Timer timer;
private DateTime now;
private int loginHour;
private int loginMin;
private int loginSec;
private int logoutHour;
private int logoutMin;
private int logoutSec;
public WebAutomationTimer(int loginHour, int loginMin, int loginSec, int logoutHour, int logoutMin, int logoutSec)
{
timer = new System.Timers.Timer();
timer.Interval = 1000; // 1 sec
timer.Elapsed += Timer_Elapsed;
timer.Start();
this.loginHour = loginHour;
this.loginMin = loginMin;
this.loginSec = loginSec;
this.logoutHour = logoutHour;
this.logoutMin = logoutMin;
this.logoutSec = logoutSec;
}
// Each second event
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
now = DateTime.Now;
//OnSecond();
//login
if (now.Hour == loginHour && now.Minute == loginMin && now.Second == loginSec)
OnLoginTime();
//logout
if (now.Hour == logoutHour && now.Minute == logoutMin && now.Second == logoutSec)
OnLogoutTime();
}
}
}
When you want to update View's control from another Thread it must show you error. Because it is using by UI Thread. In this case you have to use SynchronizationContext class or you can send Delegate to the App.Current.Dispatcher.BeginInvoke(delegate must be here);
SynchronizationContext _context = SynchronizationContext.Current;
private void UpdateLabels()
{
_context.Post(x=>
{
lblAccount.Text = AccountBalance.ToString();
},null),
//...
}
Alternative of SynchronizationContext :
private void UpdateLabels()
{
var action = new Action(() =>
{
lblAccount.Text = AccountBalance.ToString();
});
App.Current.Dispatcher.BeginInvoke(action);
//...
}
Both of them are same.
UI thread adapted for keyboard event and mouse event.
When you App.Current.Dispatcher.BeginInvoke(delegate) you say to the UI Thread that
"execute this too".
In addition you can suppose UI Thread like this
while(!thisApplication.Ended)
{
wait for something to appear in message queue
Got something : what kind of this message?
Keyboard/Mouse message --> fire event handler
User BeginInvoke message --> execute delegate
User Invoke message --> execute delegate & post result
}
this error is beacuse of change lable text beacuse lable is in another thread you can use this code
lblAccount.Invoke(new EventHandler((s, ee) => { lblAccount.Text = AccountBalance.ToString(); }));
This solution is probably only valid in my case. OP can delete this question if it´s believed to be a duplicate.
The first objective with was an easy to develop/run/debug situation with a GUI. Setting properties causes no cross thread exception. Showing the properties in a MessageBox.Show() causes no exception either. Hence no cross thread issues to dodge in the development/GUI stage.
The second objective was to migrate to a dll, hence no need to interfere with a GUI thread.
/Thanks anyway
Related
Pretty much I am trying to a make a stimulation of a larger app but as for now this will do to test things out so I tried to make it as dynamic(real world) as possible. So I have a class called Event which only has fields getters and setters methods, this is the class i want to make instances of objects from the backgroundworker. I have looked at some generic examples but they do not seem to be of great help because they are all based on a GUI app, mine is a console app.
Anyway as soon as the class Events is called from the main class(assuming the user provided the correct input) one event is created by default
class Events
{
BackgroundWorker bw = new BackgroundWorker();
private Event newEvent;
private List<Event> events = new List<Event>();
private int listIndex = 0;
public Events()
{
generateEvent(); //generate first event as soon as user initiates
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_doWork);
bw.RunWorkerAsync();
}
private void bw_doWork(object sender, DoWorkEventArgs e)
{
int sleepTime = newEvent.random.Next(1000,5000); //events randomly created between 1 to 5 seconds
BackgroundWorker worker = sender as BackgroundWorker;
while (listIndex <= 15)
{
generateEvent();
System.Threading.Thread.Sleep(sleepTime);
}
}
private void generateEvent()
{
newEvent = new Event();
this.addEvent(newEvent);
}
private void addEvent(Event e){
//check uniqueness and reassign value if necessary then add to the list
e.setIdentifier(checkUniqueness(e.getIdentifier()));
e.setX(checkUniqueness(e.getX()));
e.setY(checkUniqueness(e.getY()));
events.Add(newEvent);
listIndex++;
}
private int checkUniqueness(int num){
foreach(Event eve in events){
if ((num == eve.getIdentifier()) || //event identifier must be unique
(num == eve.getX() && num == eve.getY())) //event x,y locations must hold one event
{
return checkUniqueness(num = newEvent.random.Next());//generate a new number for identifier
}
}
return num;
}
public List<Event> getEvents()
{
return events;
}
public int getIndex()
{
return listIndex;
}
}
however the backgroundworker class doesnt generate more events as the app is running which is what I need help with because I spent much time on it but I cant seem to get it done. Also when the events are created from the backgroundworker I want to report it(basically just add it to the List and call a method from the main class to update the number of events available) which again I dont know how to do because all the examples are based on GUIs.
Any help much appreciated unless backgroundWorker does not work on console applicatons?
Thanks in advance.
i am trying to use a third party telnet library "active expert" for a basic telnet session.
in my UI code behind i have something like
private async void Button_Click(object sender, RoutedEventArgs e)
{
var ts = new TelnetService();
await ts.DoConnect(node);
}
and my TelnetService looks like this
public class TelnetService
{
private Tcp objSocket = new Tcp();
private NwConstants objConstants = new NwConstants();
public string Responses { get; set; }
private Timer timer1 = new Timer();
public TelnetService()
{
timer1.Elapsed += timer1_Elapsed;
timer1.Interval = 100;
timer1.Start();
}
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
public Task DoConnect(Node node)
{
return Task.Factory.StartNew(() =>
{
objSocket.Protocol = objConstants.nwSOCKET_PROTOCOL_TELNET;
objSocket.Connect(node.IP, 23);
while (true)
{
if ((Responses == null) || (!Responses.Contains(node.WaitString))) continue;
//do something
Responses = "";
break;
}
});
}
}
there are two important pieces of functionalities.
First in the timer1_Elapsed function which is process that will keeps on ruining and checks if there is data on socket, and if there is, it will append it to a string "Response". and i am using "timer" for it.
Second in the DoConnect function which will check the"Response" string for a certain input. for this i am using async await and Task.
in a nutshell first one accumulating the Response and Second one checking the Response.
Problem is that it looks like the timer code in general and
objSocket.ReceiveString()
line specifically is causing the UI thread to halt for several seconds. which means after clicking the button i cannot move my main form on the screen however the code is running in a separate thread.
i have tried using pure Thread for this but it didn't helped either.
update
instead of timer i am using a method AccumulateResponse
public static void AccumulateResponse()
{
while (true)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
}
and calling it like
var t = new Task(TelnetService.AccumulateResponse);
t.Start();
await TelnetService.DoConnect(node);
still no luck
The DoConnect isn't your problem. It is your Timer Elapsed Event handler.
The timer elapsed event is NOT asynchronous. Only the DoConnect is.
If there is no asynchronous version of ReceiveString() from your third party lib, then use Task.Run there as well inside of an async timer1_elapsed method.
I am completely lost in what is really causing the problem. So rather trying to explain the problem, I might as well as get straight to the code with the problem. Here is the layout of my program:
private void connection_OnMessage(object sender, agsXMPP.protocol.client.Message msg)
{
if (!string.IsNullOrEmpty(msg.Body) && ((msg.XDelay != null && msg.XDelay.Stamp.Date == DateTime.Today) || msg.XDelay == null))
{
agsXMPP.Jid JID = new Jid(msg.From.Bare);
int rowIndex = chatLog.Rows.Add();
chatLog.Rows[rowIndex].Cells["chatNameColumn"].Value = JID.User;
chatLog.Rows[rowIndex].Cells["chatMessageColumn"].Value = msg.Body;
//Begin line of the problem
if (IncomingMessage != null)
IncomingMessage(this, JID.User, msg.Body);
//End of the problem
}
}
The above code snippet is of class A. After starting up the program, this class makes the connection to the server. Right after being connected, this code snippet is rapidly fired about 20 times, once per line of message. (There are already about 20 lines of message in the chat log.) Since only one message makes it through the if condition, the lines commented with the problem is only run once. Those lines fire the code snippet below of class B.
(Around the time class A is firing, I have another class like A that fires the similar event to be handled by class B the same way, which will be handled by class C.)
private void newSource_IncomingMessage(IChatSource sender, string user, string message)
{
UpdatedMessageEventHandler temp = UpdatedMessage;
if (temp != null)
temp(sender, user, message);
}
The above code snippet of class B fires the code snippet below of class C.
private void chatManager_UpdatedMessage(IChatSource source, string user, string message)
{
if (!source.Muted)
{
updateMessage(source, user, message);
}
}
delegate void UpdateMessageCallback(IChatSource source, string user, string message);
private void updateMessage(IChatSource source, string user, string message)
{
if (allDataGridView.InvokeRequired)
{
UpdateMessageCallback d = new UpdateMessageCallback(updateMessage);
Invoke(d, new object[] { source, user, message });
}
else
{
int row = allDataGridView.Rows.Add();
allDataGridView.Rows[row].DefaultCellStyle.ForeColor = source.TextColor;
allDataGridView.Rows[row].Cells["NameColumn"].Value = user;
allDataGridView.Rows[row].Cells["MessageColumn"].Value = message;
if (!MenuItem.Checked)
{
MenuItem.Checked = true;
Show();
}
}
}
Here is what I tried to do to fix the problem, but the code is removed already:
I tried adding lock to certain codes.
I tried to put the certain codes on a separate thread and have them run.
Here is what happened:
When I run the program, the UI thread seems to be blocked. In other words, class C doesn't get painted. Sometimes, the form doesn't even appear.
A few times, it complaint about a strange error "An error occurred invoking the method. The destination thread no longer exists."
If I commented out the problem lines, everything work fine, but here is the strange part. If I create a timer object in class A and have it fired the event the same way, it works fine.
While line stepping in debug mode, I sometimes got it work fine, but majority of the time, it fails.
For a few times, I run into InvalidOperationException with the message, "Control accessed from a thread other than the thread it was created on." even though I did make it thread safe.
In conclusion, I don't know what is causing the UI thread to be blocked. Any pointer or what I might do wrong?
The problem is that you're calling methods crossthreading. This can lead to deadlocks.
You could solve this, adding the messages on a concurrent queue and on a timer (gui thread) checking the queue and adding the messages to controls.
This is not a complete solution, but a method to prevent crossthread method invoking
Like: (PSEUDO) (wrote online on the site)
// dataholder
public class ChatMsg
{
public string User {get;set;}
public string Message {get;set;}
}
// message store
private List<ChatMsg> _messages = new List<ChatMsg>();
// timer
private Timer _timer;
// callback for you chatapi?? (like you wrote)
private void newSource_IncomingMessage(IChatSource sender, string user, string message)
{
UpdatedMessageEventHandler temp = UpdatedMessage;
// lock the store
lock(_messages)
_messages.Add(new ChatMsg { User = user, Message = message });
}
// constructor
public Form1()
{
// create the check timer.
_timer = new Timer();
_timer.Interval = 100;
_timer.Tick += Timer_Tick;
_timer.Start();
}
// timer method
private void Timer_Tick(object sender, EventArgs e)
{
// copy of the queue
ChatMsg[] msgs;
// lock the store and 'move' the messages
lock(_messages)
{
msgs = _messages.ToArray();
_messages.Clear();
}
if(msgs.Length == 0)
return;
// add them to the controls
foreach(var msg in msgs)
{
// add the message to the gui controls... (copied from your question)
int row = allDataGridView.Rows.Add();
allDataGridView.Rows[row].DefaultCellStyle.ForeColor = source.TextColor;
allDataGridView.Rows[row].Cells["NameColumn"].Value = user;
allDataGridView.Rows[row].Cells["MessageColumn"].Value = message;
}
}
Something like that..
I have an UI, a custom class, and a thread. I want to run the custom class completely in a separate thread. Is there a clean way of doing this?
For example. On the MainForm below, when UI calls _threadOneClass.Sleep, I need the UI to go to the spawned ThreadOne and invoke the Sleep method in ThreadOne, not in the main thread.
Basically, all method calls in MyClass need to be executed in ThreadOne, not in main thread. It is like, the MyClass runs on its own "process", while still visible to be called from MainForm.
The MainForm has 3 buttons, and 1 textbox for logging.
I was thinking of deriving the Thread class, but it is sealed. So deriving is definitely a wrong way per Microsoft.
Help dear experts?
Here is the output (MainThread ID=10, ThreadOne ID=11)
MyClass instantiated
Starting ThreadOne
11-Run.start
Sleeping ThreadOne
10-Run.sleep for 3000 'Need this to run on ThreadID 11
10-Run.woke up 'Need this to run on ThreadID 11
Stopping ThreadOne
11-Run.done
Here is how the code look like.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Thread _threadOneThread;
private MyClass _threadOneClass;
private void btnThreadOneCreate_Click(object sender, EventArgs e)
{
_threadOneClass = new MyClass(this);
_threadOneThread = new Thread(new ThreadStart(_threadOneClass.Run));
_threadOneThread.Start();
}
private void btnThreadOneStop_Click(object sender, EventArgs e)
{
_threadOneClass.IsRunning = false;
}
private void btnThreadOneSleep_Click(object sender, EventArgs e)
{
_threadOneClass.Sleep(3000);
}
public void Log(string txt)
{
MainForm.SetText(txtLog, txt);
}
internal static void SetText(Control ctl, string val)
{
if (ctl.InvokeRequired)
ctl.Invoke((MethodInvoker)delegate() { ctl.Text += Environment.NewLine + val; });
else
ctl.Text += Environment.NewLine + val;
}
}
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning) { }
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
public void Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}
Threads allow you to run heavy operations while you continue doing other things. In the case of user interfaces (your scenario), asynchronous behavior is almost always necessary as blocking the UI thread will cause to be unresponsive to the user and just isn't an option.
Luckily, the folks at Microsoft has made it extremely easy to write the same code, but in an asynchronous manner. I usually use Tasks because I like the control you get over the operation as well as the ContinueWith() lets you control what you do with the result should you need to propagate data back to the calling thread. If you prefer to use threads, ThreadPool.QueueUserWorkItem is just as easy.
Any operation you do not want to block the UI thread wrap it like this,
Task.Factory.StartNew(() => Object.PerformOperation());
or
ThreadPool.QueueUserWorkItem(new WaitCallback((x) => Object.PeroformOperation()));
I find this allows me to write the same exact code, but without blocking the UI thread. If you have several statements to execute you can use a block as well.
Task.Factory.StartNew(() =>
{
// do something
// do more stuff
// done
}).ContinueWith((completedTask) =>
{
// if you were computing a value with the task
// you can now do something with it
// this is like a callback method, but defined inline
// use ui's dispatcher if you need to interact with ui compontents
UI.Label.Dispatcher.Invoke(new Action(() =>
UI.Item.Label.Text = completedTask.Result;
}
The upcoming async features that are being released in the next .net version actually streamline this even more! But since it uses tasks you will still want to get comfortable with using them.
// this will begin the operation, then return control back to the ui so it does not hang.
var result = await Object.PerformLongTask();
// once the long task is completed then it continues and you can use the result
UI.Item.Label = result;
To give a real example, here is some code from an FTP client I wrote which has has a WPF front end. When the start button is clicked the ftp transfer is launched in it's own task, then a while loop which updates the interface every half a second is launched in a task, so neither interferes with the interface thread. Again it's the same code, just wrapped in lambada's.
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
ftp.Mirror(#"C:\LocalFolder", "/RemoteFolder", 10));
Task.Factory.StartNew(() =>
{
while (true)
{
lbPercentSuccess.Dispatcher.Invoke(new Action(() =>
{
lbPercentSuccess.Content = ftp.FtpProgress.SuccessPercentage;
lbPercentError.Content = ftp.FtpProgress.ErrorPercentage;
lbPercentTotal.Content = ftp.FtpProgress.TotalPercentage;
lbDuration.Content = ftp.FtpProgress.Duration;
}));
Thread.Sleep(500);
}
});
}
This is not possible to my knowledge. You can only run and invoke individual methods or queue them on separate threads when need be. Setting an actual object on a separate thread defeats your purpose. This is because you only going to harness the benefits of multithreading when invoking a method on a separate thread not an object.
then reassign the del to MethodTwo... and so on. This is made easier if you conform to a method signature.
Possible solution:
Thread threadTest = new Thread(new ThreadStart(MethodOne));
threadTest = new Thread(new ThreadStart(MethodTwo));
threadTest.Start();
Or
Action del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(null, null);
Func<int,int> del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(11,null, null);
int value = del.EndInvoke(result);
It's not simple, but have a look at this. It's a nice explination of how to use cross thread communication.
http://www.codeproject.com/KB/cs/delegatequeue.aspx
So far, this is what I found (from iPhone development). The Run loop acts like a spine that invokes various methods. It is implemented like the following:
A more elegant solution is welcomed.
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning)
{
if (_runSleepMilliSeconds != null)
{
_Sleep(_runSleepMilliSeconds ?? 3000);
_runSleepMilliSeconds = null;
}
}
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
private int? _runSleepMilliSeconds = null;
public void Sleep(int milliseconds)
{
_runSleepMilliSeconds = milliseconds;
}
private void _Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}
I need to be able to delay the event handlers for some controls (like a button) to be fired for example after 1 sec of the actual event (click event for example) .. is this possible by the .net framework ?
I use a timer and call my code from the timer's tick event as below but I am not sure if this is the best approach !
void onButtonClick( ..)
{
timer1.Enabled = true;
}
void onTimerTick( ..)
{
timer.Enabled = false;
CallMyCodeNow();
}
Perhaps you could make a method that creates the timer?
void onButtonClick(object sender, EventArgs e)
{
Delay(1000, (o,a) => MessageBox.Show("Test"));
}
static void Delay(int ms, EventHandler action)
{
var tmp = new Timer {Interval = ms};
tmp.Tick += new EventHandler((o, e) => tmp.Enabled = false);
tmp.Tick += action;
tmp.Enabled = true;
}
Before coming to your question, just having read the summary bit from the main questions page, a timer was exactly what I was going to suggest.
This looks pretty clean to me. It means you can easily "cancel" the delayed event if you need to, by disabling the timer again, for example. It also does everything within the UI thread (but without reentrancy), which makes life a bit simpler than other alternatives might be.
If you're only doing this for one control, the timer approach will work fine. A more robust approach supporting multiple controls and types of events looks something like this:
class Event
{
public DateTime StartTime { get; set; }
public Action Method { get; set; }
public Event(Action method)
{
Method = method;
StartTime = DateTime.Now + TimeSpan.FromSeconds(1);
}
}
Maintain a Queue<Event> in your form and have UI events that need to be delayed add them to the queue, e.g.:
void onButtonClick( ..)
{
EventQueue.Enqueue(new Event(MethodToCall));
}
Make your timer tick 10 times a second or so, and have its Tick event handler look like this:
void onTimerTick()
{
if (EventQueue.Any() && EventQueue.First().StartTime >= DateTime.Now)
{
Event e = EventQueue.Dequeue();
e.Method;
}
}
My solution uses System.Threading.Timer:
public static class ExecuteWithDelay
{
class TimerState
{
public Timer Timer;
}
public static Timer Do(Action action, int dueTime)
{
var state = new TimerState();
state.Timer = new Timer(o =>
{
action();
lock (o) // The locking should prevent the timer callback from trying to free the timer prior to the Timer field having been set.
{
((TimerState)o).Timer.Dispose();
}
}, state, dueTime, -1);
return state.Timer;
}
}
For those limited to .NET 2.0, here is another take on Bengt's helpful solution:
/// <summary>
/// Executes the specified method in a delayed context by utilizing
/// a temporary timer.
/// </summary>
/// <param name="millisecondsToDelay">The milliseconds to delay.</param>
/// <param name="methodToExecute">The method to execute.</param>
public static void DelayedExecute(int millisecondsToDelay, MethodInvoker methodToExecute)
{
Timer timer = new Timer();
timer.Interval = millisecondsToDelay;
timer.Tick += delegate
{
// This will be executed on a single (UI) thread, so lock is not necessary
// but multiple ticks may have been queued, so check for enabled.
if (timer.Enabled)
{
timer.Stop();
methodToExecute.Invoke();
timer.Dispose();
}
};
timer.Start();
}
Using Reactive Extensions:
First, install the nuget package
PM> Install-Package Rx-Main
Code:
private void CallMyCodeNow()
{
label1.Text = "reactivated!";
}
private void Form1_Load(object sender, EventArgs e)
{
var o = Observable.FromEventPattern<EventHandler, EventArgs>(
handler => button1.Click += handler
, handler => button1.Click -= handler
)
.Delay(TimeSpan.FromSeconds(5))
.ObserveOn(SynchronizationContext.Current) // ensure event fires on UI thread
.Subscribe(
ev => CallMyCodeNow()
, ex => MessageBox.Show(ex.Message)
);
}
If you're looking for a more fancy solution, you may want to take a look at my Reactive LINQ project. The link doesn't show how to solve the particular problem you're having, but it should be possible to solve in quite an elegant style using the technique described there (in the whole 4-article series).
You can use:
Thread.Sleep(1000);
That will pause the current Thread for one second. So I would do that...
Best Regards!