I have event
button.Click += ProcessClick;
and my event handler ProcessClick is:
private void async ProcessClick(object o, EventArgs e){
await LongOperation()
}
When I will click button quickly many times,
How to process only the first thread and skip other threads, until the first is done?
Disabling button after first click is not a solution...
EDIT: utilizing any type of thread constructions is acceptable: Tasks, Semaphores, locks and so on.
You can remove the event after the first click and add it again at the end of processing the first click.
private async void button1_Click(object sender, EventArgs e)
{
Debug.Write("Running click event");
this.button1.Click -= button1_Click;
await Task.Run(() => Task.Delay(5000));
this.button1.Click += button1_Click;
}
private bool longOperationRunning;
private void async ProcessClick(object o, EventArgs e){
if (longOperationRunning)
return;
longOperationRunning = true;
await LongOperation()
longOperationRunning = false;
}
Related
In this example I'm using 1 button and web browser in VB using C#
I simply want to hit the button once then have it go to bing, wait 2 seconds, then go to google. Every method I've seen when I try it always has the pause or pauses at the beginning and not between navigation. Here's what I have. Thanks in advance.
public void button1_Click(object sender, EventArgs e)
{
WebBrowser1.Navigate("http://www.bing.com");
Thread.sleep(2000);
WebBrowser1.Navigate("http://www.google.com");
}
Subscribe to the DocumentCompleted event and navigate to the second page there:
private void LoadPages()
{
WebBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser1_DocumentCompleted);
WebBrowser1.Navigate("http://www.bing.com");
}
void WebBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser1.Navigate("http://www.google.com");
// Might want to dispose of the webbrowser instance or else
// this event will fire again for the above call to `Navigate()`
// and you'll end up in a loop.
((WebBrowser)sender).Dispose();
// Or you could unsubscribe to the event if you still need the browser instance
WebBrowser1.DocumentCompleted -= WebBrowser1_DocumentCompleted;
}
Let's assume we have this:
private void Input_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
And then i add async-await like this:
private async void Input_KeyDown(object sender, KeyEventArgs e)
{
await Task.Delay(1000);
e.Handled = true;
}
Shouldn't that do the same, but only delay it for a second? So why doesn't it?
NOTE:
I'm not seeking for debugging help, i'm just wondering why can't i use async-await to delay handling the KeyDown
i'm just wondering why can't i use async-await to delay handling the KeyDown
Event handlers are synchronous by definition. So, unless your code has a way to inform the event handler that it is acting asynchronously (e.g., a WinStore-style Deferral), then it must do all "communication" (e.g., KeyEventArgs.Handled) before its first await.
If you need to delay input in general, I recommend converting the code to use Reactive Extensions.
The problem is that you're trying to use await in an event handler. The "synchronous part" of event handler does nothing.
void OnKeyDown()
{
Keys keyData = ...;
KeyEventArgs args = new KeyEventArgs(keyData);
// Thread-safe event raiser,
// equalient to KeyDown(this, args);
RaiseKeyDownEvent(args);
// Returns immediatelly when you reach
// the first await method call
bool isHandled = args.Handled;
// In the meantime event handler
// is awaiting for Task.Delay(),
// but we have already saved Handled value
}
// This code does nothing useful
private async void Input_KeyDown(object sender, KeyEventArgs e)
{
// Will return there
await Task.Delay(1000);
// The execution will be continued from there
e.Handled = true;
}
// But this code will handle input, but without any delay
private async void Input_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
await Task.Delay(1000);
}
I would like to kill the first thread upon the second click, then re-create it. My goal is to only ever have one tick thread in existence.
I believe I can do this with supplying a delegate to the thread instance? but I have googled and fiddled with it for hours upon hours with no luck. Can anyone translate my anonymous lambda expression into something with a delegate so I can identify and kill my thread after I've started it?
I hope my question makes sense, I am still learning... thanks
Timer timer1 = new Timer();
timer1.Interval = 1000;
timer1.Start();
private void button1_Click(object sender, EventArgs e)
{
//If I click button twice, how do I kill the first tick thread,
//before creating another?
timer1.Tick += (sender2, e2) => timer1_Tick(sender2, e2, 1, "text");
}
private void timer1_Tick(object sender, EventArgs e, int num, string text)
{
//do stuff with num and text
}
All you have to do is create a variable to store the delegate -- that should be of type Action<object, EventArgs>. So something like this:
private Action<object, EventArgs> _handler;
private void button1_Click(object sender, EventArgs e)
{
if (_handler != null)
timer1.Tick -= _handler;
_handler = (sender2, e2) => timer1_Tick(sender2, e2, 1, "text");
timer1.Tick += _handler;
}
private void timer1_Tick(object sender, EventArgs e, int num, string text)
{
timer1.Tick -= _handler;
_handler = null;
//do stuff with num and text
}
Note that this creates a race condition -- the "_handler" reference could be set to null by a "timer1_Tick" thread after the other thread sets the reference, but before it adds it to the "Tick" event. (To avoid the race condition, you would want to create a local copy of "_handler".) Hopefully that gives you the idea though ...
I have Button with code:
protected void Button1_Click(object sender, EventArgs e) {
Label1.Text = "Searching for services";
UpdatePanel1.Update();
}
but in addition I need to show something when I will find my services so I add another event:
Button1.Click += (s, k) => {
discovery.FindAlreadyRegisteredServices();
discovery.discoveryClient.FindCompleted += FoundEvent;
auto[1].WaitOne();
UpdatePanel1.Update();
};
which is slow (and controlled by AutoResetEvent)
protected void FoundEvent(object sender, FindCompletedEventArgs e) {
Label1.Text = "Found " + ((discovery.endpoints.Count > 0) ? discovery.endpoints[0].Address.ToString() : "nothing");
auto[1].Set();
}
The problem is that my Button1.Click += (s, k) => just makes no sense at all because it executes after Button1_Click and there is no PostBack until all the bonded events will be finished?
I know that I can use everything I want right on client by using UpdateProgress and javascript but what I want here is client to sent 2 events and wait for 2 answers, make 2 PostBacks. Is it possible?
protected void Button1_Click(object sender, EventArgs e) {
Label1.Text = "Searching for services";
//change postback hooks
Button1.Click -= Button1_Click;
Button1.Click += AnotherEventPB;
ScriptManager.RegisterStarupScript(this, GetType(), postback, "__doPostBack();", true);
UpdatePanel1.Update();
}
protected void AnotherEventPB(object sender, EventArgs e)
{
//reset postback hooks
Button1.Click -= AnotherEventPB;
Button1.Click += Button1_Click;
discovery.FindAlreadyRegisteredServices();
discovery.discoveryClient.FindCompleted += FoundEvent;
auto[1].WaitOne();
UpdatePanel1.Update();
}
I know that I can use everything I want right on client by using UpdateProgress and javascript but what I want here is client to sent 2 events and wait for 2 answers, make 2 PostBacks.
Why? It seems like an arbitrary constraint that's making an otherwise trivial task unnecessarily complicated.
Currently I'm moving from java to c# and I'm full of crazy questions.
I'm trying new things on a windows form application and now,I would like to create a loop wich is executing a code every 1 minute,the problem is that I have no idea where to put this code.
For example,the form structure is like:
using System;
namespace Tray_Icon
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
notifyIcon1.ShowBalloonTip(5000);
}
private void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
{
label1.Text = "Baloon clicked!";
}
private void notifyIcon1_BalloonTipClosed(object sender, EventArgs e)
{
label1.Text = "baloon closed!";
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
}
private void option1ToolStripMenuItem_Click(object sender, EventArgs e)
{
//some code here
}
private void option2ToolStripMenuItem_Click(object sender, EventArgs e)
{
//some code here
}
private void option3ToolStripMenuItem_Click(object sender, EventArgs e)
{
label1.Text = "Option 3 clicked!";
}
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
option1ToolStripMenuItem_Click(this, null);
}
private void closeToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnWrite_Click(object sender, EventArgs e)
{
//code here
}
}
}
Where should I put the loop code? :(
Thanks in advance for ANY replay!!!
Add a Timer to your form:
set its Interval property to 60000 (one minute in milliseconds) and Enabled to True:
and attach an event handler to the Timer.Tick event, e.g. by double-clicking the timer in the Forms designer:
private void timer1_Tick(object sender, EventArgs e)
{
// do something here. It will be executed every 60 seconds
}
You would have to add a timer, and set the interval to 1000 miliseconds, and in the OnTick event you add the code with your loop
Timer tmr = null;
private void StartTimer()
{
tmr = new Timer();
tmr.Interval = 1000;
tmr.Tick += new EventHandler<EventArgs>(tmr_Tick);
tmr.Enabled = true;
}
void tmr_Tick(object sender, EventArgs e)
{
// Code with your loop here
}
You can't put any loop code in here.
In your designer look for the Timer control. When you have that, configure it to run every minute and place your code in the Timer_Tick event.
Or create a timer manually in code and respond to the event :) But for starters, doing it by the designer is easier!
Drag a Timer component on the Form and doubleclick it. There you go with the code.
The Timer component runs in the main thread so you can modify UI components without worrying.
Alternatively You could create a System.Timers.Timer, which has it's own thread and has some advantages, but possible caveats when modifying UI components. See http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
Try to use Background Worker and put the code in the backgroundWorker.DoWork or use a Timer
Use System.Timers.Timer:
System.Timers.Timer aTimer;
{
aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 60000;
aTimer.Enabled = true;
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
for using Timer see this tutorial: C# Timer
How you do it in Java platform?
I think Java should be the same with .net.
In fact, a form program is just normal program which contains a event dispatcher. The event dispatcher listen to the UI events and dispatch them to the event handlers. I think all the UI mode should like this, no matter Java or .net platform.
So generally speaking, you have 2 options:
Start the loop at beginning. In this case, you should insert your
code in the constructor of the Form.
Start the loop when user
click the button. In this case, you should insert your code in the
event handler function.
Yes, as others mentioned, you should use the timer. But this should after you know where your code should locate. You also can use a endless loop with a sleep call. But timer is a better solution.
Idea of timer is more better. But If you want to use threads. Then Follow this
Let me assume that You want to do it right from the start of program
You can write in body of function (event in fact) named Form1_Load as
Your actual code is just within while loop other code only to guide
I can guide if you don't know the use of threads in C#
bool button2Clicked = false;
private void Form1_Load(object sender, EventArgs e)
{
// A good Way to call Thread
System.Threading.Thread t1 = new System.Threading.Thread(delegate()
{
while (!button2Clicked)
{
// Do Any Stuff;
System.Threading.Thread.Sleep(60000); //60000 Millieconds=1M
}
});
t1.IsBackground = true; // With above statement Thread Will automatically
// be Aborted on Application Exit
t1.Start();
}