How to store any value when event is raised? - c#

I'm trying to measure the time between when I unplug my laptop and battery level reaching 10%.
I've managed to wire up the event so far but I can't figure out where I can store the values of time so that I can do subtraction later.
public class Program
{
public static void Main(string[] args)
{
SystemEvents.PowerModeChanged += OnPowerModeChanged;
Console.ReadLine();
}
public static void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if (SystemInformation.PowerStatus.PowerLineStatus.ToString() == "Offline")
{
}
}
}

In this case I would use a member variable to store the DateTimes that you want to observe.
public class Program
{
private static DateTime startTime;
public static void Main(string[] args)
{
SystemEvents.PowerModeChanged += OnPowerModeChanged;
Console.ReadLine();
}
public static void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if (SystemInformation.PowerStatus.PowerLineStatus.ToString() == "Offline")
{
this.startTime = DateTime.Now();
}
}
}
Using DateTimes also depends on what level of accuracy you want. If you are talking about measuring anything under a few seconds I would recommend using a System.Diagnostics.Stopwatch instead.

Related

C# confused about delegates, publishers and subscribers

Consider the following console program. It has four classes: Program, Attacker, Defender, and Helper. I want to remove the logic from the Defender class and use delegates to call helpers. I've spent some time on this and can't quite get it.
Where do I declare my delegate: in Program or in Defender?
Where do I instantiate my delegate: in Program or in Defender?
Where do I subscribe my delegate: in Program or in Helper?
I could post my attempts but it wouldn't be helpful.
using System;
namespace Delegates19
{
public class Program
{
static void Main(string[] args)
{
Attacker a = new Attacker();
string weapon = "sword";
a.Attack(weapon);
Defender d = new Defender();
d.Help(weapon);
weapon = "spear";
a.Attack(weapon);
d.Help(weapon);
}
}
public class Attacker
{
public void Attack(string s)
{
Console.WriteLine($"Attacker attacks with {s}");
}
}
public class Defender
{
public void Help(string s)
{
Console.WriteLine($"Defender is attacked with {s} and calls for help");
if (s == "sword")
Helper.Knight();
if (s == "spear")
Helper.Bowman();
}
}
public class Helper
{
public static void Knight()
{
Console.WriteLine($"Knight charges Attacker");
}
public static void Bowman()
{
Console.WriteLine($"Bowman shoots Attacker");
}
}
}
I'm really not sure why you would want to do this, but these both work and might give you ideas.
Unless I understand your need for events/delegates I actually prefer your code over these.
Delegates:
public class Defender
{
private static Action SwordAction = Helper.Knight;
private static Action SpearAction = Helper.Bowman;
public void Help(string s)
{
Console.WriteLine($"Defender is attacked with {s} and calls for help");
if (s == "sword")
SwordAction();
if (s == "spear")
SpearAction();
}
}
public static class Helper
{
public static void Knight()
{
Console.WriteLine($"Knight charges Attacker");
}
public static void Bowman()
{
Console.WriteLine($"Bowman shoots Attacker");
}
}
Events:
static void Main(string[] args)
{
using (var d = new Defender())
{
d.GetHelp += StandardDefenseHelp.Defender_GetHelp;
d.Help("sword");
d.Help("spear");
}
}
public class Defender : IDisposable
{
public event EventHandler<string> GetHelp;
private void RaiseGetHelp(string weapon) => GetHelp?.Invoke(this, weapon);
public void Help(string weapon)
{
Console.WriteLine($"Defender is attacked with {weapon} and calls for help");
RaiseGetHelp(weapon);
}
public void Dispose()
{
GetHelp = null;
}
}
public static class StandardDefenseHelp
{
public static void Defender_GetHelp(object sender, string weapon)
{
if (weapon == "sword")
Knight();
if (weapon == "spear")
Bowman();
}
private static void Knight()
{
Console.WriteLine($"Knight charges Attacker");
}
private static void Bowman()
{
Console.WriteLine($"Bowman shoots Attacker");
}
}
Important: events often are the cause of memory leaks, that's why Defender is now disposable.
The above design could be useful if you have multiple "DefenseHelp" types and other things also should happen when a defender needs help that the defender itself needs to know nothing about.
But I'd only do this if it gave some benefit. I believe in the KISS development methodology.

Monitoring processes with while(true) loop

