C# Timers and repeating code - c#

I am writing an IRC bot that needs to advertise something every few minutes to the channel. I made an attempt with the Timer but it's so messy I can't paste it here because it will be unreadable, I can post the entire file's code to pastebin though.
What needs to be looped/timed to send every 5 minutes to the channel:
public static void ChannelAdvertise(object sender, IrcEventArgs e)
{
string advertiseStream = "Live right now: ";
foreach (Monitor stream in streams)
{
if (stream.streamOnline)
{
advertiseStream += (char)3 + "03" + stream.nick +
(char)15 + " - " + stream.weblink() + " ";
}
}
irc.SendMessage(SendType.Message, e.Data.Channel,
advertiseString);
}
Just that piece of code needs to be sent to the channel every 10 minutes. Any help/pointers would be appreciated.
class Bot
{
private static System.Timers.Timer advertiseTimer;
static void Main(string[] args)
{
advertiseTimer = new System.Timers.Timer(60000);
advertiseTimer.Elapsed += new ElapsedEventHandler(advertiseTimer_Elapsed);
advertiseTimer.Start();
}
public static void ChannelAdvertise(object sender, IrcEventArgs e)
{
string advertiseStream = "Live right now :";
foreach (Monitor stream in streams)
{
if (stream.streamOnline)
{
advertiseStream += (char)3 + "03" + stream.nick + (char)15 + " - " + stream.weblink() + " ";
}
irc.SendMessage(SendType.Message, e.Data.Channel, advertiseStream);
}
}
static void advertiseTimer_Elapsed(object sender, ElapsedEventArgs e)
{
ChannelAdvertise();
}
}

You can use DispatcherTimer of the System.Windows.Threading namespace.
You can refer toMSDN Reference. Set the interval of this timer set as per your requirement and you can write this code in the timer tick event handler. Hope this helps

You should use the Dispatch Timer as #Aashish Thite has suggested.
additionally, here is your problem: you define
public static void ChannelAdvertise(object sender, IrcEventArgs e)
{
}
to recieve two arguments, but you are trying to call it with no arguments:
static void advertiseTimer_Elapsed(object sender, ElapsedEventArgs e)
{
ChannelAdvertise();
}
this is what your error message "No overload for method 'ChannelAdvertise' takes 0 arguments." is telling you.
that said, you have two options: call it with the required 2 arguments (as you have defined it), or redefine it so that it does not take any arguments (as you are calling it from the advertiseTimer_Elapsed method)
basically, you need to pass in a sender object and an IrcEventArgs argument.
so, you could call it like so:
static void advertiseTimer_Elapsed(object sender, ElapsedEventArgs e)
{
// make a new one, or get it form some collection, or whatever
IrcEventArgs args = new IrcEventArgs( /* initialize the object */ );
ChannelAdvertise(this,args);
}
or you could redefine like so:
// looking at your code, you are only using the channel from the IrcEventArgs.Data object
public static void ChannelAdvertise( channelobject channel )
{
}

Try:
void Main()
{
System.Threading.Timer timer = new System.Threading.Timer(
Callback,
channel,
0,
10 * 60 * 1000);
}
void Callback(object state)
{
ChannelAdvertise(this, (Channel)state);
}

I have recently written an article that may be just what you are looking for. It demonstrates in c# a generic polling component that runs at a specified interval and uses a background thread to perform the user action specified.
Sample usage:
IPoller poller = new UrlPoller(args[0], TimeSpan.FromSeconds(7));
IPolling pollingComponent = new Polling.Core.Polling(poller);
pollingComponent.SubscribeForPollingUpdates(PollingAction);
pollingComponent.Start();
For the code and complete sample see:
http://www.avantprime.com/blog/24/an-example-of-repeating-code-using-a-worker-thread-without-using-timers-c

Related

Calling a function from serial port handler took too much time and processor power

