I need a sequence as follows:
button default state
button Down, "methods for button Down" execute and Button itself is disabled for a time.
button is enabled since "Disabling" time is elapsed, button Up, "methods for button Up" execute.
button default state
I've tried this code and it acts at its first part properly. But second part (Up) does not execute.
Could anyone help me?
private void btn1_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var btn = (Button)sender;
btn.IsEnabled = false; //Disable button.
var fooTimer = new System.Timers.Timer(5000); //Exceute after 5000 milliseconds
fooTimer.Elapsed += (fooTimer_s, fooTimer_e) =>
{
//It has to be dispatched because of thread crossing if you are using WPF.
Dispatcher.Invoke(() =>
{
btn.IsEnabled = true; //Bring button back to life by enabling it.
fooTimer.Dispose();
});
};
fooTimer.Start();
// methods for button Down go here
}
private void btn1_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
// methods for button Up go here
}
thanks in advance!
You could do this more easily in an async Click handler:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
button.IsEnabled = false;
await Task.Run(() =>
{
// perform time-consuming action
Thread.Sleep(5000); // just for test
});
button.IsEnabled = true;
}
Related
When doubleclicking a button that executes the code
await Navigation.PopModalAsync(true);
the program enters break mode i.e. crashes. How should it be handled so it wont crash when spamclicking?
EDIT
I changed the parameter to false and it works as expected. Is there any workaround to keep the animation set on true?
SOLVED
simple solution:
Boolean _istapped = false;
private async void Button_Clicked(object sender, EventArgs e)
{
if (_istapped)
return;
_istapped = true;
await Navigation.PopModalAsync(true);
_istapped = false;
}
The app crash because when you double click the button, Navigation.PopModalAsync will execute twice and it can't find the page at the second time.
Here is another simple way to solve this problem:
private async void Button_Clicked(object sender, EventArgs e)
{
Button btn = sender as Button;
btn.IsEnabled = false;
await Navigation.PopModalAsync(true);
//btn.IsEnabled = true;
}
Is it possible to implement in Button click event two executing one after another methods by timer?
Could anyone suggest something?
Sequence as follows:
Within button click
first method execution
some delay (e.g. 3 sec.)
second method execution.
thanks in advance!
Use an async Click event handler with await Task.Delay:
// class member
private TimeSpan clickActionDelay = TimeSpan.FromSeconds(3);
private async void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
button.IsEnabled = false;
firstAction();
// wait 3 seconds without blocking the UI thread
await Task.Delay(clickActionDelay);
secondAction();
button.IsEnabled = true;
}
private void firstAction()
{
...
}
private void secondAction()
{
...
}
I change my button's "Enabled" property to "false" but my button still catches it's click event. I put Thread.Sleep() method to imitate some process. While my button is greyed out, i click on it, and after current process is done it begins work again (because i clicked on it while it was greyed out)
Here's my code:
int i = 0;
public Form1()
{
InitializeComponent();
label1.Text = "0";
}
private void button1_Click(object sender, EventArgs e)
{
//first click
button1.Enabled = false;
i++;
Thread.Sleep(3000); //if i click twice more while button is greyed-out the app will be non-responsive for 9 second and then prints "3" to my label
label1.Text = i.ToString();
button1.Enabled = true;
}
How can i disable my button completely (not allowing it's events to rise, but visible)?
You are freezing the UI thread which prevent anything from happening UI-wise. You should considering using the TPL to do such work.
private async void button1_Click(object sender, EventArgs e)
{
//first click
button1.Enabled = false;
i++;
await Task.Delay(TimeSpan.FromSeconds(3));
label1.Text = i.ToString();
button1.Enabled = true;
}
The Thread.Sleep(3000) call is blocking the function so the button doesn't get disabled. A quick and dirty fix to this is to call Application.DoEvents(); directly after button1.Enabled = false;. This forces the application to process any waiting events and should ensure that the button is disabled.
If you plan to replace Thread.Sleep(3000) with a long running process then you should use a BackgroundWorker. You'll find it under Components in the designer Toolbox.
I am currently trying to create a hover effect on a custom control, where a panel (panel1) shows up after the mouse enters the control.
I have a timer that starts when the mouseleave event is raised, the interval is 250ms, and there is an onTick event that changes the visibility of the panel1 to false.
This all works. However, the buttons on panel1 do not always respond when clicked.
Here is the pertinent code - I will supply anything else that is required if I'm missing some information.
private void MagicCardViewer_MouseLeave(object sender, EventArgs e)
{
timer1.Start();
timer1.Interval = 250;
timer1.Tick += new EventHandler(timer1_TickOff);
timer1.Tick -= timer1_TickOn;
}
private void MagicCardViewer_MouseEnter(object sender, EventArgs e)
{
showPanel1();
}
public void showPanel1()
{
//show necessary controls
buttonDiscard.Show();
//show panel1
panel1.Visible = true;
ActiveControl = panel1;
}
public void hidePanel1()
{
panel1.Visible = false;
//hide controls
}
# region button events
private void buttonChoose_Click(object sender, EventArgs e)
{
Chosen = !Chosen;
if (Chosen)
{
callCardChosen();
}
}
private void buttonTap_Click(object sender, EventArgs e)
{
cards[0].ChangeTap();
DrawCardTap();
onCardChanged();
}
private void buttonActivate_Click(object sender, EventArgs e)
{
cards[0].TryActivate(0);
}
private void buttonDiscard_Click(object sender, EventArgs e)
{
cards[0].onDiscard();
}
# endregion
I think that is everything, but there is a lot of code to select from.
breakpoints don't trigger, the button flashes but nothing happens. If the timer interval is set very long, it works fine, but the point is for the button to vanish quickly once the mouse leaves the control. If the mouse is on the buttons, then the form reports it as having left the control.
To sum up - the buttons are not always processing when I click on them.
If you have the timer ticking every 250ms that could prevent the event on the mouse click.
I would check that you stop the timer after the tick if you no longer need it, and restart as I think you are doing when the user leaves the control or enter it again.
This could be why it works when you set a longer time interval.
I have this really little problem, but which can't be easily solved. Currently, my program has 2 buttons, a "Start" and a "Cancel". When the user clicks the start, the buttons should go instantly:
StartButton.IsEnabled = false;
CancelButton.IsEnabled = true;
But this occurs only when the BackgroundWorker has finished (all the code which will be ran after pressing the button), because the UI is always updated as last. There's no way I could add these commands to the "ProgressChanged" or "Completed" event of the backgroundworker. These events can take up to 10min to complete.
One easy way is to add these commands to the "ProgressChanged" part, and in the end "Complete" change their state again. But I'd like to avoid this, as the buttons should be showing their real state all the time, not after few "ProgressChanged" events. Of course there's always ways around, like not using the button's UI properties.
Is there any short solution for this?
It doesn't work to add the Button.Property changes to the ClickEvent. That's the main problem in this. I can easily use the "Completed" part of BGW to change the Button's back to match the starting state. The problem is to get them set right before all the events and BGW.
if you have a start button like:
this.StartButton = new System.Windows.Forms.Button();
then you can do
this.StartButton.Click += new System.EventHandler(this.button1_Click);
and then do
private void button1_Click(object sender, EventArgs e)
{
StartButton.IsEnabled = false;
CancelButton.IsEnabled = true;
Thread bg = new Thread(new ThreadStart( UpdateDatabase()));
bg.Start();
}
if you want the bg thread to send messages to the UI use the Invoke method like here
public delegate void UpdateUIHndler();
public void UpdateUI()
{
}
and do
if (InvokeRequired)
{
Invoke(new UpdateUIHndler(UpdateUI));
}
Take a look at a previous question of mine (quite similer). I should go for option 1.
ASP.NET Application log while code is running / progress bar
UI will only be delayed 5 seconds. Instead of text update the button styling using AJAX.
you can disable the start button in the click event of that button itself and enable it again it on RunWorkerCompleted event of BGW as shown below
BackgroundWorker _worker = new BackgroundWorker();
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
private void StartButton_Click(object sender, RoutedEventArgs e)
{
startButton.IsEnabled = false;
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
stratButton.IsEnabled = true;
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
//Your processing code
}