I'm creating a WPF tool to use on my HelpDesk team using XAML and C#, but I'd like to improve upon what I've done. I've got a textbox to enter a hostname, a button to start a ping, and a textbox that will keep pinging that hostname until I press the button again.
I'd like to keep the functionality the same, but I know there's a better way to write this code.
Currently, I have a class that pings the server and returns a response ONE single time. My main form calls this class, the logic is not written in the main form. When I tried to make this loop, it just kills the function after the first run through rather than looping. The way I got it to work was by using a timer to call the function/ping class every 500 MS or so, and stopping the timer by clicking the button again.
Here's my current way of doing this, t stands for "timer":
private void onTick(object sender, EventArgs e)
{
PingClass pingClass = new PingClass();
_richtext.AppendText(pingClass.PingHost(_textBox.Text));
_richtext.ScrollToEnd();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if ((string)_pingBtn.Content == "Ping")
{
_richtext.Visibility = Visibility.Visible;
_pingBtn.Content = "Stop Ping";
t.Interval = 500;
t.Tick += onTick;
t.Start();
}
else if ((string)_pingBtn.Content == "Stop Ping")
{
_richtext.Visibility = Visibility.Hidden;
_pingBtn.Content = "Ping";
t.Stop();
}
The class itself is pretty simple, it just returns a string of whatever the response from the host is. Unfortunately, it doesn't allow me to loop through inside the class because it stops at the first return. I'd like to gather an "average ping" and some other stats, but can't with the way it's currently set up. I don't want to have a timer, I want to be able to loop in the class itself until the button in the main form is pressed. Is this possible?
Related
Im trying to make a simple application to learn some things in c# (Visual Studio).
For now i am building a music player, and one of the actions is fading out the music at the button click event.
I've got no problem with building a fade-out part, i made a while loop and put the volume down with 1% eacht time the loop is running. Also i update a label with the fade value.
Only problem is, for slowing down the fading i'm using the Thread.Sleep event, and that part is freezing my application, and also is blocking any updates to my text label with the fade value.
The fading is working fine, so the only part I have to work on is another option to build some delay in. On some topics over here i did read about the timer, and i added a timer component in Visual Studio. Only problem, I am new to c# and don't know how to use it correctly in this while loop.
Can anybody give me some help?
The current code is:
private void BtnPodiumtune1Fadeout_Click(object sender, EventArgs e)
{
PlayerPodiumtune1.settings.volume = 100;
fade1 = 100;
while (fade1 != -1)
{
PlayerPodiumtune1.settings.volume = fade1;
Fadelevel1.Text = fade1.ToString();
System.Threading.Thread.Sleep(30);
fade1 = fade1 - 1;
}
PlayerPodiumtune1.Ctlcontrols.stop();
}
You could use a pattern like this instead of a timer. A timer is a fine way to go, just throwing this option out there:
private async void button_Click(object sender, EventArgs e)
{
if (Monitor.TryEnter(sender))
{
int fade1 = 1000;
while (fade1 != -1)
{
await Task.Delay(30);
fade1--;
}
}
}
So sender is the button, and Monitor.TryEnter prevents the function from being run again until the function is done. async tells the framework that this function can be executed asynchronously and is necessary for await. await returns control of the thread to the UI until the task is done.
PS--You're going to need something like Monitor.TryEnter to prevent re-entrancy in a timer-based solution as well, by the way.
This is a Console Application in C#:
using System;
namespace WaitAsync
{
class Program
{
static void Main(string[] args)
{
bool ok = false;
Console.Write("EnterTime (Seconds): ");
int time = Convert.ToInt32(Console.ReadLine()) * 1000;
while (ok != true)
{
System.Threading.Thread.Sleep(time);
ok = true;
Console.WriteLine("Waiting Time Just Finished");
}
Console.ReadLine();
}
}
}
I asked in a previous question how to "Threading 2 forms to use simultaneously C#".
I realize now that I was not explicit enough and was asking the wrong question.
Here is my scenario:
I have some data, that I receive from a local server, that I need to write to a file.
This data is being sent at a constant time rate that I cant control.
What I would like to do is to have one winform for the initial setup of the tcp stream and then click on a button to start reading the tcp stream and write it to a file, and at the same time launch another winform with multiple check-boxes that I need to check the checked state and add that info simultaneously to the same file.
This processing is to be stopped when a different button is pressed, closing the stream, the file and the second winform. (this button location is not specifically mandatory to any of the winforms).
Because of this cancel button (and before I tried to implement the 2nd form) I used a background worker to be able to asynchronously cancel the do while loop used to read the stream and write the file.
private void bRecord_Click(object sender, EventArgs e)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss") + ".xml", true);
data_feed = client.GetStream();
data_write = new StreamWriter(data_feed);
data_write.Write("<SEND_DATA/>\r\n");
data_write.Flush();
exit_state = false;
string behavior = null;
//code to launch form2 with the checkboxes
//...
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler((state, args) =>
{
do
{
int var = data_feed.ReadByte();
if (var != -1)
{
data_in += (char)var;
if (data_in.IndexOf("\r\n") != -1)
{
//code to check the checkboxes state in form2
//if (form2.checkBox1.Checked) behavior = form2.checkBox1.Text;
//if (form2.checkBoxn.Checked) behavior = form2.checkBoxn.Text;
file.WriteLine(data_in + behavior);
data_in = "";
}
}
}
while (exit_state == false);
});
worker.RunWorkerAsync();
}
private void bStop_Click(object sender, EventArgs e)
{
exit_state = true;
worker.CancelAsync();
}
I hope I've been clearer now.
I not experienced in event programming and just started in C# so please try to provide some simple examples in the answers if possible.
At first would it be enough to use one Winform? Disable all checkboxes, click a button which enables the checkboxes and start reading the tcpstream? If you need two Forms for other reasons let me know, but i think this isn't needed from what i can see in your question.
Then i would suggest you to use the Task Library from .Net. This is the "modern" way to handle multithreading. BackgroundWorker is kind of old school. If you just able to run on .Net 2.0 you have to use BackgroundWorker, but don't seem to be the case (example follows).
Further if you want to cancel a BackgroundWorker operation this isn't only call CancelAsync();. You also need to handle the e.Cancelled flag.
backgroundWorker.WorkerSupportsCancellation = true;
private void CancelBW()
{
backgroundWorker.CancelAsync();
}
private void backgroundWorker_DoWork += ((sender, args)
{
//Handle the cancellation (in your case do this in your loop for sure)
if (e.Cancelled) //Flag is true if someone call backgroundWorker.CancelAsync();
return;
//Do your stuff.
});
There is no common way to directly cancel the backgroundWorker
operation. You always need to handle this.
Now let's change your code to the modern TAP-Pattern and make some stuff you want to have.
private void MyForm : Form
{
private CancellationTokenSource ct;
public MyForm()
{
InitializeComponent();
checkbox1.Enable = false;
//Disable all checkboxes here.
ct = new CancellationTokenSource();
}
//Event if someone click your start button
private void buttonStart_Click(object sender, EventArgs e)
{
//Enable all checkboxes here
//This will be called if we get some progress from tcp
var progress = new Progress<string>(value =>
{
//check the behaviour of the checkboxes and write to file
file.WriteLine(value + behavior);
});
Task.Factory.StartNew(() => ListenToTcp(ct, progress as IProgress<string)); //starts the tcp listening async
}
//Event if someone click your stop button
private void buttonStop_Click(object sender, EventArgs e)
{
ct.Cancel();
//Disable all checkboxes (better make a method for this :D)
}
private void ListenToTcp(CancellationToken ct, IProgess<string> progress)
{
do
{
if (ct.IsCancellationRequested)
return;
int temp = data_feed.ReadByte(); //replaced var => temp because var is keyword
if (temp != -1)
{
data_in += (char)temp;
if (data_in.IndexOf("\r\n") != -1)
{
if (progress != null)
progress.Report(data_in); //Report the tcp-data to form thread
data_in = string.empty;
}
}
while (exit_state == false);
}
}
This snippet should do the trick. I don't test it so some syntax error maybe occur :P, but the principle will work.
The most important part is that you are not allowed to access gui
components in another thread then gui thread. You tried to access the
checkboxes within your BackgroundWorker DoWork which is no possible
and throw an exception.
So I use a Progress-Object to reuse the data we get in the Tcp-Stream, back to the Main-Thread. There we can access the checkboxes, build our string and write it to the file. More about BackgroundWorker vs. Task and the Progress behaviour you can find here.
Let me know if you have any further questions.
I am implementing a debugger using c#(working on VS2012 -- .Net 4.5), it should work as below: (This is a vbscript debugger which is using msscript.ocx control)
On the line with breakpoint it should wait for the {F5} key and upon having the {F5} key it should move to next code line.
Now the problem is that in the debug method(This method is called upon hitting breakpoint) keeps on moving in the loop checking for the static variable set as true ( The key-press event on the control sets this static variable as true).
The application goes un-responsive and i have to stop it.
Here goes the code for it:
Following code is implemented at the KeyPress event of a TextBox:
Whenever it receive a {F5} key it sets true in a static variable.
static bool dVar;
private void fctb_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.F5)
{
//Setting the static variable true when the control recieves a {F5} key
dVar = true;
}
}
Now Upon hitting the breakpoint following function is called
public void DebugIT()
{
dVar=false
//Waits for the {F5} key press by checking for the static variable
//The Application goes Un-Responsive on this Loop and stops accepting keys
while (dVar!=true)
{
System.Threading.Thread.Sleep(1000);
}
}
}
The issue here is that when it enter the while loop it stops accepting the key-presses and goes unresponsive.
Need a way that suspends the code execution till the time it receives a desired key-press.
Or
Can we have a separate thread which checks for the {F5} key press and does not make the application un-Responsive.
Can anyone please help?
Here is an example of how you can do this.
If you want this exact code to work create a new form and drag-drop two buttons and a textbox on it.
public partial class Form1 : Form
{
ManualResetEvent man = new ManualResetEvent(false);
public Form1()
{
InitializeComponent();
button1.Click += button1_Click;
button2.Click += button2_Click;
}
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Enabled = false;//Do some work before waiting
await WaitForF5(); //wait for a button click or a key press event or what ever you want
textBox1.Enabled = true; //Continue
}
private Task WaitForF5()
{
return Task.Factory.StartNew(() =>
{
man.WaitOne();
man.Reset();
}
);
}
private void button2_Click(object sender, EventArgs e)
{
man.Set();
}
}
In the above example when you click button1 the textbox is disabled and when you press the second button is gets enabled again.
And this is done without blocking the UI
You need to add DoEvents into your while loop. See the example from MSDN
I have a button click event handler with a switch case in it that controls multiple buttons in one event handler.
I need to use a queue because while one button is clicked and doing some processing, second button click won't interfere with the first button click, but added to the queue. I don't want to use .enabled=false; because it'll discard the second click completely, and I'm currently editing someone's software at work so I don't want to break things that I don't know, so what are you suggesting?
The best idea, I think, is to create a producer/consumer queue.
Another question is explaining this technique.
Basically, the idea is to have a worker thread that will consume a queue to get the job to do, while other thread produce job by queuing operation in the queue.
I did succeed this with System.Collections.Queue
The code is :
private Queue<Button> Button_Queue = new Queue<Button>();
private bool isProcessing = false;
private void Button_Click((object sender, EventArgs e){
if(isProcessing){
Button_Queue.Enqueue(this);
}
else
{
isProcessing = true;
// code here
isProcessing = false;
while(Button_Queue.Count > 0){
Button_Queue.Dequeue().PerformClick();
}
}
of course mine is slightly different from this because I need to pass some variables and my click method is modified for this.
Dirty, but simple solution.
public partial class DataRefresh : Form //DataRefresh is just "some form"
{
...
...
public DateTime ClickTime; //Time when click is processed by system
public DateTime LastExecutionRunTime = DateTime.MinValue; //Time when the all the click code finish
private void buttonDataRefresh_Click(object sender, EventArgs e)
{
ClickTime = DateTime.Now;
if (ClickTime.Subtract(LastExecutionRunTime).TotalSeconds < 5 )
{
//It will keep returning - hopefully until all events in que are satisfied
return;
}
//Long running code
//Importing whole table from remote DB
...
...
//End of the Long running code
LastExecutionRunTime = DateTime.Now;
}
}
Hello I am trying to program some checkboxes to become checked and unchecked in a specific sequence programmatically. I know it sounds dumb, but this is corresponding to some LED controls that I've already coded the check events for.
I want to check a checkbox to start this sequence and uncheck it to stop it. Currently the checking and unchecking of my D2 checkbox occurs fine, but the do while loop freezes the form so I can't actually uncheck the cycle box. I probably should not be using Thread.Sleep either. Any advice is appreciated.
private void cycleCheckBox_CheckedChanged(object sender, EventArgs e)
{
do
{
D2.Checked = true;
Thread.Sleep(1000);
D2.Checked = false;
Thread.Sleep(1000);
} while (cycleCheckBox.Checked);
}
The Thread.Sleep method will run on the UI thread if called directly in the checked event which is why the UI is freezing. Push the work into a System.Windows.Forms.Timer (assumption is this is a WinForms app):
Implements a timer that raises an event at user-defined intervals.
This timer is optimized for use in Windows Forms applications and must
be used in a window.
Example based on your question:
Timer _timer;
private void cycleCheckBox_CheckedChanged(object sender, EventArgs e)
{
if(_timer == null )
{
_timer = new Timer();
_timer.Interval = 1000; // 1 second
_timer.Tick += DoTimerWork;
}
if(cycleCheckBox.Checked)
{
_timer.Start();
}
else
{
_timer.Stop();
}
}
private void DoTimerWork(object obj, EventArgs args)
{
D2.Checked = !D2.Checked;
}
I don't know if this will work for you but what I would do is drag in a Timer Control at 1000 ms and use a method to figure out which checkbox should currently be checked by using an integer that loops to 0 at a certain point and gets incremented at each tick.