Exception when closing Form (thread + invoke) - c#

I have just started to learn about threads and methodinvoking in c#, but I have come across a problem which I couldn't find the solution of.
I made a basic C# form program which keeps updating and displaying a number, by starting a thread and invoke delegate.
Starting new thread on Form1_load:
private void Form1_Load(object sender, EventArgs e)
{
t = new System.Threading.Thread(DoThisAllTheTime);
t.Start();
}
Public void DoThisAllTheTime (which keeps updating the number) :
public void DoThisAllTheTime()
{
while(true)
{
if (!this.IsDisposed)
{
number += 1;
MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
this.Invoke(yolo);
}
}
}
Now when I click the X button of the form, I get the following exception:
'An unhandled exception of type 'System.ObjectDisposedException' occurred in System.Windows.Forms.dll
Can't update a deleted object'
While I actually did check if the form was disposed or not.
EDIT: I added catch (ObjectDisposedException ex) to the code which fixed the problem.
Working code:
public void DoThisAllTheTime()
{
while(true)
{
number += 1;
try {
MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
this.Invoke(yolo);
}
catch (ObjectDisposedException ex)
{
t.Abort();
}
}
}

Your call to this.IsDisposed is always out of date. You need to intercept your form closing event and stop the thread explicitly. Then you won't have to do that IsDisposed test at all.
There are many ways you can do this. Personally, I would use the System.Threading.Tasks namespace, but if you want to keep your use of System.Threading, you should define a member variable _updateThread, and launch it in your load event:
_updateThread = new System.Threading.Thread(DoThisAllTheTime);
_updateThread.Start();
Then in your closing event:
private void Form1_Closing(object sender, CancelEventArgs e)
{
_stopCounting = true;
_updateThread.Join();
}
Finally, replace the IsDisposed test with a check on the value of your new _stopCounting member variable:
public void DoThisAllTheTime()
{
MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
while(!_stopCounting)
{
number += 1;
this.Invoke(yolo);
}
}

Just put this override in your form class:
protected override void OnClosing(CancelEventArgs e) {
t.Abort();
base.OnClosing(e);
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Thread.CurrentThread.Abort();
}

Related

C# Background Worker Append TextBox

