How to disable and after enable the click receiving...? - c#

I wanna reset the MouseEventArgs to always run only once.
If somebody click the button more than once (10 times) then the program run 10x and so on.
My code doesn't work well, because if someone click on the button1 2x or more times it will be runned.
I wanna reset the MouseEventArgs or do other solution.
Windows Form Application (XP, 32bit)
private void button1_MouseClick(object sender, MouseEventArgs e)
{
button1.Enabled = false;
button1.MouseClick -= button1_MouseClick;
mc++;
if (true)
{
button1.Enabled = false;
//button1.Location = new Point(40, 40);
//Point location = button1.Location;
//location.X = 0; location.Y = 0;
System.Threading.Thread.Sleep(2000);
if (mc == 1)
{
//button1.Location = new Point(67, 191);
//location.X = 67; location.Y = 191;
mc = 0;
button1.Enabled = true;
button1.MouseClick += button1_MouseClick;
textBox1.AppendText("Click " + e.Clicks + ", Clicks: " + mc + "\n");
}
}
}

You are trying to execute some long running job on the main thread.
It might look like you disabled the button and following clicks should be ignored but they are actually placed in a queue. If you take a look at the events queue every click is done when the button is enabled:
Click
Disable button
Wait 2 seconds
Enable button
Click
...
Try the following code:
private void button1_MouseClick(object sender, MouseEventArgs e)
{
//disable button on main thread
button1.Enabled = false;
Thread worker = new Thread(() =>
{
//do time consuming job
System.Threading.Thread.Sleep(2000);
//enable button (from the main thread)
this.Invoke((MethodInvoker)delegate
{
textBox1.AppendText("Click " + e.Clicks + "\n");
button1.Enabled = true;
});
});
worker.Name = "Button 1 worker";
worker.Start();
}
Now the time consuming job is done on separate thread and the UI events will work as expected:
Click
Disable button
Do job on another thread ------------> Wait 2 seconds
Click - ignored (button is disabled) |
Click - ignored (button is disabled) |
Click - ignored (button is disabled) |
Click - ignored (button is disabled) |
Enable button
Click
Disable button ...

Instead of writing logic inside the event try to make a custom control that extend System.Windows.Forms.Button.
But as far as I can understand your code make you click event handler always be linked with the function, if mc value start with 0.
Hope it helps

When you disabled your button is may not receive any mouse-events further so you do not have to change any event-handlers. Write your code that should be executed once within your handler and disable the button. Thus the code cannot be executed any longer as long as the button is disabled.

Related

Is there a way to call a function after button is pressed?