i am getting data from serial port interface each data stream (packet) consist of 1kbytes. these values are basic digital oscilloscope analog signals. After processing these datas i draw the signals to the screen.
The problem is if i call the function which process the signals from serial port "DataReceivedHandler" it takes too much time(200mS) and too much process power. But when i call my function seperatly like via button click it took 10mS. After debugging too many times i couln't find why is this taking too long? what are the possible reasons for this? can you give me some solutions?
In two examples below results are correct but time consuming different.
public void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
int temp_buffer_count;
temp_buffer_count = sp.BytesToRead;
label55.Text += temp_buffer_count.ToString() + "--";
serialPort1.Read(readBuffer, uart_count, temp_buffer_count);
uart_count += temp_buffer_count;
if(uart_count>3)
{
int dataadet = readBuffer[1] * 256 + readBuffer[2] + 3;
if(uart_count>= dataadet)
{
if(readBuffer[0]==0xff)
{
UdpReceivedData = new byte[dataadet + 100];
Array.Copy(readBuffer, ReceivedData, dataadet);
uart_count = 0;
dataadet = 0;
if(ReceivedData[3]==AdcDataIslemi)
{
stopwatch2.Resart();
//this function tooks too much time
PreparePage(false, true);
stopwatch2.Stop();
}
}
}
}
}
if i call same function with a button click that function is executing 20 times faster.
private void button2_Click(object sender, EventArgs e)
{
stopwatch2.Resart();
PreparePage(false, true);
stopwatch2.Stop();
}

C# add text to ListBox or TextBox

Hello, I've got problem to write simple string to TextBox and ListBox. I do not know what is wrong.
After click on button3 is in class Listen running method to open communication and receiving packets. In this method (Listen.StartListen) is reference to PrintReceivedPackets. Is it mistake in Task part?
Is it better to use Thread instead of Task?
2.
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private Listen lis, start;
public Form1()
{
InitializeComponent();
}
private void button2_Click_1(object sender, EventArgs e)
{
string deviceNum = comboBox2.Text;
char dN = deviceNum[0];
start = new Listen();
Task.Factory.StartNew(() => start.StartListen(dN));
}
private void button3_Click(object sender, EventArgs e)
{
lis = new Listen();
var devices = lis.GetDevices();
comboBox2.DataSource = devices;
}
public void PrintReceivedPackets(string packetInfo)
{
// Do not work
Console.WriteLine(">>>" + packetInfo);
listBox1.Items.Add(packetInfo);
textBox1.AppendText(packetInfo);
}
}
Methods in Class Listen
public void StartListen(char deviceNum)
{
int deviceNumber = (int)Char.GetNumericValue(deviceNum);
// Take the selected adapter
PacketDevice selectedDevice = allDevices[deviceNumber - 1];
// Open the device
using (PacketCommunicator communicator =
selectedDevice.Open(65536, // portion of the packet to capture
// 65536 guarantees that the whole packet will be captured on all the link layers
PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode
1000)) // read timeout
{
Console.WriteLine("Listening on " + selectedDevice.Description + "...");
// start the capture
communicator.ReceivePackets(0, PacketHandler);
}
}
// Callback function invoked by Pcap.Net for every incoming packet
public void PacketHandler(Packet packet)
{
Console.WriteLine(packet.Timestamp.ToString("dd-MM-yyyy ") + " length:" + packet.Length + " " + packet.DataLink);
string packetInfo = packet.Timestamp.ToString("dd-MM-yyyy ") + " length:" + packet.Length + " " + packet.DataLink;
Form1 f = new Form1();
f.PrintReceivedPackets(packetInfo);
}
Edit: added comments on how to make the main form visible to the Listener
The easiest way would be to add a reference to the main form to your Listen class. A'la:
public class Listen
{
Form1 mainForm;
public Listen(Form1 mainForm)
{
this.mainForm = mainForm;
...
}
}
Then, in button2_Click_1 you can create the start object like this:
start = new Listen(this);
And then, in PacketHandler, you can do:
mainForm.Invoke((Action)(() => mainForm.PrintReceivedPackets(packetInfo)));
And remove Form1 f = new Form1() from the PacketHandler, as you dont actually want a new form for every packet.
In the PacketHandler you are creating a new Form1 instance and then calling PrintReceivedPackets method of that form. That form, judging by the code, is never actually opened - for that you would need to call f.Show() or f.ShowSialog() at some point.
If your intent is to display the packet notification of the actual main form, then you need to do two things:
Make your main form visible to the StartListen object, by either assigning the main form object to a global variable, or pass it into StartListen as parameter.
In PacketHandler, call the PrintReceivedPackets method of the main form. It's not quite apparent, in which thread the PacketHandler is executed. If you get a "cross-thread" exception, then you need to pass the update into main thread with Invoke, something like this:
mainForm.Invoke((Action)(() => mainForm.PrintReceivedPackets(packetInfo)));

stop sounds in threads c#

