BeginInvoke cause application hang in BackgroundWorker - c#

I was trying to solve the problem in this Question but I ended up having another problem
in short words that question was asking how to load a huge file into textBox chunk by chunk,
so in back ground worker Do_work event I did this:
using (FileStream fs = new FileStream(#"myFilePath.txt", FileMode.Open, FileAccess.Read))
{
int bufferSize = 50;
byte[] c = null;
while (fs.Length - fs.Position > 0)
{
c = new byte[bufferSize];
fs.Read(c , 0,c.Length);
richTextBox1.AppendText(new string(UnicodeEncoding.ASCII.GetChars(c)));
}
}
that didn't work because a backgroundWorker can't affect UI elements and I need to use BeginInvoke to do it.
so I changed the code:
delegate void AddTextInvoker();
public void AddText()
{
using (FileStream fs = new FileStream(#"myFilePath.txt", FileMode.Open, FileAccess.Read))
{
int bufferSize = 50;
byte[] c = null;
while (fs.Length - fs.Position > 0)
{
c = new byte[bufferSize];
fs.Read(c , 0,c.Length);
richTextBox1.AppendText(new string(UnicodeEncoding.ASCII.GetChars(c)));
}
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
this.BeginInvoke(new AddTextInvoker(AddText));
}
there are two problems with this code.
1- it's taking longer and longer time to append the text (I think because of string immutability replacing the text over time will take longer)
2- on every addition the richTextBox will scroll down to the end which causing application hang.
the question is what can I do to stop the scrolling and application hang?
and what can I do to enhance string concatenation here?
Edit: after some testing and using Matt's answer I got this:
public void AddText()
{
using (FileStream fs = new FileStream(#"myFilePath.txt", FileMode.Open, FileAccess.Read))
{
int bufferSize = 50;
byte[] c = null;
while (fs.Length - fs.Position > 0)
{
c = new byte[bufferSize];
fs.Read(c , 0,c.Length);
string newText = new string(UnicodeEncoding.ASCII.GetChars(c));
this.BeginInvoke((Action)(() => richTextBox1.AppendText(newText)));
Thread.Sleep(5000); // here
}
}
}
when the loading pauses I can read and write without problems or hanging, once the text exceeded the the richTextBox size the loading will scroll down and will prevent me from continue.

One problem I see is that your background worker is, well, not doing any work in the background. It's all running on the UI thread. This may be why the UI thread is non-responsive.
I would refine your DoWork handler like so:
public void AddText()
{
using (FileStream fs = new FileStream(#"myFilePath.txt",
FileMode.Open, FileAccess.Read))
{
int bufferSize = 50;
byte[] c = null;
while (fs.Length - fs.Position > 0)
{
c = new byte[bufferSize];
fs.Read(c , 0,c.Length);
string newText = new string(UnicodeEncoding.ASCII.GetChars(c));
this.BeginInvoke((Action)(() => richTextBox1.AppendText(newText));
}
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
AddText();
}
What I've done is localized the use of BeginInvoke to the single UI call made in the handler. That way, all of the other work is done in the background thread. Maybe that will help with the UI thread becoming non-responsive.

Just call Application.DoEvents. That's the simplest thing, no need to worry about manually creating or synchronizing threads or background workers, yet your app stays responsive.
Also, try using File.ReadLines, which is a lazy-loaded enumerable, rather than manually using a FileStream. This, for example, works for me, and gives you everything you need in a loop and two lines of code.
private void button1_Click(object sender, EventArgs e)
{
foreach (var line in File.ReadLines(#"C:\Users\Dax\AppData\Local\Temp\dd_VSMsiLog0D85.txt", Encoding.ASCII))
{
richTextBox1.AppendText(line + "\r\n");
Application.DoEvents();
}
}
Alternately you can specify your chunk size and load it by that. This will run a bit faster, but take a bit longer (less than a second though) to read the full file at first.
private void button1_Click(object sender, EventArgs e)
{
var text = File.ReadAllText(#"C:\Users\Dax\AppData\Local\Temp\dd_VSMsiLog0D85.txt", Encoding.ASCII);
const int chunkSize = 1000000;
for (var i = 0; i < text.Length / chunkSize; ++i)
{
richTextBox1.AppendText(text.Substring(chunkSize * i, chunkSize));
Application.DoEvents();
}
}
Try this third option and see if your hang is caused by the file or by the loop:
void button1_Click(object sender, EventArgs e)
{
while(true)
{
richTextBox1.AppendText("a");
Application.DoEvents();
}
}

Ok that's not exactly the best solution but it do what I want, instead of using AppendText which will surly scroll down I used +=, and I still got the hang so needed the Sleep(100)
public void AddText()
{
using (FileStream fs = new FileStream(#"myFilePath.txt", FileMode.Open, FileAccess.Read))
{
int bufferSize = 50;
byte[] c = null;
while (fs.Length - fs.Position > 0)
{
c = new byte[bufferSize];
fs.Read(c , 0,c.Length);
string newText = new string(UnicodeEncoding.ASCII.GetChars(c));
this.BeginInvoke((Action)(() => richTextBox1.Text += newText));
Thread.Sleep(100);
}
}
}
this will actually not allow me to scroll down until loading is done,
I couldn't come up with a better idea.
Edit: And a work around to be able to read the text before loading is done is to set scrollBasrs on richTextBox to None and set the form autoscroll to true and in TextChanged event:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
using (Graphics g = CreateGraphics())
{
SizeF size = g.MeasureString(richTextBox1.Text, richTextBox1.Font);
richTextBox1.Width = (int)Math.Ceiling(size.Width) >
richTextBox1.Width ? (int)Math.Ceiling(size.Width) : richTextBox1.Width;
richTextBox1.Height = (int)Math.Ceiling(size.Height) >
richTextBox1.Height ? (int)Math.Ceiling(size.Height) : richTextBox1.Height;
}
}
this way I will be able to scroll down while loading. I hope someone find a better solution.

Try this:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (FileStream fs = new FileStream(
#"myFilePath.txt", FileMode.Open, FileAccess.Read))
{
int bufferSize = 50;
byte[] c = null;
while (fs.Length - fs.Position > 0)
{
c = new byte[bufferSize];
fs.Read(c, 0, c.Length);
Invoke(new Action(() =>
richTextBox1.AppendText(
new string(UnicodeEncoding.ASCII.GetChars(c)))));
}
}
}
The problem was the BeginInvoke, that call the AppendText async, see
http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspxhttp://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx
and
http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
Keep in mind that the Invoke method can throw exception, eg: if you close the form while loading text, so put it in try catch block and handle it.

BackgroundWorker CAN affect elements on the UI thread, since its events 'ProgressChanged' and 'RunWorkerCompleted' are executed on the calling thread. The following example increments an integer variable up to 10 on a separate thread, and communicates each increment back to the UI thread.
BackgroundWorker _worker;
private void button1_Click(object sender, EventArgs e)
{
_worker.RunWorkerAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
_worker = new BackgroundWorker();
_worker.WorkerReportsProgress = true;
_worker.DoWork += new DoWorkEventHandler(worker_DoWork);
_worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
for (int i = 0; i < 10; i++)
{
// pass value in parameter userState (2nd parameter), since it can hold objects
worker.ReportProgress(0, i); // calls ProgressChanged on main thread
}
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// get value, passed in DoWork, back from UserState
richTextBox1.AppendText(e.UserState.ToString());
}

Related

C# WPF MjpegStream. video appears to pause when writing and reading data on TCP/IP packets

My window should display the status of the video stream
and the data sent and received in tcpip.
Every two seconds, the video appears to pause
when writing and reading data on TCP/IP.
How can we solve this phenomenon?
For your information,
The application programs that deal with video stream,
the stream look natural regardless of the tcpip I send and receive.
enter code here
private MJPEGStream m_Stream;
private DispatcherTimer m_Timer = null;
public TcpClient clientTcp = new TcpClient;
public NetworkStream streamTcp = new NetworkStream;
public MainWindow()
{
InitializeComponent();
IpCamera();
OpenTcpIpCommuncation();
}
public void OpenTcpIpCommuncation()
{
var result= clientTcp.BeginConnect("192.168.0.3","24", null, null);
streamTcp = clientTcp.GetStream();
m_Timer = new DispatcherTimer();
m_Timer.Interval = TimeSpan.FromSeconds(2.0);
m_Timer.Tick += new EventHandler(TcpTimer_Tick);
m_Timer.Start();
}
private void TcpTimer_Tick(object sender, EventArgs e)
{
for (int=0; i<20; i++)
{
stream.Write(send_status_packet, 0, Length);
Thread.Sleep(50);
NumberOfBytes = stream.Read(data, 0, data.Length);
}
// label, text etc upate from data
}
public void IpCamera()
{
string sUrl = "http://192.168.0.100:8080" "//" + kCameraInfo.SubUrl;
m_Stream = new MJPEGStream(sUrl);
m_Stream.Login = "admin";
m_Stream.Password = "1234";
m_Stream.NewFrame += Camera_Frame;
m_Stream.Start();
}
private void Camera_Frame(object sender, NewFrameEventArgs eventArgs)
{
try
{
BitmapImage bi;
using (var bitmap = (Bitmap)eventArgs.Frame.Clone())
{
bi = bitmap.ToBitmapImage();
}
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate { imgCamera.Source = bi; }));
}
catch (Exception e)
{
}
}
Thread.Sleep blocks the UI thread.
Not sure why exactly you have this for loop, but it blocks the UI thread for at least 20 * 50 milliseconds, i.e. one second.
As a workaround, you may declare the Tick event handler async and use Task.Delay instead. You may perhaps also use the async versions of the Write and Read methods:
private async void TcpTimer_Tick(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
await stream.WriteAsync(send_status_packet, 0, Length);
await Task.Delay(50);
NumberOfBytes = await stream.ReadAsync(data, 0, data.Length);
}
...
}
It might also be better not have the loop at all, and run the timer at a shorter interval.

BackgroundWorker's progress bar is not working

The BackgroundWorker's progressbar is not updated while doing some tasks. What I would like to reach is progressbar moving while iterating through each file in DirectoryInfo. Suppose we have 20 files of ".sql" while first file completed it should be 5%, 10% and etc.
Here is my code.
private void CSV_Click(object sender, RoutedEventArgs e)
{
try
{
btnExtract.IsEnabled = false;
workerextract.RunWorkerAsync();
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.Message);
}
}
private void workerextract_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
this.Dispatcher.Invoke(() =>
{
DirectoryInfo di = new DirectoryInfo(txtQueryfolder.Text);
files = di.GetFiles("*.sql").Count();
currentfile = 0;
foreach (FileInfo fi in di.GetFiles("*.sql"))
{
// Open the text file using a stream reader.
using (StreamReader sr = new StreamReader(fi.FullName))
{
// Read the stream to a string, and write the string to the console.
string line = sr.ReadToEnd();
//System.Windows.MessageBox.Show(line);
ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name));
currentfile++;
}
int percentage = (currentfile + 1) * 100 / files;
workerextract.ReportProgress(percentage);
}
});
}
catch(Exception ex)
{
System.Windows.MessageBox.Show(ex.Message);
}
}
private void workerextract_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progressBarExtract.Value = e.ProgressPercentage;
}
private void workerextract_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnExtract.IsEnabled = true;
System.Windows.MessageBox.Show("CSV Data extraction finished!");
}
I found that
private void workerextract_ProgressChanged(object sender,
System.ComponentModel.ProgressChangedEventArgs e)
is called once at the end when 100%.
Also,
private void workerextract_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
never called as I do not see Message Box at the end.
So, I think I am doing something wrong here, could you please direct me on right way?
The problem was in wrapping whole DoWork inside Dispatcher.Invoke.
I need to wrap only those code where it is interacting with UI.
So I changed the code appropriately and it works.
private void workerextract_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
this.Dispatcher.Invoke(() =>
{
di = new DirectoryInfo(txtQueryfolder.Text);
});
files = di.GetFiles("*.sql").Count();
currentfile = 0;
foreach (FileInfo fi in di.GetFiles("*.sql"))
{
// Open the text file using a stream reader.
using (StreamReader sr = new StreamReader(fi.FullName))
{
// Read the stream to a string, and write the string to the console.
string line = sr.ReadToEnd();
this.Dispatcher.Invoke(() =>
{
//System.Windows.MessageBox.Show(line);
ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name));
});
currentfile++;
}
int percentage = (currentfile + 1) * 100 / files;
workerextract.ReportProgress(percentage);
}
}
catch(Exception ex)
{
System.Windows.MessageBox.Show(ex.Message);
}
}
Thanks to all for showing the direction.
Using this.Dispatcher.Invoke in the BackgroundWorker's DoWork event you are executing the whole operation in the UI thread; which is what BackgroundWorker born to avoid to do.
Also, you get an error unwrapping your code from the dispatcher because you are accessing an UI object, which is txtQueryfolder.
Just use:
private void workerextract_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
string queryFolder = e.Argument.ToString();
try
{
DirectoryInfo di = new DirectoryInfo(queryFolder);
files = di.GetFiles("*.sql").Count();
currentfile = 0;
foreach (FileInfo fi in di.GetFiles("*.sql"))
{
// Open the text file using a stream reader.
using (StreamReader sr = new StreamReader(fi.FullName))
{
// Read the stream to a string, and write the string to the console.
string line = sr.ReadToEnd();
//System.Windows.MessageBox.Show(line);
// ExtractToCSV shouldn't access to a UI object.
ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name));
currentfile++;
}
int percentage = (currentfile + 1) * 100 / files;
workerextract.ReportProgress(percentage);
}
}
catch (Exception ex)
{
// Don't use MessageBox in a thread different from the UI one. Just set the result (e.Result) and get that in the RunWorkerCompleted event.
// System.Windows.MessageBox.Show(ex.Message);
}
}
When you call the RunWorkerAsync method just add the parameter like below:
workerextrac.RunWorkerAsync(txtQueryfolder.Text);