So my problem is the following:
I have a button, which has a set background. If the button is pressed, I call the function, which is called check();
The problem is, that if the button is pressed, I will set the background to a certain picture, and if I call the fucntion check, and in that check, sometimes I delete the background.
So sometimes without even seeing the background it gets deleted. How can I improve it, so it gets deleted only like after 3-4 seconds?
private void button2_Click(object sender, EventArgs e)
{
Image img = Image.FromFile(#"C:\Users\nhorv\Downloads\javascript.jpg");
button2.BackgroundImage = img;
buttonList.Add(button2);
counter++;
check();
}
This is the button_click function, and this is the check() func:
void check()
{
if (counter == 2)
{
if (buttonList.Contains(button1) && buttonList.Contains(button6))
{
progressBar1.Increment(10);
}
.
.
.
else
{
buttonList[0].BackgroundImage = null;
buttonList[1].BackgroundImage = null;
}
buttonList.Clear();
counter = 0;
}
}
The buttons are stored in the buttonList list.
For the timing, I heard about: System.Threading.Thread.Sleep(1000); - for a 1 second delay.
Any help is really appreciated!
Edit:
The problem is with the buttons. If I call the button1_pressed function, it runs trough and only after that is the background changed. Unfortunately, there is the check function, which immediately deletes the background. So I have to somehow make the check function after the button press, so that the button can change the background, and only after that will I call check();
Use
System.Threading.Thread.Sleep(3000);
to pause the execution for 3 seconds and then delete the background based on the condition.
private void button2_Click(object sender, EventArgs e)
{
Image img = Image.FromFile(#"C:\Users\nhorv\Downloads\javascript.jpg");
button2.BackgroundImage = img;
buttonList.Add(button2);
System.Threading.Thread.Sleep(3000);
check();
}
So this is what I have understood from your code: you have button 2 with the event handler button2_Click associated on it.
Once you have clicked button 2, you set the background image to the button, add the BUTTON 2 to a list of button, increment a variable called counter by 1 and then call check function.
Check function, first of all, controls if counter is 2. If not, exit. Else, controls if button1 and button6, that I don't know where they're and if thery're added to to buttonList or not, are into the list or not. If they both are present, then increment the progressbar by 10. If one of them is not in the list, or both, you set the background immage of the first 2 buttons in the buttonList to null...
In the end, you clear the buttonList and set the counter to 0.
First of all, we should see the entire code in order to understand what's going on. Relying only on what I can see, start the programm in debug mode and check if button1 and button6 are in the list. In my opinion, you never add those 2 buttons to the list (is enough that only one of them is not present, since there's an and into the if), so the program will always delete the background image.
If I understand you correctly, you want to delay the check() function that deletes the background. You will need to create a thread that will do that:
async Task check()
{
if (counter == 2)
{
await Task.Delay(3000);
...<your other code>
}
}
Your button click then becomes:
private async void button2_Click(object sender, EventArgs e)
An you call your check method:
_ = check();
To create a small delay (so the player can check if they match, you should go for the async method)
But you need to prevent that, when the Task.Delay is running, a button is disabled. The await Delay ensures that the paint messages are handled, but also new buttons can be clicked.
Here an example:
private bool _buttonsEnabled = true;
private async void button2_Click(object sender, EventArgs e)
{
if(!_buttonsEnabled)
return;
_buttonsEnabled = false;
Image img = Image.FromFile(#"C:\Users\nhorv\Downloads\javascript.jpg");
button2.BackgroundImage = img;
buttonList.Add(button2);
counter++;
await check();
_buttonsEnabled = true;
}
private async Task check()
{
if (counter == 2)
{
if (buttonList.Contains(button1) && buttonList.Contains(button6))
{
progressBar1.Increment(10);
}
.
.
.
else
{
// wait for a second before clearing the background.
await Task.Delay(1000);
buttonList[0].BackgroundImage = null;
buttonList[1].BackgroundImage = null;
}
buttonList.Clear();
counter = 0;
}
}
You could set up a timer (see https://learn.microsoft.com/dotnet/api/system.windows.forms.timer) after the second button was pressed and reset the button images in the event handler of elapsed timer. (event is named Tick)

WPF - Queued mouse event trigger on next screen

Intro
I have a WPF application.
When i click/double click on a button to show next screen, this is captured with both MouseLeftButtonDown and MouseLeftButtonUp.
- MouseLeftButtonDown is making the button darker
- MouseLeftButtonUp is sending me to next screen
The problem:
If i "spam" or sometimes just click 2-3 (we say 3 times in this case) times on the button, it's start loading the next screen. When the next screen is shown, two mouse clicks is left in the queue and if the mouse is over another new button at the second screen, this is clicked on.
I tried with stuff like:
void LayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.OverrideCursor = Cursors.Wait;
if (this.IsVisible && this.IsLoaded)
OnButtonPatient();
}
but both properties is set to true.
I guess thats right since i can see the button when the mouse event triggers.
The events can be explained like:
3 mouse clicks
mouse cursor = waiting cursor
next screen is loaded
mouse cursor = normal
mouse cursor = waiting cursor
next button is clicked
How can i handle this?
I dont want mouse event that happend on a previously screen follow on to my next screen.
Greetings!
I tried a simple example using StackPanel as control. Although I am not sure why you are not using Button Click event if you are using a button (Why move on ButtonUp?)
private int count = 0;
private void StackPanel_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (count == 0 && (sender as StackPanel).IsMouseOver)
{
Mouse.OverrideCursor = Cursors.Wait;
count++;
}
e.Handled = true;
}
private void StackPanel_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (count == 1 && (sender as StackPanel).IsMouseOver)
{
Mouse.OverrideCursor = Cursors.Arrow;
count++;
}
e.Handled = true;
}
I would suggest checking the IsMouseOver property on your first window/screen when the MouseUp event fires. This would let you filter out events where the new window is blocking the first.
void LayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.OverrideCursor = Cursors.Wait;
if (this.IsVisible && this.IsLoaded && this.IsMouseOver)
OnButtonPatient();
}

