How should I know if an application is working or processing something? Lets say that I'm trying to write a huge data into a file, on that time the application is not responding. I want to know the application current status.
Use BackgroundWorker componenet to process huge data in background thread. Notify user about progress via ProgressChanged event.
Sample:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
}
private void WriteDataButton_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= numberOfIterations; i++)
{
// write part of data
backgroundWorker1.ReportProgress(i * 100 / numberOfIterations);
}
}
// This event handler updates the progress.
private void backgroundWorker1_ProgressChanged(
object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
// This event handler deals with the results of the background operation.
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Huge data was written");
}
}
Related
I have a board which I am trying to communicate with. When I give it some commands it should return string messages back and should get posted in a textbox. My problem is when the device has to return multiple lines of text only 1 of the lines gets posted. I have tried also with ReadExisting instead of ReadLine but after one command I get only empty strings back.
public partial class Form1 : Form
{
private string x;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
serialPort1.Open();
timer1.Start();
}
private void button1_Click(object sender, EventArgs e)
{
serialPort1.WriteLine(textBox1.Text);
textBox1.Clear();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(x))
{
}
else
{
textBox2.AppendText(x + "\n\r");
x = "";
}
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
x = serialPort1.ReadLine();
//x = serialPort1.ReadExisting();
}
private void Form1_Closing(object sender, EventArgs e)
{
serialPort1.Close();
timer1.Stop();
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
}
You're always better off avoiding DataReceived and just using BaseStream. Like this:
private async void Form1_Load(object sender, EventArgs e)
{
serialPort1.Open();
using (var reader = new StreamReader(serialPort1.BaseStream)) {
while (serialPort1.IsOpen) {
string x = await reader.ReadLineAsync();
textBox2.AppendText(x + "\r\n");
}
}
}
The await keyword silently manages synchronization back to the UI thread -- you don't need Invoke, you don't get cross-thread failures, you don't get a second invocation of your event handler triggered while the first one is still running, you don't get race conditions from multiple threads accessing the same variable. Much easier to get right.
As a style issue, I wouldn't put this code directly in your Form Load event handler, I would put it in a suitably named helper function (OpenAndReadSerial() perhaps) and call that from overridden OnLoad().
I am a beginner in C# and WPF and I am building this project in which I have to trigger when the mouse is moved. Under some conditions, I have to use it as a background worker. I want to call the mouse_Moved method in the background, but I don't know how to actually do that . Can anyone help me please? This is my code so far:
public MainWindow()
{
InitializeComponent();
mouse = new MouseInput();
mouse.MouseMoved += mouse_MouseMoved;
}
void mouse_MouseMoved(object sender, EventArgs e)
{
//The code that I need
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
//where I want to call the mouse_Moved method
}
Create a method and call it from both:
void mouse_MouseMoved(object sender, EventArgs e)
{
DoMouseMovedWork();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
DoMouseMovedWork();
}
private DoMouseMovedWork()
{
//The code I need
}
I have the problem with changing the timer Interval in backgroundworker's DoWork event. While changing the Interval by clicking the Button, Timer stops and doesn't start again.
Does anyone know how to solve this problem?
Simple code:
public Form1()
{
InitializeComponent();
timerTest.Tick += new EventHandler(timerTest_Tick);
timerTest.Interval = 1000;
timerTest.Start();
}
private void buttonTest_Click(object sender, EventArgs e)
{
push = true;
}
private void timerTest_Tick(object sender, EventArgs e)
{
ticks++;
labelTest.Text = ticks.ToString();
if(running == false)
{
running = true;
backgroundWorkerTest.RunWorkerAsync();
}
}
public void activate()
{
timerTest.Stop();
timerTest.Interval = 4000;
timerTest.Start();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
while(running)
{
if(push == true)
{
activate();
}
}
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
running = false;
}
}
}
You never set push to false.
Therefore, the following code:
while(running)
{
if(push == true)
{
activate();
}
}
will continuously call activate() in a tight loop. activate() stops the timer and then restarts it, and the time between calls to it will be far less than the timer interval. Therefore, the timer will never be left long enough to fire.
In any case, why don't you call activate() directly from buttonTest_Click()?
I can see this was asked a long time ago, but for the reference:
When it comes to timers or threadings in general (remember timer is system.threading) in combination with background workers (tasks) Never ever try to change a thread proerties randomly without knowing what the worker is doing.
It is always a good practice when assigning the DoWork handler to prepare the background worker Progress and Complete handlers as well.
At each cycle, report the progress or the completion, this would give you the chance to do your checks and modify another thread properties if needed.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!worker.CancellationPending)
{
// do task 1 as per the timer1 interval
// do task 2 as per such and such .....
// if I call ChangeInterval here I'll be fiddling with another thread when
// this is still in progress
// that a full loop, Progress will be reported now
}
}
private void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e)
{
// Now as the Do work is not in progress
// do something
// check if the user wanted to change the interval ?
// if yes then
ChangeInterval(6000);
// here the progress reporting is done so it will go back to DoWork with the
// NewInterval Value in place and the timer enabled
}
private void ChangeInterval(int NewInterval)
{
timer1.Enabled =false;
timer1.Interval = NewInterval;
timer1.Enabled = true;
}
Try invoke your activate method with the UI Thread's Dispatcher. (Assuming Win Forms?)
this.Invoke(new Action(activate));
Reason is that your timer is a UI control and you're updating the Interval on a separate thread. This will throw a Cross-Thread exception.
Why don't you see the exception? When the DoWork method in your BackgroundWorker throws an exception, it will be propogated to the Completed method. So you should always look at e.Error to see if an exception occurred.
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
// Oh no something went wrong...
}
running = false;
}
It took me a while, but I found out what was wrong. I'll post you a working code, just in case someone will have the same problem.
public partial class Form1 : Form
{
public int ticks = 0;
public bool running = false;
public bool push = false;
public Form1()
{
InitializeComponent();
timerTest.Tick += new EventHandler(timerTest_Tick);
timerTest.Interval = 1000;
timerTest.Start();
}
private void buttonTest_Click(object sender, EventArgs e)
{
push = true;
}
private void timerTest_Tick(object sender, EventArgs e)
{
ticks++;
labelTest.Text = ticks.ToString();
if(running == false)
{
running = true;
backgroundWorkerTest.RunWorkerAsync();
}
}
public void activate()
{
ZmienIntervalNaAwaryjny = true;
}
public bool ZmienIntervalNaAwaryjny = false;
private void DoWork(object sender, DoWorkEventArgs e)
{
if(push == true)
{
activate();
}
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
if(ZmienIntervalNaAwaryjny == true)
{
timerTest.Stop();
timerTest.Interval = 12000;
timerTest.Start();
}
ZmienIntervalNaAwaryjny = false;
running = false;
}
}
Hey everyone, can someone let me know what they see wrong with this code ?
it throws "Cross-thread operation not valid" exception, on
_DialogueThread.Start();
but if i remove "owner" from
_progressDialogue = new Progresser{Owner = _owner, StartPosition = FormStartPosition.CenterParent};
the exception wont be thrown but the progressDialouge will be shown then hidden right away .
now i understand why this the error is thrown if i set the progressDialouge.Owner to a parent form that was created on a different thread. but why dose the form disappears when i dont ? what am i doing wrong ?
thanks
class Sampleer : BackgroundWorker
{
private Progresser _progressDialogue;
private Thread _DialogueThread;
private Form _owner;
private bool _SampleSuccess;
public Sampleer(Form owner)
{
_owner = owner;
_progressDialogue = new Progresser{Owner = _owner, StartPosition = FormStartPosition.CenterParent};
_progressDialogue.Closed += ProgressDialogueClosed;
WorkerReportsProgress = true;
WorkerSupportsCancellation = true;
DoWork += Sampleer_DoWork;
RunWorkerCompleted += Sampleer_RunWorkerCompleted;
ProgressChanged += Sampleer_ProgressChanged;
}
private void Sampleer_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//UPDATE STATUS CODE IS HERE
}
void ProgressDialogueClosed(object sender, EventArgs e)
{
CancelAsync();
Dispose();
}
void Sampleer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//FINISH PROCESS
}
void Sampleer_DoWork(object sender, DoWorkEventArgs e)
{
_DialogueThread = new Thread(_progressDialogue.Show);
_DialogueThread.Start();
//DO LONG PROCESS HERE
}
}
In your action (button click), i would create the progress dialog, and then fire off the background worker. The background worker then reports back to the dialog in the ProgressChanged event.
public partial class MainWindow : Window {
private void btnDoSomething_Click(object sender0, RoutedEventArgs e0) {
_progressDialogue = new Progresser{Owner = _owner, StartPosition = FormStartPosition.CenterParent};
_progressDialogue.Closed += ProgressDialogueClosed;
_progressDialogue.Show();
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += delegate(object sender, DoWorkEventArgs e) {
DoSomething();
e.Result = result;
};
worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e) {
progressDialogue.Update()
};
worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
progressDialogue.Close()
};
worker.RunWorkerAsync(new CustomArgs() {
SomeValue = txtValue.Text,
});
}
}
There are a few mistakes in your approach. Let me point them out one by one.
You inherit BackgroundWorker. That is fine. But you create another thread inside (_DialogueThread). There is no need. DoWork() method runs in a separate thread.
You create/use/manipulate a UI element in another thread. Now, always remember. A Thread never creates a UI element. Its the other way around. A UI element creates a Thread. Progresser in your case should be creating a new Thread or using BackgroundWorker to do any background work you require.
`
Yes decyclone is right, there are many mistakes in the code and in your approach to solution.
You are inherting BackgroundWorker type but subscribing to its own events?
Instead override the methods that are responsible for raising the event in your class.
ex: Instead of subscribing to DoWork, override OnDoWork method.
I've created a sample application, in which a Form (when performing a background task) shows another Form (BackgroundWorkUINotification) and starts the background task in BackgroundWorker thread. The BackgroundWorkUINotification notifies the main form when the Form's CancelButton is clicked.
The main Form when notified, closes the notifier and cancels the background task.
Code below: BackgroundWorkUINotification Form
public partial class BackgroundWorkUINotification : Form
{
public event EventHandler CancelClicked;
public BackgroundWorkUINotification()
{
InitializeComponent();
// call code to animate progress bar..
// probably in another BackgroundWorker that reports progress..
this.cancelButton.Click += HandleCancelButtonOnClick;
}
protected virtual void OnCancelClicked()
{
if (CancelClicked != null)
this.CancelClicked(this, EventArgs.Empty);
}
private void HandleCancelButtonOnClick(Object sender, EventArgs e)
{
this.OnCancelClicked();
}
}
Main Form
public partial class Form1 : Form
{
private BackgroundWorker backgroundWorker;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.backgroundWorker = new BackgroundWorker();
this.backgroundWorker.DoWork += HandleBackgroundWorkerOnDoWork;
this.backgroundWorker.RunWorkerCompleted += HandleBackgroundWorkerOnRunWorkerCompleted;
this.backgroundWorker.WorkerSupportsCancellation = true;
}
private void HandleDataRequest()
{
// show UI notification...
BackgroundWorkUINotification backgroundWorkUINotification = new BackgroundWorkUINotification();
backgroundWorkUINotification.CancelClicked += HandleBackgroundWorkUINotificationOnCancelClicked;
backgroundWorkUINotification.Show(this);
// start the background worker
this.backgroundWorker.RunWorkerAsync();
}
private void HandleBackgroundWorkUINotificationOnCancelClicked(Object sender, EventArgs e)
{
// UI notification Form, Cancelled
// close the form...
BackgroundWorkUINotification backgroundWorkUINotification = (BackgroundWorkUINotification)sender;
backgroundWorkUINotification.Close();
// stop the background worker thread...
if (backgroundWorker.IsBusy)
backgroundWorker.CancelAsync();
}
private void HandleBackgroundWorkerOnRunWorkerCompleted(Object sender, RunWorkerCompletedEventArgs e)
{
}
private void HandleBackgroundWorkerOnDoWork(Object sender, DoWorkEventArgs e)
{
// do some work here..
// also check for CancellationPending property on BackgroundWorker
}
}
Some days ago I had the same trouble.
This was helped me: "MSDN. How to: Make Thread-Safe Calls to Windows Forms Controls"
I used first aproach (checking InvokeRequired) because it is easiest way.
Hope it is helpful advise!
now program show Messagebox and wait user decision.
How make, that program don't wait?
Show Messagebox, ant keep going.
(I do not need a user action. I just need to show text)
Or maybe a better option than to report the information to a new window?
I hope to understand my problem.
quick and easy way: use a BackgroundWorker to host your long running job and use the worker's events to pop up messages in the UI thread.
edit: might want to display the messages in the form of a message log.
public partial class MainWindow : Form
{
#region Constructor
public MainWindow()
{
InitializeComponent();
}
#endregion
#region Events
private void button_Click(object sender, EventArgs e)
{
listBox.Items.Add("Job started!");
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10; i++)
{
// send data from the background thread
backgroundWorker.ReportProgress(0, i);
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// communicate with UI thread
listBox.Items.Add(string.Format("Received message: {0}", e.UserState));
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
listBox.Items.Add("Job done!");
}
#endregion
}
Create a new Form, put some controls on it and show it to the user:
new PopupForm().Show();
If you just have to show a notification window, then this would be a help that I wrote sometime back; works like Outlook like notification window.