I've got two questions about some problems on this code:
1) How can I stop the sounds? Sounds are in a separate thread, and I don't know how to stop them.
2) If I continue pressing the key this code will play a lot of times the same sounds and this is not realistic (imagine a piano keyboard: if I press a key and I continue pressing it just one sounds (the firs) will play). How to solve this problem?
I found a solution but now with threads I don't know how to do.
private void Form1_KeyDown(object sender, KeyPressEventArgs e)
{
[...] // Other code
th = new Thread(press));
th.Start(new object[] { key, name });
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
[...] // Other code
th = new Thread(leave);
th.Start(new object[] { key, name });
}
private void press(object data)
{
[...] // Other code
playSound(name);
}
private void leave(object data)
{
[...] // Other code
stopSound(name);
}
private void playSound(string name)
{
[...] // Other code
string url = Application.StartupPath + "\\notes\\" + name + ".wav";
var sound = new System.Windows.Media.MediaPlayer();
sound.Open(new Uri(url));
sound.play();
}
private void stopSound(string name)
{
???
}
Thank'you so much!
Create the thread as a variable in the class so that it can be accessed whenever you want.
Use the Handled Property to prevent the event from being handled again
e.Handled = true;

wcf call completed event is not fired in correct order

In my Silverlight application, I put the WCF call in my ViewModel class.
DateTime CurrentDateTime;
internal void GetDateTime()
{
var client = new WcfClient();
client.GetCurrentDateTimeCompleted += GetCurrentDateTimeCompleted;
client.GetCurrentDateTimeAsync();
}
private void GetCurrentDateTimeCompleted(object sender, GetCurrentDateTimeCompletedEventArgs args)
{
try
{
CurrentDateTime = args.Result;
}
Then in my code behind code some.xaml.cs file. I have a checkbox clicked event.
private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
var msgBoxControl = new MessageBoxControl();
msgBoxControl.Closed -= MessageBoxYesNo_Closed;
msgBoxControl.Closed += MessageBoxYesNo_Closed;
Inside the method MessageBoxYesNo_Closed, I call the method in the ViewModel class.
private void MessageBoxYesNo_Closed(object sender, EventArgs e)
{
try
{
this.ViewModel.GetDateTime();
curDateTime = this.ViewModel.CurrentDateTime;
My question is that sometimes the line curDateTime = this.ViewModel.CurrentDateTime; is executed before wcf call completed method, so I can't get the right value.
I guess that it may be there are two threads, one is in UI, the other one is in service call? Please don't use async/await as I have to use Visual Studio 2010.
Thanks
Get the solution, just add a while loop:
this.ViewModel.GetDateTime();
while (true)
{
this.ViewModel.CurrentDateTime = DateTime.Now;
if (this.ViewModel.CurrentDateTime != DateTime.MinValue)
break;
}
curDateTime = this.ViewModel.CurrentDateTime;

How to use event argument outside the event

I'm trying to create a custom download app. Its all working except for the download all button that cant pick up the "percent1" variable from the "DownloadProgressChangedEventArgs". I have instantiated it prior to the mainForm constructor but it wont read the changed value.
Here's the code, partially stripped since most of it isnt relevant to the question:
public partial class Main : Form
{
//Variables (not all, just the one im having issues with)
private double percentage1;
//Main form constructor
public Main(){...}
//Download File Async custom method
public void DldFile(string url, string fileName, string localPath, AsyncCompletedEventHandler completedName, DownloadProgressChangedEventHandler progressName)
{
WebClient webClient = new WebClient();
webClient.DownloadFileAsync(new Uri(url), localPath + "\\" + fileName);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(completedName);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(progressName);
}
//Button 1 click event to start download
private void btnDld1_Click(object sender, EventArgs e)
{
if (url1 != "" && Directory.Exists(localPath1))
{
_startDate1 = DateTime.Now;
DldFile(url1, fileName1, localPath1, completed1, progress1);
}
//took out the try/catch, other ifs to try and cut it down
}
//Download Progress Changed event for Download 1
public void progress1(object sender, DownloadProgressChangedEventArgs e)
{
percentage1 = e.ProgressPercentage; //THIS IS WHERE I WAS EXPECTING TO UPDATE "percentage1"
progressBar1.Value = int.Parse(Math.Truncate(percentage1).ToString());
}
//Button that starts all downloads click event where all my problems are at the moment
private void btnDldAll_Click(object sender, EventArgs e)
{
//The progress bar that should let me know the global status for all webClients
progressBarAll.Value = (
int.Parse(Math.Truncate(percentage1).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage2).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage3).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage4).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage5).ToString())) / 5; //HERE IS MY PROBLEM
//Checks if the link exists and starts it from the download button click event
if (url1 != "")
{
btnDld1.PerformClick();
}
//Continues for url2, 3, 4, 5 and else
}
}
So this is the shortest way i found of letting you know what im trying to pull off, if there's something missing please let me know, i'll try to add any info as fast as possible.
I have tried to instantiate "progress1" to try and acess its percentage1 variable, but it didnt work. I've tried doing the same thing with the webClient but didnt work either. I have used google and stackflow search to no avail. So im not sure if the question is too dumb, or there's a diferent way to look at the issue thats completely out of my mindset.
So main problem is updating the "percentage1" variable and using it.
There are other problems regarding the "progressBarAll.Value" calculation that will be solved when i can get my hands on the right value. So no need to worry about that if you see it.
Try not to think about 'using the event arguments outside the event'. Think about updating the state of your form.
Use properties to simplify the update logic:
public partial class Main : Form
{
private double percentage1;
private double percentage2;
private double percentage3;
private double percentage4;
private double percentage5;
private double Percentage1
{
get
{
return this.percentage1;
}
set
{
this.percentage1 = value;
this.UpdatePercentageAll(); // this will update overall progress whenever the first one changes
progressBar1.Value = GetValueFromPercentage(value);
}
}
private double Percentage2
// same code as for Percentage1
void UpdatePercentageAll()
{
this.PercentageAll = (this.Percentage1 + this.Percentage2 + this.Percentage3 + this.Percentage4 + this.Percentage5) / 5;
}
static int GetValueFromPercentage(double percentage)
{
return (int)Math.Truncate(percentage);
}
double percentageAll;
private double PercentageAll
{
get
{
return this.percentageAll;
}
set
{
this.percentageAll = value;
progressBarAll.Value = GetValueFromPercentage(value);
}
}
//Download File Async custom method
public void DldFile(string url, string fileName, string localPath, AsyncCompletedEventHandler completedName, DownloadProgressChangedEventHandler progressName)
{
WebClient webClient = new WebClient();
webClient.DownloadFileAsync(new Uri(url), localPath + "\\" + fileName);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(completedName);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(progressName);
}
//Button 1 click event to start download
private void btnDld1_Click(object sender, EventArgs e)
{
if (url1 != "" && Directory.Exists(localPath1))
{
this.StartDownloadFile1();
}
//took out the try/catch, other ifs to try and cut it down
}
void StartDownloadFile1()
{
this.Percentage1 = 0;
_startDate1 = DateTime.Now;
DldFile(url1, fileName1, localPath1, completed1, progress1);
}
//Download Progress Changed event for Download 1
public void progress1(object sender, DownloadProgressChangedEventArgs e)
{
this.Percentage1 = e.ProgressPercentage; // update property, not field
//this will be done in property setters
//progressBar1.Value = int.Parse(Math.Truncate(percentage1).ToString());
}
// then add similar code for other download buttons
//Button that starts all downloads click event where all my problems are at the moment
private void btnDldAll_Click(object sender, EventArgs e)
{
//Checks if the link exists and starts it from the download button click event
if (url1 != "")
{
this.StartDownloadFile1();
}
//Continues for url2, 3, 4, 5 and else
}
}
I would refactor the code even further, but I think it will be easier for you to understand if the code is closer to the original.
The main idea is to create a set of linked properties which work like mathematical functions. When writing the PercentageX properties I'm kind of saying 'let PercentageAll be the average of all percentages'. Then I have each download update it's own progress. Once any progress is updated it updates the average, and I don't have to rememver that inside the progress changed event handler.
And the last point is updating progress bars from percentage properties. It's quite straightforward: once a percentage is changed, I need to update a bar. If so, why bother writing something like
this.Percentage1 = x;
this.progressBar1.Value = (int)Math.Truncate(x);
In this case I have to remember everywhere that once I change the Percentage1 I have to update the bar. And in my example I just create a strict rule for that which is only in one place and works everytime. So I just cannot forget it. And if I need to change the rule, I need to change only one place, so again I cannot make a mistake.
The technique I demonstrate can be expressed as a well-known rule: 'one rule - one place', which means that you should try to have only single place in code that expresses each logical rule that exists in your program. It is a very important idea, I suggest you learn and use it.

Categories

Resources