first off I'd like to say I'm brand new to C# so I am not too aware with how the background worker is supposed to be implemented. I have a GUI program that basically pings a domain a returns the response to a textbox. I am able to get it to work normally, however, it freezes the code because it is running on the same thread which is why I am trying to implement a background worker.
Here is the basic setup
private void button1_Click(object sender, EventArgs e)
{
url = textBox1.Text;
button1.Enabled = false;
button2.Enabled = true;
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerAsync();
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
do
{
if (bgWorker.CancellationPending)
break;
Invoke((MethodInvoker)delegate { monitor(); });
} while (true);
}
public void monitor()
{
textBox2.AppendText("Status of: " + url + "\n");
Status(url);
System.Threading.Thread.Sleep(30000);
}
private void Status(string url)
{
// This method does all the ping work and also appends the status to the Text box as it goes through , as OK or down
}
I have not worked with bgworkers before and as you can imagine it's confusing. I've looked at tons of other articles and I can't seem to get it. Sorry if the code looks crazy, I'm trying to learn.
Use Microsoft's Reactive Framework (NuGet "System.Reactive.Windows.Forms" and add using System.Reactive.Linq;) and then you can do this:
private void button1_Click(object sender, EventArgs e)
{
var url = textBox1.Text;
Observable
.Interval(TimeSpan.FromMinutes(0.5))
.SelectMany(_ => Observable.Start(() => Status(url)))
.ObserveOn(this)
.Subscribe(status => textBox2.AppendText("Status of: " + status + "\n"));
}
You then just need to change Status to have this signature: string Status(string url).
That's it. No background worker. No invoking. And Status is nicely run on a background thread.
You've got several mistakes. First,
Invoke((MethodInvoker)delegate
{
monitor();
});
will call monitor() on your UI thread. In almost all cases you should not call methods on other threads. You especially should not call methods that block or do anything that takes more than a few milliseconds on your UI thread, and that is what this does:
System.Threading.Thread.Sleep(30000);
Instead of calling a method on another thread; submit immutable data to the other thread and let the thread decide when to handle it. There is an event already built in to BackgroundWorker which does that. Before you call bgWorker.RunWorkerAsync() do this:
url = new Uri(something);
bgWorker.WorkerReportsProgress = true;
bgWorker.WorkerSupportsCancellation = true;
bgWorker.ProgressChanged += Bgw_ProgressChanged;
private void Bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox2.AppendText("Status of: " + url + ": " + e.UserState.ToString()
+ Environment.NewLine);
}
Your bgWorker_DoWork should look more like this:
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (!bgw.CancellationPending)
{
System.Threading.Thread.Sleep(new TimeSpan(0, 0, 30));
var status = ResultOfPing(e.Argument as Uri);
bgw.ReportProgress(0, status);
}
e.Cancel = true;
}
and you should call it like this:
bgWorker.RunWorkerAsync(url);
You've got a second problem. BackgroundWorker creates a thread, and your thread is going to spend most of its time blocked on a timer or waiting for network responses. That is a poor use of a thread. You would be better off using completion callbacks or async/await.
The background worker is running on a thread pool thread, but your call to Status and Sleep is running on the UI thread. You need to move that stuff back into bgWorker_DoWork.
Try this code:
public partial class Form1 : Form
{
bool cancel;
public Form1()
{
InitializeComponent();
}
public void StartPinging()
{
this.cancel = false;
startButton.Enabled = false;
stopButton.Enabled = true;
responseBox.Clear();
responseBox.AppendText("Starting to ping server.");
responseBox.AppendText(Environment.NewLine);
var bw = new BackgroundWorker
{
WorkerReportsProgress = false,
WorkerSupportsCancellation = true
};
bw.DoWork += (obj, ev) =>
{
while (!cancel)
{
// Ping Server Here
string response = Server.PingServer();
this.Invoke(new UiMethod(() =>
{
responseBox.AppendText(response);
responseBox.AppendText(Environment.NewLine);
}));
}
};
bw.RunWorkerCompleted += (obj, ev) =>
{
this.Invoke(new UiMethod(() =>
{
responseBox.AppendText("Stopped pinging the server.");
responseBox.AppendText(Environment.NewLine);
startButton.Enabled = true;
stopButton.Enabled = false;
}));
};
bw.RunWorkerAsync();
}
delegate void UiMethod();
private void startButton_Click(object sender, EventArgs e)
{
StartPinging();
}
private void stopButton_Click(object sender, EventArgs e)
{
responseBox.AppendText("Cancelation Pressed.");
responseBox.AppendText(Environment.NewLine);
cancel = true;
}
}
public class Server
{
static Random rng = new Random();
public static string PingServer()
{
int time = 1200 + rng.Next(2400);
Thread.Sleep(time);
return $"{time} ms";
}
}
Erwin, when dealing with C# - threads and UI elements usually you will come across cross-thread operations i.e. Background thread with UI threads. This interaction needs to be done in thread safe way with the help of Invoke to avoid invalid operations.
Please look into below resource: InvokeRequired section.
https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls

How to get updates and reply telegram bot?