How to use Key Event in Timer?

I have the following code, which on key press, starts moving the two labels from top of the form to the bottom, and after reaching the bottom of the form, it stops. I have done it using the timer. Here is the code
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
label1.Text = "Key Pressed: " + e.KeyChar;
//animate(sender, e);
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
Random random = new Random();
int X = random.Next(0, 1230);
int y = X;
label2.Location = new Point(X, 5);
label3.Location = new Point(X + 20, 5 + 20);
for (int i = 5; i <= 470; i++)
{
label2.Location = new Point(y, i);
label3.Location = new Point(y + 20, i + 20);
Thread.Sleep(1);
}
timer1.Stop();
}
Now during the animation (from the top of the form to the bottom), when I press the key, the animation restarts after reaching the bottom i.e. it completes the tick event and then and only then starts over or stop.
Now what I want is that whenever, during this movement of the labels from the top to bottom i.e. during the tick, if I press any key (or any specific key), the timer should stop.
In short, during the Timer1_Tick method, I want it to stop immediately on a key press.
I tried but couldn't get it to work. I hope that you folks here would help me sort this issue out and hope that you reply on your earliest. Thank you for your time!
The problem here is that you are not really using the Timer in the way that it's intended to be used. Ideally you would have an event that makes a change every time the tick event fires for a Timer.
Here you listen to the event and do several rounds of processing without ever returning from the handler at which point you stop the timer. This means the code will only ever process the tick event once instead of N times.
To fix this try breaking up the handler to do incremental work once per tick and only stop once the drawing is complete. This will also allow you to handle key events in between the tick events and stop the timer. The best place to break up the work is at the Thread.Sleep call (which itself should not appear in the handler)
Try it is so simple
Public Boolean tick = false;
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
tick = !tick;
label1.Text = "Key Pressed: " + e.KeyChar;
//animate(sender, e);
if(tick)
timer1.Start();
else
timer1.Stop();
}
First of all i recommend you to use keyDown and keyUp events instead of key press. To solve your problem: simple set a bool = true on keyDown and and the bool = false on keyUp. Now you can check the bool within you tick method and do whatever you want if you detect key is being pressed.

How to wait for a button to be clicked?