Is it possible to optimise my console application? It uses up to 60% of CPU because of while(true) loop.
The idea is to kill Microsoft managment console (services) process every time it starts up. And to start/stop services - use pswrd and console.
public static void Main(string[] args)
{
Thread consoleInput = new Thread(_consoleInput);
consoleInput.Start();
killProcess();
}
static void _consoleInput(){
getPassword();
sendServiceCommands();
}
static void killProcess(){
while(true){
try{
System.Diagnostics.Process[] myProcs = System.Diagnostics.Process.GetProcessesByName("mmc");
myProcs[0].Kill();
}
catch(Exception e){}
}
}
You need System.Threading.Timer. Something like this:
public class Killer
{
protected const int timerInterval = 1000; // define here interval between ticks
protected Timer timer = new Timer(timerInterval); // creating timer
public Killer()
{
timer.Elapsed += Timer_Elapsed;
}
public void Start()
{
timer.Start();
}
public void Stop()
{
timer.Stop();
}
public void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
System.Diagnostics.Process[] myProcs = System.Diagnostics.Process.GetProcessesByName("mmc");
myProcs[0].Kill();
}
catch {}
}
}
...
public static void Main(string[] args)
{
Killer killer = new Killer();
Thread consoleInput = new Thread(_consoleInput);
_consoleInput.Start();
killer.Start();
...
// whenever you want you may stop your killer
killer.Stop();
}

Timer sequence is messing up

So I am making a Robbery system the timer works perfectly on the first start but on second try it minuses the time 2ice.. meaning the sequence by the timer goes down is 10,9,8,7...... But on the 2nd try the sequence is 10,8,6,4...... on the 3rd try its 10,7,4,1..... Etc meaning on each start the timer sequence increase the decrease time? How is it possible?
public void robberyCountdown(User player)
{
time = 10;
cd.Elapsed += (source, e) => OnTimer(player);
cd.Start();
}
public void OnTimer(User player)
{
cd.Stop();
cd.Elapsed -= (source, e) => OnTimer(player);
}
Save the delegate you create into a private field so you can access it later:
private ElapsedEventHandler _onTimer;
public void robberyCountdown(User player)
{
time = 10;
_onTimer = (source, e) => OnTimer(player)
cd.Elapsed += _onTimer;
cd.Start();
}
public void OnTimer(User player)
{
cd.Stop();
cd.Elapsed -= _onTimer;
}
Of course, this approach assumes that player will be the same for both. A better way is probably to make your delegate just be constant, and use a private field to keep track of which players are being timed.
private HashSet<Player> _timedPlayers = new HashSet<Player>();
public MyClass() // or whatever your constructor is called
{
cd.Elapsed += OnTimer;
}
public void OnTimer(Object source, ElapsedEventArgs e)
{
foreach(var player in _timedPlayers)
{
// ...
}
}
public void robberyCountdown(User player)
{
time = 10;
_timedPlayers.Add(player);
cd.Start();
}
public void OnTimer(User player)
{
cd.Stop();
_timedPlayers.Remove(player);
}

How to set a periodic task through my application?