This is my code that i try to connect to a telegram bot
namespace telegramUpdate
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
TelegramBotClient bot = new TelegramBotClient("xxxxxxxxx");
int offset = 23;
Update temp = null;
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
try
{
var m = Task.Run(async()=> bot.GetUpdatesAsync(offset,50)).Result;
foreach (var x in m.Result)
{
switch (x.Type)
{
case UpdateType.MessageUpdate:
temp = x;
backgroundWorker1.ReportProgress(0);
bot.SendTextMessageAsync(x.Message.Chat.Id, ":)").ConfigureAwait(false);
break;
}
offset = x.Id+1;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = temp.Message.From.FirstName;
}
}
}
after ruining message box show "One or more errors occurred." what is the problem? telegram bot should reply ":)" but it don't. I can not find out if m receive any updates or not.
try this:
bot.SendTextMessageAsync(x.Message.Chat.Id, ":)").GetAwaiter().GetResult();
you didn't execute the task. just it
to me this same error happen recently (the code was working on Feb 2020 but did not work later) when making bot.SendTextMessageAsync i received same exception. After some research i found this topic [Telegram Bot stops with An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll
that actually solved my problem.
using System.Net;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Wait for an Comport value inside a other thread in C#

I've created a small program. Everthing works fine but now I have recognized that I have to wait for an comport input and here I stuck .
Here is my DataReceived thread:
void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
RxString = serialPort.ReadLine();
this.Invoke(new EventHandler(DisplayText));
}
void DisplayText(object sender, EventArgs e)
{
String RxString1 = RxString+("\n");
if (RxString1 == "END\n") {
stopauto = "stop";
autostart.Enabled = true;
autostop.Enabled = false;
}
Here the if with end and other things works fine.
But now I have another thread, inside which I have to wait for an comport input to receive , eg: "go".
I don't post the whole code it has near 200 lines ...
private void AutostartClick(object sender, EventArgs e)
{
.... Do some Code
... Here i want to wait for "go"
... If go is received go ahead
}
I have tried it with a while and while and a if ... but this will not work because inside the while I receive nothing from the comport .
Then played around with AutoResetEvent , but it stucks too.
What am I doing wrong?
I would do the following: As the DataReceived event of the SerialPort component is executed in a separate thread, you are safe to assume that it will be executed even though your main thread waits.
This allows you to set a WaitHandle if the required "keyword" is received, and you can wait for this event to occur:
private ManualResetEvent _goReceived = new ManualResetEvent(false); // Initialize as "not set"
void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
RxString = serialPort.ReadLine();
// DO NOT CALL DISPLAYTEXT IF YOU RECEIVE "GO" - THE MAIN THREAD IS BLOCKED!
if (RxString.StartsWith("go"))
{
_goReceived.Set();
}
else
{
this.Invoke(new EventHandler(DisplayText));
}
}
void DisplayText(object sender, EventArgs e)
{
String RxString1 = RxString+("\n");
if (RxString1 == "END\n") {
stopauto = "stop";
autostart.Enabled = true;
autostop.Enabled = false;
}
}
In your method that should wait for "go", just wait for the event to occur:
private void AutostartClick(object sender, EventArgs e)
{
.... Do some Code
// Wait for "go" and THEN call DisplayText instead of calling
// it above
_goReceived.Wait();
DisplayText();
// Reset the event to make this works more than just once
_goReceived.Reset();
... If go is received go ahead
}
I have found a solution ... maybe not the best way but it works.
With ManualResetEvent or AutoResetEvent it always freeze.
I think the problem was that i was in a while loop and so the wait handler was never signaled so it freeze at this point.
Now i work with a global variable, a simple if in the DisplayText event and a while which calls this.Invoke(new EventHandler(DisplayText)); and it works without any problems.
Here is the Serialport and DisplayText Code:
String waitvar = ""; // Global wait Variable
void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
RxString = serialPort.ReadLine();
this.Invoke(new EventHandler(DisplayText));
}
void DisplayText(object sender, EventArgs e)
{
String RxString1 = RxString+("\n");
if (RxString1 == "go\n") {
waitvar = "go";
}
comview.AppendText(RxString1);
}
And at the Wait point:
private void AutostartClick(object sender, EventArgs e)
{
.... Do some Code
// Wait here
while (waitvar != "go")
{
this.Invoke(new EventHandler(DisplayText));
}
.... Do some Code
}
Thank you to all helpers !

Delegate loads the Alert Form but I can't use any of the components.. its stuck

The problem is below. Here's my code...
// Contents of Form1.cs
// Usual includes
namespace ProcessMonitor
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Boolean getStatus()
{
// Returns true if the system is active
if (label1.Text.Equals("Active"))
return true;
return false;
}
private void button1_Click(object sender, EventArgs e)
{
if(getStatus())
{
label1.Text = "Not Active";
button1.Text = "Activate";
}
else
{
label1.Text = "Active";
button1.Text = "Deactivate";
}
}
private void Form1_Load(object sender, EventArgs e)
{
Monitor mon = new Monitor(this);
mon.Run();
}
}
}
// Contents of Monitor.cs
// Usual includes
using System.Management;
using System.Diagnostics;
using System.Threading;
namespace ProcessMonitor
{
class Monitor
{
Form1 parent;
private void ShowAlert(Alert al)
{
al.Show();
}
public Monitor(Form1 parent)
{
this.parent = parent;
}
public void InvokeMethod()
{
//This function will be on main thread if called by Control.Invoke/Control.BeginInvoke
Alert frm = new Alert(this.parent);
frm.Show();
}
// This method that will be called when the thread is started
public void Run()
{
var query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 0, 0, 1),
"TargetInstance isa \"Win32_Process\");
while (true)
{
using (var watcher = new ManagementEventWatcher(query))
{
ManagementBaseObject mo = watcher.WaitForNextEvent();a
//MessageBox.Show("Created process: " + ((ManagementBaseObject)mo["TargetInstance"])["Name"] + ",Path: " + ((ManagementBaseObject)mo["TargetInstance"])["ExecutablePath"]);
ManagementBaseObject o = (ManagementBaseObject)mo["TargetInstance"];
String str = "";
foreach (PropertyData s in o.Properties)
{
str += s.Name + ":" + s.Value + "\n";
}
this.parent.Invoke(new MethodInvoker(InvokeMethod), null);
}
}
}
}
}
Alert.cs is just a blank form with a label that says “new process has started”. I intend to display the name of the process and location, pid, etc. by passing it to this alert form via the Thread (i.e. class Monitor). I have deliberately made the thread load in form_load so that I can resolve this error first. Adding it as a thread properly after the main form loads fully is a later task. I need to fix this first..
The delegate creates the Alert form but I can’t click on it, its just stuck. Need help to solve this.
Your while loop in Run is blocking the UI thread.
by passing it to this alert form via the Thread
You never actually create a new thread or task here - you just run code which executes in the UI thread, and causes an infinite loop. This will prevent the main form, as well as your Alert form, from ever displaying messages.
You need to push this into a background thread in order for it to work, ie:
private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(_ =>
{
Monitor mon = new Monitor(this);
mon.Run();
});
}

