I am trying to build a clock application in Silverlight.
My application has multiple pages, one for analog, one for digital and one for a timer.
If I want to have a separate class that handles the time-keeping as follows:
private void startTimer()
{
DispatcherTimer myDispatcherTimer = new DispatcherTimer();
myDispatcherTimer.Interval = new TimeSpan(0,0,1);
myDispatcherTimer.Tick += new EventHandler(eachClick);
myDispatcherTimer.Start();
}
How can I get the current page that is displayed so that the method can use that page's event handler?
What is the best way to go about this?
I dont really understand what exactly you're trying to do. "How can I get the current page so that the method can use that page event handler?"
If you have three pages, and you're trying to synchronize the time between all three of them, why dont you create a static Timer class.
I dont know, maybe something like this:
public static class StaticTimer
{
public delegate void Time(DateTime time);
public static event Time Tick = delegate { };
static StaticTimer()
{
DispatcherTimer myDispatcherTimer = new DispatcherTimer();
myDispatcherTimer.Interval = new TimeSpan(0,0,1);
myDispatcherTimer.Tick += (s,e) => Tick(DateTime.Now);
myDispatcherTimer.Start();
}
}
Then, from each page, just subscribe to the Tick event when you create it.
void AnalogPage_OnLoaded( ... )
{
StaticTimer.Tick += someEventHandler;
}
void someEventHandler(DateTime time)
{
if(thisIsCurrentPage)
{
clock.Update(time);
}
}
Related
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
I have an application with a gui and a Rich Text Box where I output what the program is currently doing since data processing can be quite long.
I tried two approaches for that:
1 In the Backgroundworker method I can just call the following code fine:
GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();
Whereas I cannot use Form1.Processchange(); in the helper class due to the non static context
2 Therefore I tried to create my very first eventhandler.
The Idea was that helper.UpdateConsole() would raise an event
public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
OnConsoleUpdate(this, EventArgs.Empty);
}
to which the Backgroundworker listens and then calls Processchange from its context
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks();
Helper helper = new Helper();
helper.OnConsoleUpdate += Processchange;
task.DoSomeStuffHere()
}
public void Processchange(object sender=null, EventArgs e=null)
{
//MessageBox.Show(GlobalVar.backgroundWorkerAppendText);
GlobalVar.next = false;
backgroundWorker1.ReportProgress(1);
while (GlobalVar.next == false)
{
helper.TimeBreaker(100,"ms");
}
}
Unfortunately this was was not successful. As soon as rising the Event I get the errormessage System.NullReferenceException which -after googling- leads me to the conclusion that there is no listerner attached to the event eventhouh I attached it in the Backgroundworker Do work.
Edit: the OnConsoleUpdate() == null as shown on the screenshot below
event = null
The helper is in another class file "helpers" which might be important for a solution.
i hope you guys can help me out.
Welcome to SO!
A few things immediately jump to mind.
First, let's get the event issue out of the way. You've got the correct approach - you need an event and method to call it, but that method should check if the event is null.
Basically, do this:
public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}
The above makes use of ?, a null-condition operator. You can read more about it on this MSDN page.
Second thing... it's unclear what your background worker actually IS. It sounds like it's some kind of custom class you crated? The reason it's important is because .NET actually has a BackgroundWorker class used for running operations... well, in the background. It also has an OnProgressChanged event which you can hook up to which could be used to update the UI (just remember to set the WorkerReportsProgress property to true). And to use the BackgroundWorker mentioned above, you shouldn't need to create any events of your own.
Here's how you can use the standard .NET BackgroundWorker:
System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
void StartBackgroundTask()
{
worker.DoWork += worker_DoWork;
//if it's possible to display progress, use this
worker.WorkerReportsProgress = true;
worker.ProgressChanged += worker_ProgressChanged;
//what to do when the method finishes?
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
//start!
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
//perform any "finalization" operations, like re-enable disabled buttons
//display the result using the data in e.Result
//this code will be running in the UI thread
}
//example of a container class to pass more data in the ReportProgress event
public class ProgressData
{
public string OperationDescription { get; set; }
public int CurrentResult { get; set; }
//feel free to add more stuff here
}
void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
//display the progress using e.ProgressPercentage or e.UserState
//this code will be running in the UI thread
//UserState can be ANYTHING:
//var data = (ProgressData)e.UserState;
}
void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
//this code will NOT be running in the UI thread!
//you should NOT call the UI thread from this method
int result = 1;
//perform calculations
for (var i = 1; i <= 10; i++)
{
worker.ReportProgress(i, new ProgressData(){ OperationDescription = "CustomState passed as second, optional parameter", CurrentResult = result });
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
result *= i;
}
e.Result = result;
}
Now, the thing about the BackgroundWorker class is that it is rather old, and with current .NET versions you can use the async / await keywords to easily handle background operations and UI updates, but this probably is going outside the bounds of this question. That said, the existence of async / await doesn't invalidate the use of BackgroundWorker which is pretty simple in its usage.
There's one more worrisome thing in your code.
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks(); //<- you create a task
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper event
task.DoSomeStuffHere(); // <- you do stuff with the task... but the task doesn't know about your helper above! Does `StandardTasks` use `Helper`? If so, how?
}
Do note that events, unless made static, aren't global. So hooking up to an event in one instance of a class won't cause another instance of that class to "fire" that event. It seems one way to fix your issues would be to make the StandardTasks class take Helper as one of the constructor parameters, so the code would look like this:
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper class event to actually do something
StandardTasks task = new StandardTasks(helper); //<- you create a task which will use the helper with the hooked up event above
At the moment I am in the process of building a custom button handler (I needed to integrate the kinect into the button system which also used a mouse) then I got to a horrible thing called Event Handling.. at least an hour yelling at my pc :P. I was wondering, before I go and spend a while changing my system to allow for my new want, which is to have multiple events per handler, I was wondering, is the way I'm going to try work (I would just try, but I'm getting off for the night, so my hope is that I can save some time when I boot the computer up tomorrow and not attempt if my system isn't designed for it)
Also, ive seen a getInvoc list or somthing like that before when I was coding.. Would I add multiple delegates onto it then get that list and itterate over it?
On previous examples I had seen where people used:
public event EventHandler myEventHandler;
I had to use:
private Dictionary<BtnEvent, Delegate> m_events;
and then they did the following to add a handler (their way, not mine):
myObj.myEventHandler += delegate(object sender, EventArgs ea)
{
//do stuff on event
};
first.. If they ran this twice, once with funcA and second with funcb would it run both? or just one?
second, if I applied that logic of += to a Delegate would it work? (I had to use Delegate as I was storing the handlers inside of a dictionary, this allowed for logical access to handlers through use of an enum)
(my code)
private Dictionary<BtnEvent, Delegate> m_events;
//....
m_events = new Dictionary<BtnEvent, Delegate>(6);
m_events.Add(BtnEvent.CLICK_ENTER, null);
m_events.Add(BtnEvent.CLICK_LEAVE, null);
m_events.Add(BtnEvent.CLICK_STAY, null);
m_events.Add(BtnEvent.HOVER_ENTER, null);
m_events.Add(BtnEvent.HOVER_LEAVE, null);
m_events.Add(BtnEvent.HOVER_STAY, null);
//....
public bool addHandle(BtnEvent stateToGet, Delegate function)
{
bool success = false;
if(m_events.ContainsKey(stateToGet))
{
m_events[stateToGet] = function;
}
return(success);
}
// CHANGE ABOVE TO:
public bool addHandle(BtnEvent stateToGet, Delegate function)
{
bool success = false;
if(m_events.ContainsKey(stateToGet))
{
m_events[stateToGet] += function;
}
return(success);
}
Will changing m_events[stateToGet] = function; to m_events[stateToGet] += function; allow me to have multiple event handles (functions I passed to addHandle) be called through the following code?
private void ExecuteEvent(BtnEvent currEvent)
{
if(m_events.ContainsKey(currEvent))
{
if(m_events[currEvent] != null)
{
m_events[currEvent].DynamicInvoke(null);
}
}
}
Please see below code which answers your first question:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
funcA();
funcB();
}
private void funcA()
{
button1.Click += new EventHandler(button1_Click);
}
private void funcB()
{
button1.Click += new EventHandler(button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("I am in event handler");
}
}
On clicking the Button, "I am in event handler" message is shown twice which means += operator works in similar way with delegates as it works with integers or strings. It simply adds the function handler to the queue and upon execution of events, calls all the function pointers in queue.
Regarding your second question, I think you wont achieve the expected behavior by changing = to +=. What I understand from your statement is that, you wish to execute multiple events handlers like CLICK_ENTER, CLICK_LEAVE on calling ExecuteEvent() function. However, since you are storing event handlers and their delegates in a Dictionary, changing = to += will only work in the same way as illustrated in above code.
This is a fictional example but I was wandering what happens if the InitialiseTimer function gets called twice. Does the timer elapsed function get triggered twice. Will this change if the functions are made static?
private static void InitialiseTimer()
{
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 400;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
}
public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
}
I was going to use below to prevent this
Has an event handler already been added?
Thanks,
Richard
If you register the event handler twice, it will be invoked twice every time the event is raised.
This won't change if you make TheTimer_Elapsed static, because you'll still hold two references to this static method.
In most cases there's no need to write compicated things like what Blair Conrad posted in the question you linked to. Just don't forget to use -= every time you have += and you'll be safe.
I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{
Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();
Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}
public class Foo
{
private static System.Timers.Timer TheTimer = null;
public static event EventHandler Fired;
public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}
public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}
if you call the method InitialiseTimer twice you will create two Timers each of them will have only one event handler attached but they might elapse both. It's not really about having the method static or not, it's more about the method itself, you could check if TheTimer is null and do the rest only if it's null so you assign it only once.
If event is registered twice you will have two executions.
You can check if event is null, and the problem will be solved.
Static or not, you are recreating the Timer. So you can invoke the InitialiseTimer many, many times without adding more than a single handler. You will end up with many timers though...
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!