After a button is clicked in a Windows form application written in C#, how to wait for another button to be clicked? Meanwhile I am updating a datagridview dynamically by current information.
EDIT
After button1 is clicked, I want to repeatedly update a dataGridView with current information and when button2 is clicked I want to stop updating the dataGridView.
Use Timer Class.
public partial class Form1 : Form
{
System.Windows.Forms.Timer timer;
public Form1()
{
InitializeComponent();
//create it
timer = new Timer();
// set the interval, so it'll fire every 1 sec. (1000 ms)
timer.Interval = 1000;
// bind an event handler
timer.Tick += new EventHandler(timer_Tick);
//...
}
void timer_Tick(object sender, EventArgs e)
{
//do what you need
}
private void button1_Click(object sender, EventArgs e)
{
timer.Start(); //start the timer
// switch buttons
button1.Enabled = false;
button2.Enabled = true;
}
private void button2_Click(object sender, EventArgs e)
{
timer.Stop(); //stop the timer
// switch buttons back
button1.Enabled = true;
button2.Enabled = false;
}
From MSDN:
A Timer is used to raise an event at user-defined intervals. This
Windows timer is designed for a single-threaded environment where UI
threads are used to perform processing. It requires that the user code
have a UI message pump available and always operate from the same
thread, or marshal the call onto another thread.
When you use this timer, use the Tick event to perform a polling
operation or to display a splash screen for a specified period of
time. Whenever the Enabled property is set to true and the Interval
property is greater than zero, the Tick event is raised at intervals
based on the Interval property setting.
So you have button A and button B. When button A is pressed you want to wait for button B to be pressed, then do something special? Without more information the simplest way is something like this:
private void OnButtonAClicked(object sender, EventArgs e)
{
ButtonA.Enabled = false;
ButtonA.Click -= OnButtonAClicked;
ButtonB.Click += OnButtonBClicked;
ButtonB.Enabled = true;
}
private void OnButtonBClicked(object sender, EventArgs e)
{
ButtonB.Enabled = false;
ButtonB.Click -= OnButtonBClicked;
// Do something truly special here
ButtonA.Click += OnButtonAClicked;
ButtonA.Enabled = true;
}
This code will toggle(initial state; button A is enabled, button B is disabled), when button A is pressed, button B becomes enabled and processes events, etc.
Use the BackgroundWorker http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
It doesn't freeze the UI, support ProgressBar, also it can be async. At the link you will see a good example with same functional that you want (start some task by click on one button and cancel it by click on another button).

Strange issue when disabling a button

I've got a WinForm, which contains a button. In the button's click event, I call button1.Enabled = false and then a number of lines of code follow. After this code, I call button1.Enabled = true.
This is done so that the button cannot be pressed while the execution is being carried out. The strange thing is that while the button is disabled, if the user clicks on the button many times, the button is actually clicked.
Could anyone explain why this is happening? The code looks like this:
button1.Enabled = false
//Code
//Code
//Code
button1.Enabled = true
My guess is that you're actually doing a load of work in those lines of code, blocking the UI thread. You shouldn't do that - you should set the button to be disabled, then start off your work in a background thread (or using asynchronous calls, if most of the time is spent talking to a web service or something similar). Then when the work is finished, it should marshal a call back into the UI thread to re-enable the button.
(If that's not the problem, please show a short but complete program which demonstrates the problem.)
EDIT: Thanks to Sarwar's comments, I understand why you're getting the multiple events being fired - they're being queued up (due to the UI thread being blocked), and only processed after the button is re-enabled. So yes, if you avoid doing lots of work on the UI thread, it can handle the clicks on the disabled button, ignore them, and then there won't be a backlog when the button is re-enabled.
EDIT: For anyone who is interested in trying this themselves, here's my test program demonstrating the problem:
using System;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks; // For the fix below
class Program
{
static void Main()
{
Button button = new Button { Text = "Click me" };
button.Click += HandleClick;
Form form = new Form { Controls = { button } };
Application.Run(form);
}
static void HandleClick(object sender, EventArgs e)
{
Console.WriteLine("In click handler");
Button button = (Button) sender;
button.Enabled = false;
Thread.Sleep(10000);
button.Enabled = true;
Console.WriteLine("Finishing click handler");
}
}
And the fix using C# 5's async handling:
static async void HandleClick(object sender, EventArgs e)
{
Console.WriteLine("In click handler");
Button button = (Button) sender;
button.Enabled = false;
// Delay by 10 seconds, but without blocking the UI thread
await TaskEx.Delay(10000);
button.Enabled = true;
Console.WriteLine("Finishing click handler");
}
We encountered this same problem and like Jon mentioned, it was because the UI was blocked by the work we did inside the click event. When the UI resumed, it registered all the clicks which had happened when the UI was blocked.
Here's an another answer from Stack Overflow which provides some code showing how you can fix the problem.
I solved this using Application.DoEvents() to empty the queue before re enabling the button
AppButton.Enabled = false;
...
do some work
...
Application.DoEvents();
AppButton.Enable = true;

Categories

Resources