WPF C# - Update progressbar from another thread

I'm stuck trying to update a progressbar from other threads ran in a different class. To explain what I do I think a picture will be better. I want to update the progressbar in the //HERE point :
I've tried using a delegate, tried with ReportProgress and I think i've basically tried to use everything google reported in the first 100 results, without success. I'm still learning WPF and this might be silly way to proceed, i'm looking for a quick and dirty way to get the work done but feel free to tell me what I should redesign for a cleaner application.
EDIT : More code.
In ExecutorWindow.xaml.cs :
public void RunExecutor()
{
// CREATE BACKGROUNDWORKER FOR EXECUTOR
execBackground.DoWork += new DoWorkEventHandler(execBackground_DoWork);
execBackground.RunWorkerCompleted += new RunWorkerCompletedEventHandler(execBackground_RunWorkerCompleted);
execBackground.ProgressChanged += new ProgressChangedEventHandler(execBackground_ProgressChanged);
execBackground.WorkerReportsProgress = true;
execBackground.WorkerSupportsCancellation = true;
// RUN BACKGROUNDWORKER
execBackground.RunWorkerAsync();
}
private void execBackground_DoWork(object sender, DoWorkEventArgs e)
{
myExecutor = new Executor(arg1, arg2);
myExecutor.Run();
}
private void execBackground_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("RunWorkerCompleted execBackground");
}
private void execBackground_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ExecutorProgressBar.Value += 1;
}
// TESTING
private void updateProgressBar(int i)
{
ExecutorProgressBar.Value += i;
}
public delegate void callback_updateProgressBar(int i);
In Executor.cs :
public void Run()
{
string[] options = new string[2];
int i = 0;
while (LeftToRun > 0)
{
if (CurrentRunningThreads < MaxThreadsRunning)
{
BackgroundWorker myThread = new BackgroundWorker();
myThread.DoWork += new DoWorkEventHandler(backgroundWorkerRemoteProcess_DoWork);
myThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerRemoteProcess_RunWorkerCompleted);
myThread.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerRemoteProcess_ProgressChanged);
myThread.WorkerReportsProgress = true;
myThread.WorkerSupportsCancellation = true;
myThread.RunWorkerAsync(new string[2] {opt1, opt2});
// HERE ?
CurrentRunningThreads++;
i++;
LeftToRun--;
}
}
while (CurrentRunningThreads > 0) { }
logfile.Close();
MessageBox.Show("All Tasks finished");
}
private void backgroundWorkerRemoteProcess_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker myBackgroundWorker = sender as BackgroundWorker;
string[] options = (string[])e.Argument;
string machine = options[0];
string script = options[1];
// UPDATE HERE PROGRESSBAR ?
RemoteProcess myRemoteProcess = new RemoteProcess(machine, script);
string output = myRemoteProcess.TrueExec();
// UPDATE HERE PROGRESSBAR ?
this.logfile.WriteLine(output);
}
private void backgroundWorkerRemoteProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
CurrentRunningThreads--;
}
private void backgroundWorkerRemoteProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//myExecWindow.ExecutorProgressBar.Value = e.ProgressPercentage; // TESTING
//ExecutorWindow.callback_updateProgressBar(1); // TESTING
}
EDIT 2 : I got it! Simple in fact, but i guess I've been looking too close to find out.
In my ExecutorWindow class :
private void execBackground_DoWork(object sender, DoWorkEventArgs e)
{
myExecutor = new Executor(arg1, arg2);
myExecutor.Run(sender);
}
private void execBackground_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ExecutorProgressBar.Value += 1;
}
And in my Executor class :
private BackgroundWorker myExecutorWindow;
[...]
public void Run(object sender)
{
myExecutorWindow = sender as BackgroundWorker;
string[] options = new string[2];
int i = 0;
while (LeftToRun > 0)
{
if (CurrentRunningThreads < MaxThreadsRunning)
{
BackgroundWorker myThread = new BackgroundWorker();
myThread.DoWork += new DoWorkEventHandler(backgroundWorkerRemoteProcess_DoWork);
myThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerRemoteProcess_RunWorkerCompleted);
myThread.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerRemoteProcess_ProgressChanged);
myThread.WorkerReportsProgress = true;
myThread.WorkerSupportsCancellation = true;
myThread.RunWorkerAsync(new string[2] {opt1, opt2});
CurrentRunningThreads++;
i++;
LeftToRun--;
}
}
[...]
private void backgroundWorkerRemoteProcess_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker myBackgroundWorker = sender as BackgroundWorker;
myBackgroundWorker.ReportProgress(1);
// PROCESSING MY STUFF HERE
myBackgroundWorker.ReportProgress(1);
}
private void backgroundWorkerRemoteProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myExecutorWindow.ReportProgress(1);
}
Thank you !
You can run any method on the UI thread with this very basic sample
this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
{
this.progressBar.Value= 20; // Do all the ui thread updates here
}));
Running commands inside the Dispatcher.Invoke(...), you can actually interact with the UI from any worker thread, where otherwise you would get an exception.
If you really need to have the ultimate control on the background threads & main (UI) thread updates, here is a fantastic tutorial on that: http://blog.decarufel.net/2009/03/good-practice-to-use-dispatcher-in-wpf.html
You should be able to use the Dispatcher.Invoke method
e.g.
Dispatcher.Invoke(
new System.Action(() => myProgressBar.Value = newValue)
);
I got it! Simple in fact, but i guess I've been looking too close to find out.
In my ExecutorWindow class :
private void execBackground_DoWork(object sender, DoWorkEventArgs e)
{
myExecutor = new Executor(arg1, arg2);
myExecutor.Run(sender);
}
private void execBackground_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ExecutorProgressBar.Value += 1;
}
And in my Executor class :
private BackgroundWorker myExecutorWindow;
[...]
public void Run(object sender)
{
myExecutorWindow = sender as BackgroundWorker;
string[] options = new string[2];
int i = 0;
while (LeftToRun > 0)
{
if (CurrentRunningThreads < MaxThreadsRunning)
{
BackgroundWorker myThread = new BackgroundWorker();
myThread.DoWork += new DoWorkEventHandler(backgroundWorkerRemoteProcess_DoWork);
myThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerRemoteProcess_RunWorkerCompleted);
myThread.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerRemoteProcess_ProgressChanged);
myThread.WorkerReportsProgress = true;
myThread.WorkerSupportsCancellation = true;
myThread.RunWorkerAsync(new string[2] {opt1, opt2});
CurrentRunningThreads++;
i++;
LeftToRun--;
}
}
[...]
private void backgroundWorkerRemoteProcess_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker myBackgroundWorker = sender as BackgroundWorker;
myBackgroundWorker.ReportProgress(1);
// PROCESSING MY STUFF HERE
myBackgroundWorker.ReportProgress(1);
}
private void backgroundWorkerRemoteProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myExecutorWindow.ReportProgress(1);
}
I found a really simple solution to create a thread to run any block of code as well as handle Invocation back to the main thread to change the control's properties. It works out of the box with .NET 4.5 and the lambda call on the Dispatcher could be adapted to work with earlier versions of .NET. The main benefit is it's just so blissfully simple and perfect when you just need a quick thread for some really basic bit of code.
So presuming you have a progress bar somewhere on your dialog in scope do this:
progBar.Minimum = 0;
progBar.Maximum = theMaxValue;
progBar.Value = 0;
Dispatcher disp = Dispatcher.CurrentDispatcher;
new Thread(() => {
// Code executing in other thread
while (progBar.Value < theMaxValue)
{
// Your application logic here
// Invoke Main Thread UI updates
disp.Invoke(
() =>
{
progBar.Value++;
}
);
}
}).Start();
You also need to ensure you have a reference to WindowsBase.dll
If you want a more reusable snippet of code running as the thread start you could use a method as the delegate but I find the inline lambda so easy for simple tasks and you don't need to deal with events as with the Background Worker approaches.

Categories

Resources