Updating GUI from other thread

I'm trying to update a listbox from another thread, what is the simplest way to achieve this?
I tried Invoking the textbox, but it didn't work.
private void dowork()
{
TcpClient client = new TcpClient();
client.Connect("192.168.1.3", 10);
StreamWriter writer = new StreamWriter(client.GetStream());
StreamReader reader = new StreamReader(client.GetStream());
JObject o = new JObject();
o.Add("comando", 1);
o.Add("dir", #"C:\Users\klein\Desktop\Acionamentos");
writer.Write(o.ToString());
writer.Flush();
JArray array = JArray.Parse(reader.ReadToEnd());
for (int i = 0; i < array.Count; i++)
{
listBox1.Items.Add(array[i]); //update GUI from this thread
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(dowork);
t.Start();
}
I would use a BackgroundWorker, you can do your async stuff in DoWork, report your progress using bgworker.ReportProgress() and you will get the callback in ProgressChanged (I would call ReportProgress for every element processed), then you will be able to update your GUI controls.
The worker can also fire RunWorkerCompleted when it ends.
YourType arrayitem;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
TcpClient client = new TcpClient();
client.Connect("192.168.1.3", 10);
StreamWriter writer = new StreamWriter(client.GetStream());
StreamReader reader = new StreamReader(client.GetStream());
JObject o = new JObject();
o.Add("comando", 1);
o.Add("dir", #"C:\Users\klein\Desktop\Acionamentos");
writer.Write(o.ToString());
writer.Flush();
JArray array = JArray.Parse(reader.ReadToEnd());
int percentage;
for (int i = 0; i < array.Count; i++)
{
arrayitem = array[i];
percentage = ((i + 1)*100)/array.Count;
backgroundWorker1.ReportProgress(percentage);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
listBox1.Items.Add(arrayitem);
progressBar1.Value = e.ProgressPercentage; // in case you'd want to add a progressbar
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label1.Text = "Done";
}
Keep in mind your backgroundworker must have true in the WorkerReportProgress property.
You can use Control.Invoke to get on UI thread and then update the list box.
However, I suggest you look at using a BackgroundWorker.
You need to use Dispatcher.BeginInvoke. You can check this link to have better understanding on how to update the UI controls from different thread.
For example, if the listbox is named listbox1
for (int i = 0; i < array.Count; i++)
{
listBox1.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(delegate() { listBox1.Items.Add(array[i]) });
}

Background Worker Crashes Due to too Much Processing?

I've been struggling with a Background Worker for sometime, and I'm beginning to wonder if there are limits to what one can do with a bw. I'm trying to utilize a bw to handle a TCPIP exchange while updating the UI using its ProgressChanged Method. I know the UI update is ok, but my DoWork routine (shown below) sometimes causes the bw thread to disappear/stop working. Has anyone else had this problem?
private void TCPIP_DoWork(object sender, DoWorkEventArgs e)
{
int a = 0;
s.Send(System.Text.Encoding.ASCII.GetBytes("s"));
if (worker.CancellationPending == true)
{
s.Send(System.Text.Encoding.ASCII.GetBytes("t"));
}
else
{
try
{
a = s.Available;
s.Receive(bytes);
Thread.Sleep(25);
using (Stream fileStream = new FileStream(#sbpFile.Text,
FileMode.Append, FileAccess.Write, FileShare.None))
{
using (BinaryWriter bw = new BinaryWriter(fileStream))
{
if (a == 0)
Thread.Sleep(20);
else if (a < 1023)
{
bw.Write(bytes, 0, a);
Thread.Sleep(20);
}
else
{
bw.Write(bytes, 0, 1024);
Thread.Sleep(20);
}
}
}
}
catch(Exception e)
{
Console.WriteLine("{0} Exception.", e);
}
}
}
NOTE: The only reason those Thread.Sleep() operations are in there are because they seem to be the temporary fix for having the bw not trip over itself...
Try to check Error property on RunWorkerCompleted event handler. Maybe you get some exception, which in not handled by your code.
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
Console.WriteLine("{0} Exception.", e.Error);
// etc
}

Multi threading in WPF using C# (with background worker)

I have written code to save an image which is generated by the application. The size of the image is around 32-35 MB. While saving the image to a BMB file, it is taking a long time, around 3-5 secs. For this purpose, I have used a background worker but when running the background worker, it shows an error like..."can't access the object as it is created on different thread".
Following is the code:
private void btnSaveDesign_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
sfd.Title = "Save design as...";
sfd.Filter = "BMP|*.bmp";
if (sfd.ShowDialog() == true)
{
ww = new winWait();
ww.Show();
System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
fName = sfd.FileName;
cache = new CachedBitmap((BitmapSource)imgOut.Source, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
bw.RunWorkerAsync();
}
}
void bw_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
ww.Close();
}
void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(cache)); //here... it says cant access...
using (FileStream file = File.OpenWrite(fName))
{
encoder.Save(file);
}
}
I have declared "cache" as a global object. (A similar trick worked when I was programming in Windows Forms with VB.NET.)
ww is the wait window that I want to be displayed while the precess is being executed.
How to do this? Is there any other simple method for multi threading in WPF?
When WPF objects are created they are assigned to a Dispatcher object. This disallows any threads other than the creating thread to access the object. This can be circumvented by freezing the object by calling the freeze method. You would need to call Freeze on your bitmapsource object. Once you have frozen your object it becomes uneditable
Your problem comes about because you are accessing an object which is not created by the background worker thread. Normally this would happen if you access a UI control which is created in the main thread and accessed from different thread.
Use the code below.
Dispatcher.Invoke
(
new Action(
delegate()
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(cache));
using (FileStream file = File.OpenWrite(fName))
{
encoder.Save(file);
}
}
)
);
I think you have to pass cache as a parameter to the new thread:
bw.RunWorkerAsync(cache);
and get it from the DoWork method:
var cache=(CacheType) e.Argument;
.NET framework provides a simple way to get started in threading with
the BackgroundWorker component. This wraps much of the complexity and
makes spawning a background thread relatively safe. In addition, it
allows you to communicate between your background thread and your UI
thread without doing any special coding. You can use this component
with WinForms and WPF applications. The BackgroundWorker offers
several features which include spawning a background thread, the
ability to cancel the background process before it has completed, and
the chance to report the progress back to your UI.
public BackgroudWorker()
{
InitializeComponent();
backgroundWorker = ((BackgroundWorker)this.FindResource("backgroundWorker"));
}
private int DoSlowProcess(int iterations, BackgroundWorker worker, DoWorkEventArgs e)
{
int result = 0;
for (int i = 0; i <= iterations; i++)
{
if (worker != null)
{
if (worker.CancellationPending)
{
e.Cancel = true;
return result;
}
if (worker.WorkerReportsProgress)
{
int percentComplete =
(int)((float)i / (float)iterations * 100);
worker.ReportProgress(percentComplete);
}
}
Thread.Sleep(100);
result = i;
}
return result;
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
int iterations = 0;
if (int.TryParse(inputBox.Text, out iterations))
{
backgroundWorker.RunWorkerAsync(iterations);
startButton.IsEnabled = false;
cancelButton.IsEnabled = true;
outputBox.Text = "";
}
}
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
// TODO: Implement Cancel process
this.backgroundWorker.CancelAsync();
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// e.Result = DoSlowProcess((int)e.Argument);
var bgw = sender as BackgroundWorker;
e.Result = DoSlowProcess((int)e.Argument, bgw, e);
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
workerProgress.Value = e.ProgressPercentage;
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
outputBox.Text = "Canceled";
workerProgress.Value = 0;
}
else
{
outputBox.Text = e.Result.ToString();
workerProgress.Value = 0;
}
startButton.IsEnabled = true;
cancelButton.IsEnabled = false;
}

Categories

Resources