The problem I don't know the answer to...
So on app level I want to do something when PC wakes up from sleep, so on my class ctor I did this:
public MyClass()
{
SystemEvents.PowerModeChanged += OnPowerChange;
}
OnPowerChange method looks like this:
private async void OnPowerChange(object sender, PowerModeChangedEventArgs e)
{
Debug.WriteLine(e.Mode);
if (e.Mode == PowerModes.Resume)
//Do something
}
So this event triggers only sometimes... For example when I run my app and go to sleep, when I wake - event fires. But now, when I go to sleep for the second time, after sleep, when I wake up nothing happens... Debug.WriteLine does not show anything, so the event is never fired... What could be the problem? How can I make OnPowerChange event work always?
Related
I have a event which in many case fires many times but I want an event to be completed before the next event is ran.
I am trying to create a cryptocurrency trading bot. The event in question is private void CoinInformation_OnNewTradeEvent(object sender, AggregateTradeEventArgs e)
Since that single event fires multiple times, I always thought it would be executed in a synchronous fashion where when one event is running, the next event wont run until this is completed. I tried putting locks but realize that doesnt work.
private void CoinInformation_OnNewTradeEvent(object sender, AggregateTradeEventArgs e)
{
lock(myObject)
{
try
{
Decimal currentTradePrice = e.Trade.Price;
UpdateSMA(currentTradePrice);
TryBuy(currentTradePrice);
TrySell(currentTradePrice);
TryStopLoss(currentTradePrice);
}
catch
{
return;
}
}
}
Sorry seems like my TryBuy and TrySell were async and I didnt await them thus there were reentries.
TL;DR: Can I make a handler that is attached to many events fire only once, even when I know all of the events will be fired?
I'm trying to listen to a collection of objects, each of which will complete a specific task and then notify the owner that it is completed. To do this I've simply looped over the collection and added an event handler to each object
foreach(var obj in collection)
{
obj.Event += GroupHandler;
}
and that works fine. However since I know the tasks will complete around the same time, and since it really doesn't matter if I queue a bit early I'd like to have a way to ensure that once GroupHandler is raised, it won't be raised again for the current execution set so I could do something like:
private void GroupHandler(object sender, EventArgs e)
{
foreach(var obj in collection)
{
obj.QueueNext();
}
}
Ideally I'd end up with something like
private void GroupHandler(object sender, EventArgs e)
{
if(GroupHandler.HasRun) return;
foreach(var obj in collection)
{
obj.QueueNext();
}
}
I know that I could use some global bool (or more likely an int to track cycles) but I don't like that as a solution. I'm looking for something a bit nicer than that.
As Gusman said in comments, you can have just one of the objects fire off the event. That way you know it executes only once per event set.
Alternatively, you could set up a Timer, a counter and a flag. Set the flag on the first event execution and then start the timer. As long as the flag is set, ignore the rest of the events. Set your counter to the number of objects you're tracking and decrement the counter as each one fires off its event. When either the timer expires or the counter reaches zero, reset the flag, reset the counter and cancel the timer. This could rapidly get complicated and may have a bunch of corner cases, so if you don't care too much about timing, then the first method is much better. Simplify as much as possible.
I ended up working with what Gusman mentioned in the comments an removed the event handlers. The real key though was finding out where to reattach them. So I ended up passing the handler function in the QueueNext call.
Code looks like this
private void GroupHandler(object sender, EventArgs e)
{
foreach(var obj in collection)
{
obj.Event -= GroupHandler;
}
foreach(var obj in collection)
{
obj.QueueNext(GroupHandler);
}
}
and QueueNext looks like
public void QueueNext(EventHandler nextHandler)
{
this.Event += nextHandler
QueueNext();
}
this way the event is only called once, and will be called for each set of execution.
After asking this question, I am wondering if it is possible to wait for an event to be fired, and then get the event data and return part of it. Sort of like this:
private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();
Please make sure whatever solution you provide returns the value directly rather than getting it from something else. I'm asking if the method above is available in some way. I know about Auto/ManuelResetEvent, but I don't know that they return the value directly like I did above.
Update: I declared an event using MyEventHandler (which contains a Message field). I have a method in another thread called ReadLine waiting for the event to fire. When the event fires the WaitForValue method (part of the event handling scene) returns the event args, which contains the message. The message is then returned by ReadLine to whatever had called it.
The accepted answer to that question I asked was what I did, but it just doesn't feel quite right. It almost feels like something could happen to the data between the ManuelResetEvent firing and the program retrieving the data and returning it.
Update: The main problem with the Auto/ManualResetEvent is that it is too vulnerable. A thread could wait for the event, and then not give enough time for anyone else to get it before changing it to something else. Is there a way to use locks or something else? Maybe using get and set statements.
If the current method is async then you can use TaskCompletionSource. Create a field that the event handler and the current method can access.
TaskCompletionSource<bool> tcs = null;
private async void Button_Click(object sender, RoutedEventArgs e)
{
tcs = new TaskCompletionSource<bool>();
await tcs.Task;
WelcomeTitle.Text = "Finished work";
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
tcs?.TrySetResult(true);
}
This example uses a form that has a textblock named WelcomeTitle and two buttons. When the first button is clicked it starts the click event but stops at the await line. When the second button is clicked the task is completed and the WelcomeTitle text is updated. If you want to timeout as well then change
await tcs.Task;
to
await Task.WhenAny(tcs.Task, Task.Delay(25000));
if (tcs.Task.IsCompleted)
WelcomeTitle.Text = "Task Completed";
else
WelcomeTitle.Text = "Task Timed Out";
You can use ManualResetEvent. Reset the event before you fire secondary thread and then use the WaitOne() method to block the current thread. You can then have secondary thread set the ManualResetEvent which would cause the main thread to continue. Something like this:
ManualResetEvent oSignalEvent = new ManualResetEvent(false);
void SecondThread(){
//DoStuff
oSignalEvent.Set();
}
void Main(){
//DoStuff
//Call second thread
System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
oSecondThread.Start();
oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
oSignalEvent.Reset();
//Do more stuff
}
A very easy kind of event you can wait for is the ManualResetEvent, and even better, the ManualResetEventSlim.
They have a WaitOne() method that does exactly that. You can wait forever, or set a timeout, or a "cancellation token" which is a way for you to decide to stop waiting for the event (if you want to cancel your work, or your app is asked to exit).
You fire them calling Set().
Here is the doc.
If you're happy to use the Microsoft Reactive Extensions, then this can work nicely:
public class Foo
{
public delegate void MyEventHandler(object source, MessageEventArgs args);
public event MyEventHandler _event;
public string ReadLine()
{
return Observable
.FromEventPattern<MyEventHandler, MessageEventArgs>(
h => this._event += h,
h => this._event -= h)
.Select(ep => ep.EventArgs.Message)
.First();
}
public void SendLine(string message)
{
_event(this, new MessageEventArgs() { Message = message });
}
}
public class MessageEventArgs : EventArgs
{
public string Message;
}
I can use it like this:
var foo = new Foo();
ThreadPoolScheduler.Instance
.Schedule(
TimeSpan.FromSeconds(5.0),
() => foo.SendLine("Bar!"));
var resp = foo.ReadLine();
Console.WriteLine(resp);
I needed to call the SendLine message on a different thread to avoid locking, but this code shows that it works as expected.
Try it : e.Handled = true; It works to prevent KeyEventArgs, for example.
Here is my situation :
I have a ThreadManager launching BackgroundWorkers; I subscribe to the doWork event to Log stuff in it. I also subscribo to the doWork event in the BackgroundWorker itself to process stuff.
Well, The first subscription raises the event way after the second one was raised.
class ThreadManager
{
//(...)
for (int i = 0; i<100; i++)
{
myWorker wk = new myWorker();
wk.DoWork += new DoWorkEventHandler(wk_DoWork);
}
//(...)
public void wk_DoWork(object sender, DoWorkEventArgs e)
{
Console.Out.Write("PONG");
//(...) Workers Management logic (Pooling, priority, etc.)
}
}
internal class myWorker : : BackgroundWorker
{
//(...)
DoWork += new DoWorkEventHandler(DoMe);
//(...)
void DoMe(object sender, DoWorkEventArgs e)
{
Console.Out.Write("PING");
//(...) Run a 2-3mn file reading process
}
}
For some reason, I am getting all "Pings" in a row, and start getting Pongs only a few minutes after.
Is there something I am missing here ?
EDIT : I do not use "Console" per se, but asynchronous loggers (that was for the example). I have been careful to watch the debug process at the "PONG" line, and it is not hit way after the "PING"s has been launched.
MY SOLUTION :
This is exactly the extra code I was hoping to avoid, but I could'nt cut the pain finally.
So here it is, for those having the same issu and stumbling on this post :
class ThreadManager
{
//(...)
for (int i = 0; i<100; i++)
{
myWorker wk = new myWorker();
wk.StartedEvent += new myWorker.startDelegate(wk_Started);
}
//(...)
public void wk_Started(params-if-needed)
{
Console.Out.Write("PONG");
//(...) Do Stuff
}
}
internal class myWorker : BackgroundWorker
{
public delegate void startDelegate(string ID);
public event startDelegate StartedEvent;
protected override void OnDoWork(DoWorkEventArgs e)
{
StartedEvent(ID); //put whatever parameter suits you or nothing
base.OnDoWork(e);
e.Result = e.Argument;
Console.Out.Write("PING");
//(...) Do Stuff
}
}
You are missing the following:
The subscribers to the DoWork event are not called in parallel but in a serial manner, i.e. first your handler with PING and after that the handler with PONG. So, when the PING handler takes 3 minutes, the PONG handler will be executed three minutes after you called RunWorkerAsync.
DoWork is a normal event, and with multicast, it's a sequential call-chain, and BackgroundWorker does not change that.
In short, it's not typical to hang multiple event handlers off of that event.
So yes, it's perfectly natural, since you specifically mention in your comments that the first event handler runs for 2-3 minutes, then yes, the second event handler will start a few minutes later.
As far as I know, Console.Out.Write is buffered. Try WriteLine.
This might be unrelated, but it's recommended to override OnXXX methods in derived classes rather then subscribe to own events. Thus,
class MyWorker : BackgroundWorker
{
protected override void OnDoWork(...) { .... }
}
And do not forget to call base.OnDoWork().
I want to make my program aware of the computer being put to sleep or waking up from sleep, possibly have an event that is triggered when either of these occur. Is this possible?
You can subscribe to the SystemEvents.PowerModeChanged event.
SystemEvents.PowerModeChanged += OnPowerChange;
void OnPowerChange(Object sender, PowerModeChangedEventArgs e) {
switch ( e.Mode ) {
case PowerModes.Resume:
...
case PowerModes.Suspend:
...
}
}