I would like to implement a periodic file posting function to my application. For example, it uploads a certain text file in every 5 mins. So I am thinking some sort of manager that can handle time. I understand how to use Timer() method in c#, So how do I keep track on my timer through my application running? What will be the appropriate approach for such process?
Welcome to StackOverflow :D
I am assuming that you're using Windows Forms.
Here's an example on how to achieve this :
A periodic uploader for which you can set the interval, the upload handler and manage it (start/stop)
The upload handler will be a method on your side where you do the upload, this is great in the sense that this class does not need to know about it, it just calls it. In other terms separation of concerns.
internal class MyPeriodicUploader
{
private readonly Timer _timer;
private Action<string, string> _uploadHandler;
public MyPeriodicUploader(int miliseconds = 50000)
{
if (miliseconds <= 0) throw new ArgumentOutOfRangeException("miliseconds");
_timer = new Timer {Interval = miliseconds};
_timer.Tick += timer_Tick;
}
public string InputFile { get; set; }
public string TargetUrl { get; set; }
private void timer_Tick(object sender, EventArgs e)
{
if (_uploadHandler != null && InputFile != null && TargetUrl != null)
{
_uploadHandler(InputFile, TargetUrl);
}
}
public void SetUploadHandler(Action<string, string> uploadHandler)
{
if (uploadHandler == null) throw new ArgumentNullException("uploadHandler");
_uploadHandler = uploadHandler;
}
public void StartTimer()
{
_timer.Start();
}
public void StopTimer()
{
_timer.Stop();
}
public void SetUploadInterval(int minutes)
{
_timer.Interval = TimeSpan.FromMinutes(minutes).Milliseconds;
}
}
Now you want it available for your whole application, open Program.cs and create a property of it there :
internal static class Program
{
private static readonly MyPeriodicUploader _myPeriodicUploader = new MyPeriodicUploader();
public static MyPeriodicUploader MyPeriodicUploader
{
get { return _myPeriodicUploader; }
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
Then on your form use it like this :
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Program.MyPeriodicUploader.SetUploadHandler(UploadHandler);
Program.MyPeriodicUploader.InputFile = "yourFileToUpload.txt";
Program.MyPeriodicUploader.TargetUrl = "http://youraddress.com";
Program.MyPeriodicUploader.StartTimer();
}
private void UploadHandler(string fileName, string targetUrl)
{
if (fileName == null) throw new ArgumentNullException("fileName");
// Upload your file
using (var webClient = new WebClient())
{
webClient.UploadFileAsync(new Uri(targetUrl), fileName);
}
}
}
UploadHandler is a callback if you're not familiar with the term I guess you'll quickly find it useful because you define the uploading, you won't depend of the implementation that MyPeriodicUploader would provide if it was the case; sometimes it would not fit your needs so defining it yourself is really useful.
I've put a really simple uploader in UploadHandler() as an example.
Note, I have used Action<string,string>, the first parameter is the file name, the second the target URL. The class will fail gracefully, if none of the file name and target url are defined, the operation will simply not happen.
Mark the answer if you like it, if there's something else update your question with more details so I can help.

error learning how to use custom events

i'm learning how to use custom events in c#, but i get some errors
i get "An object reference is required for the nonstatic field, method, or property" in the bold words
so i tried following this
but case 1 couldn't be tried 'cause TypeChanged is already a nonstatic method (i think)
in case 2 i get "impossible to acces BicycleType as an instance reference, qualify it as a type"
public class Bicycle
{
public event EventHandler TypeChanged;
private string type;
...
public string BicycleType {
get { return this.type; }
set {
this.type = value;
if (this.TypeChanged != null)
this.TypeChanged( this, new EventArgs() );
}
}
public Bicycle() {}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("heila!");
Bicycle istanza = new Bicycle();
istanza.TypeChanged += new EventHandler(**istanza_TypeChanged**);
istanza.BicycleType = "io";
Console.WriteLine("io");
}
void istanza_TypeChanged(object sender, EventArgs e) {
Console.WriteLine("rofkd");
}
}
the tutorial i followed told me i can use events "as" methods, maybe i'm wrong here?
the code is completely similar to te tutorial code
sorry for my bad english and thanks in advance
As you are registering the event from the main method, which is static, the event handler (istanza_TypeChanged) has to be made static too.
You problem is that Main is static and can therefore not access nonstatic members of the class Program. However you try to access istanza_TypeChanged. That is what is causing your exception.
You have to make istanza_TypeChanged static too to solve the issue
class Program
{
static void Main(string[] args)
{
Console.WriteLine("heila!");
Bicycle istanza = new Bicycle();
istanza.TypeChanged += new EventHandler(**istanza_TypeChanged**);
istanza.BicycleType = "io";
Console.WriteLine("io");
}
static void istanza_TypeChanged(object sender, EventArgs e)
{
Console.WriteLine("rofkd");
}
}
Register the event from a non-static context or change your event to be static.
Change istanza_TypeChanged to the following:
private static void istanza_TypeChanged(object sender, EventArgs e)
{
Console.WriteLine("rofkd");
}
The following fired the event for me:
public class Bicycle
{
public event EventHandler TypeChanged;
private string type;
public string BicycleType
{
get { return this.type; }
set
{
this.type = value;
if (this.TypeChanged != null)
this.TypeChanged(this, new EventArgs());
}
}
public Bicycle()
{
}
private class Program
{
private static void Main(string[] args)
{
Console.WriteLine("heila!");
Bicycle istanza = new Bicycle();
istanza.TypeChanged += istanza_TypeChanged;
istanza.BicycleType = "io";
Console.WriteLine("io");
}
private static void istanza_TypeChanged(object sender, EventArgs e)
{
Console.WriteLine("rofkd");
}
}
}

Categories