I want this part of my program (I showed in code by "//" sign before the line) to wait until button3 is clicked to resume.
private void button2_Click(object sender, EventArgs e)
{
if (this.textBox3.Text != "")
{
this.listView1.Items.Clear();
//this.listView1.Items.Add(this.textBox3.text);
}
}
Seems like you want something like this:
private void button2_Click(object sender, EventArgs e)
{
if (this.textBox3.Text != "")
{
this.listView1.Items.Clear();
button3.Click += Function;
}
}
private void Function(object sender, EventArgs e)
{
this.listView1.Items.Add(this.textBox3.text);
button3.Click -= Function;
}
So we'll start out with this helper method that produces a task that will be completed when a button is clicked:
public static Task WhenClicked(this Button button)
{
var tcs = new TaskCompletionSource<bool>();
EventHandler handler = null;
handler = (sender , args) =>
{
tcs.SetResult(true);
button.Click -= handler;
};
button.Click += handler;
return tcs.Task;
}
Using this, along with await from C# 5.0, we can create code that reads just like what you requested, even though it produced code similar to what the other answers have (thus maintaining asynchrony and not blocking the UI thread).
private async void button2_Click(object sender, EventArgs e)
{
if (this.textBox3.Text != "")
{
this.listView1.Items.Clear();
await button3.WhenClicked();
this.listView1.Items.Add(this.textBox3.text);
}
}
Related
private void Form1_Load(object sender, EventArgs e)
{
webbrowser.Navigate(url);
}
private async void buttonDownload_Click(object sender, EventArgs e)
{
await Task.Run(()=> {
MessageBox.Show(webBrowser.Document.GetElementsByTagName("body")[0].InnerHtml);
});
}
The error displayed "The specified conversion is not valid" i read about it and it something because is another thread not ui thread, do you know a simple and short way to make this work ?
Edit
You must subscribe to webBrowser.DocumentCompleted event
webBrowser.DocumentCompleted += completed;
private void completed(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (sender is WebBrowser w)
{
var a = w.Document.GetElementsByTagName("body")[0].InnerHtml;
}
}
private async void buttonDownload_Click(object sender, EventArgs e){
webBrowser.Navigate(url);
}
I would rewrite your download method like this (I assume the webBrowser object is doing some 'long' computation and you don't want to block the UI thread)
private async void buttonDownload_Click(object sender, EventArgs e)
{
var htmlString = await Task.Run(()=> {
return webBrowser.Document.GetElementsByTagName("body")[0].InnerHtml;
});
MessageBox.Show(htmlString);
}
Also, are you sure that is the correct error? perhaps you overlooked some inner exception, which could explain more
I want to know the the task status runnning in A button event from the other button click.
Like this.
private void button1_Click(object sender, EventArgs e)
{
Task.Run(()=>{
//The method to take long time
//For example
Thread.Sleep(5000)
;});
}
private coid button2_Click(object sender, EventArgs e)
{
//until 5000ms
//the method to know the above task status (Runnning....)
//after 5000ms
//the method to know the above task status (Conpleted....)
}
It's not entirely clear what you're trying to achieve, but if you want to check the status of the task, you can get its reference when calling Task.Run()
private Task _task;
private void button1_Click(object sender, EventArgs e)
{
_task = Task.Run(() => Thread.Sleep(5000));
}
private void button2_Click(object sender, EventArgs e)
{
if (_task?.Status == TaskStatus.RanToCompletion)
//do something
}
The answer is as vague as the question, so if you could give me a bit more details, I could come up with a better more tailored answer.
Again, it's very unclear what you're looking for here...but this is an expanded version of Faylit's example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Task T = null;
private void Form1_Load(object sender, EventArgs e)
{
updateStatus();
}
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
await (T = Task.Run(() =>
{
updateStatus();
System.Threading.Thread.Sleep(5000);
}));
button1.Enabled = true;
updateStatus();
}
private void button2_Click(object sender, EventArgs e)
{
updateStatus();
}
private void updateStatus()
{
if (label1.InvokeRequired)
{
label1.Invoke((MethodInvoker)delegate
{
updateStatus();
});
}
else
{
if (T == null)
{
label1.Text = "Task not started.";
}
else if (!T.IsCompleted)
{
label1.Text = "Task running...";
}
else
{
label1.Text = "Task completed.";
}
}
}
}
It might give you some more ideas.
On .NET Windows form, I have Background worker component that works fine. I have 5 forms, that has basically same Background worker on it with same code.
Can I extract this code to other class and somehow use it, considering this is an event? This is code I have on form. It takes 20 lines of code, and it would be nice if this can be refactored. Note: as you can see, I have already put it to other class BackgroundWorkerHelper, but can I also somehow refactor this events on Background worker, so that it is in other class as well, this way code is less and reused.
private void RunBackgroundWorker(string infoLabelText, int imageIndex)
{
BackgroundWorkerHelper.Run(backgroundWorker, progressBar, infoLabelText, imageIndex);
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorkerHelper.DoWork(backgroundWorker);
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BackgroundWorkerHelper.ProgressChanged(sender, e, progressBar);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorkerHelper.RunWorkerCompleted(sender, e, progressBar);
}
Note: for now I would like to avoid using user control. I know I could do it, but then you have code that handles placing user control and so on. I am still not very good in it.
Here is solution, thanks to rory who gave me idea how to do it. First, I made this class:
public class BackgroundWorkerHelper
{
private static string _infoLabelText = string.Empty;
public BackgroundWorker _BackgroundWorker;
private BarEditItem _marqueeInfo;//this is marquee progress bar
public BackgroundWorkerHelper(BarEditItem marqueeInfo)
{
_marqueeInfo = marqueeInfo;
_BackgroundWorker = new BackgroundWorker();
_BackgroundWorker.WorkerReportsProgress = true;
_BackgroundWorker.WorkerSupportsCancellation = true;
_BackgroundWorker.DoWork += backgroundWorker_DoWork;
_BackgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
_BackgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
}
public void Run(string labelText, int imageIndex)
{
_marqueeInfo.Caption = labelText;
_marqueeInfo.ImageIndex = imageIndex;
if (!_BackgroundWorker.IsBusy)
_BackgroundWorker.RunWorkerAsync();
else
_marqueeInfo.Caption = "Busy processing saving data, please wait...";
}
public void DoWork()
{
for (int i = 0; i <= 5; i++)
{
_BackgroundWorker.ReportProgress(i); // call backgroundWorker_ProgressChanged event and pass i (which is e argument e.ProgressPercentage) to update UI controls
Thread.Sleep(250);
}
}
public void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
_marqueeInfo.Visibility = BarItemVisibility.Always;
}
public void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_marqueeInfo.Visibility = BarItemVisibility.Never;
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
DoWork();
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressChanged(sender, e);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RunWorkerCompleted(sender, e);
}
then in FORM, in class level above constructor place
private readonly BackgroundWorkerHelper _backgroundWorkerHelper;
then in Form Constructor instantiate class
_backgroundWorkerHelper = new BackgroundWorkerHelper(marqueeInfo);
and then I just call it in my form
_backgroundWorkerHelper.Run("Saving", 14);
I have a user control with some buttons (tmNewItem, tmEdit, tmInsert)
I write a clickButton event for them.
for example:
public void btnEdit_Click(object sender, EventArgs e)
{
btnNew.Enabled = false;
btnEdit.Enabled = false;
}
I used this user control in another project and write another method for the buttons and assign it to the usr control:
public void DTedit(object sender, EventArgs e)
{
}
private void UserControl_Load(object sender, EventArgs e)
{
DT_Navigator.btnCancel.Click += new EventHandler(DTedit);
}
and now, when I run the project and press btnEdit button, the first time, btnEdit_Click will execute and after that DTedit. can i change it? I mean the first time DTedit (that I define it in my project) run, and after it btnEdit_Click (that I define it in the user control) run?
how can I do that?
Try this
public void DTedit(object sender, EventArgs e)
{
//Place your code here
DT_Navigator.btnCancel.Click -= new EventHandler(DTedit); //This will remove handler from the button click and it will not be executed next time.
}
private void UserControl_Load(object sender, EventArgs e)
{
DT_Navigator.btnCancel.Click += new EventHandler(DTedit);
}
Suggested Code
//User control
public event CancelEventHandler BeginEdit;
public event EventHandler EndEdit;
private btnYourButton_Click(object sender, EventArgs e)
{
CancelEventArgs e = new CancelEventArgs();
e.Cancel = false;
if (BeginEdit != null)
BeginEdit(this, e);
if (e.Cancel == false)
{
if (EndEdit != null)
EndEdit(this, new EventArgs);
//You can place your code here to disable controls
}
}
I have tried all day, and looked up all kinds of ideas... with no real help.
When I press a button, like "JOG", which would move a CNC Machine axis continuously, as long a the button is pressed, then when released, it would stop.
To test this I am using a "picuture / LED" which when I press and hold, should be on... and when I release, it should turn off.
Pressed Button should = only while pressed, do something.
Release of same button = stop doing whatever you were doing now.
I am sure for you advanced folks, this is maybe 101... but for me... it is eating my lunch... help?
You can use the MouseDown and MouseUp events. When the MouseDown event is hit, call a method that loops and performs your action. Once MouseUp is hit, stop the loop.
private bool _run = false;
public void button_MouseDown(object sender, EventArgs e)
{
_run = true;
MyAction();
}
public void button_MouseUp(object sender, EventArgs e)
{
_run = false;
}
public void MyAction()
{
while(_run)
{
//You actions
}
}
Note that the above example will hog up the UI thread. You should run it on another thread using a BackgroundWorker or something similar.
Generically, have a look at the mouse up and down events. I would have it call some function asynchronously (not on the UI thread) when the mouse is down. And stop it when the mouse up event fires. System.Threading has some nice models for this. Try googling around there.
You are wanting to start and stop a thread where the procedure is looping performing your action.
I'd make my own subclass, something like this:
public class RepeatButton : Button
{
readonly Timer timer = new Timer();
public event EventHandler Depressed;
public virtual TimeSpan Interval
{
get { return TimeSpan.FromMilliseconds(timer.Interval); }
set { timer.Interval = (int)value.TotalMilliseconds; }
}
public RepeatButton()
{
timer.Interval = 100;
timer.Tick += delegate { OnDepressed(); };
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
timer.Stop();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
timer.Start();
}
protected virtual void OnDepressed()
{
var handler = this.Depressed;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
This allows your code to be asynchronous but also the Depressed event would be invoked on the UI thread still.
Consider Space bar to trigger button down and up as well.
this.button1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.button1_MouseDown);
this.button1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.button1_MouseUp);
this.button1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.button1_KeyDown);
this.button1.KeyUp += new System.Windows.Forms.KeyEventHandler(this.button1_KeyUp);
private void button1_MouseDown(object sender, MouseEventArgs e)
{
led18.Show();
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
led18.Hide();
}
private void button1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Space && e.Alt==false && e.Control==false && e.Shift==false)
{
led18.Show();
}
}
private void button1_KeyUp(object sender, KeyEventArgs e)
{
led18.Hide();
}
Thanks all, this is about as simple as I could get it.
Button and Mouse control mixed togather, needs mouse handling... which is added in the button properties, which will add the code to the designer.
private void button2_MouseDown(object sender, MouseEventArgs e)
{
led18.Show();
}
private void button2_MouseUp(object sender, MouseEventArgs e)
{
led18.Hide();
}
//below get automatically put into the design file...
this.button1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.button1_MouseDown);
this.button1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.button1_MouseUp);