ProgressBar problems while program downloading file - c#

I have a problem with a simple updater program. It should to download archive and extract it. Well, this works fine. But i cannot overcome progressbar.
It shows at setProgressBar(progressBar1.Maximum/20) fine.
But all other changes of it's value doesn't shows at all. I can't define reason for this behavior. Could anyone help me?
UPD: It seems that e.ProgressPercentage returns always 0, and only once 100, right before download is complete.
Here is my code:
static EventWaitHandle _waitHandle = new AutoResetEvent(false);
void UpdaterForm_Shown(object sender, System.EventArgs e)
{
setProgressBar(progressBar1.Maximum/20);
UpdateProgram(address, login, password);
setProgressBar(progressBar1.Maximum);
ExecuteProgram(Path + "../" + programName + ".exe");
Application.Exit();
}
private void UpdateProgram(string pathToUpdateArchive, string login, string pass)
{
string downloadedArchive = null;
Thread downloadAsync = new Thread(() => DownloadFileFromFtp(pathToUpdateArchive, login, pass, out downloadedArchive));
downloadAsync.Name = "downloadAsync";
downloadAsync.Start();
_waitHandle.WaitOne();
ExtractFile(downloadedArchive, Path + "/../");
}
private void DownloadFileFromFtp(string address, string login, string password, out string archivePath)
{
fileName = address.Substring(address.LastIndexOf('/') + 1);
try
{
WebClient wc = new WebClient();
wc.Credentials = new NetworkCredential(login, password);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted);
archivePath =Path + fileName;
wc.DownloadFileAsync(new Uri(address), archivePath);
}
catch
{
}
}
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
setProgressBar(e.ProgressPercentage*7/10 + 10);
}
void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
_waitHandle.Set();
}
private void setProgressBar(int value)
{
if (progressBar1.InvokeRequired)
this.BeginInvoke((MethodInvoker)delegate { progressBar1.Value = value; });
else
progressBar1.Value = value;
}

Related

How to move a function to a separate assembly from the interface [Error]

I am currently working on a file copying facility that allows me to select a source and a destination for the folders to be copied from and to. A progress bar is displayed after the user clicks on Copy.
The only issue is that All of my functions reside in one file which is form1.cs (as follows)
namespace CopyFacility
{
public partial class Form1 : Form
{
BackgroundWorker background = new BackgroundWorker();
FolderBrowserDialog folderBrowser = new FolderBrowserDialog();
OpenFileDialog openFile = new OpenFileDialog();
public Form1()
{
InitializeComponent();
background.WorkerSupportsCancellation = true;
background.WorkerReportsProgress = true;
background.DoWork += Background_DoWork;
background.RunWorkerCompleted += Background_RunWorkerCompleted;
background.ProgressChanged += Background_ProgressChanged;
}
string inputFile = null;
string outputFile = null;
private void CopyFile(string source, string destination, DoWorkEventArgs e)
{
FileStream fsOut = new FileStream(destination, FileMode.Create);
FileStream fsIn = new FileStream(source, FileMode.Open);
byte[] buffer = new byte[1048756];
int readBytes;
while((readBytes = fsIn.Read(buffer,0,buffer.Length)) > 0)
{
if(background.CancellationPending)
{
e.Cancel = true;
background.ReportProgress(0);
fsIn.Close();
fsOut.Close();
return;
}
else
{
fsOut.Write(buffer, 0, readBytes);
background.ReportProgress((int) (fsIn.Position * 100 / fsIn.Length));
}
fsOut.Write(buffer, 0, readBytes);
background.ReportProgress((int)(fsIn.Position * 100 / fsIn.Length));
}
fsIn.Close();
fsOut.Close();
}
private void Background_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
fileProgressBar.Value = e.ProgressPercentage;
}
private void Background_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Cancelled)
{
fileProgressBar.Visible = true;
lblMessage.Visible = true;
lblMessage.Text = "The process has been cancelled";
}
else
{
fileProgressBar.Visible = true;
lblMessage.Visible = true;
lblMessage.Text = "The process has been completed";
}
}
private void Background_DoWork(object sender, DoWorkEventArgs e)
{
CopyFile(inputFile, outputFile + #"\" + Path.GetFileName(inputFile),e);
}
private void btnCancel_Click(object sender, EventArgs e)
{
background.CancelAsync();
}
private void btnCopy_Click(object sender, EventArgs e)
{
if(background.IsBusy)
{
lblProgress.Visible = true;
}
else
{
fileProgressBar.Visible = true;
background.RunWorkerAsync();
}
}
private void btnSource_Click(object sender, EventArgs e)
{
if(openFile.ShowDialog() == DialogResult.OK )
{
inputFile = openFile.FileName;
btnSource.Text = inputFile;
}
}
private void btnDestination_Click(object sender, EventArgs e)
{
if (folderBrowser.ShowDialog() == DialogResult.OK)
{
outputFile = folderBrowser.SelectedPath;
btnDestination.Text = outputFile + #"\" + Path.GetFileName(inputFile);
}
}
}
}
I was wondering how I could go about putting the function "CopyFile" into it's own class that can be called whenever the button is clicked?
When I try creating a new class method and inserting the functions related to the copying function into a new class "CopyFunction.cs" , I get a following error from the code "InitializingComponent();" as follows
public CopyPresenter(BackgroundWorker background, FolderBrowserDialog folderBrwoser, OpenFileDialog openFile)
{
InitializeComponent();
background.WorkerSupportsCancellation = true;
background.WorkerReportsProgress = true;
background.DoWork += Background_DoWork;
background.RunWorkerCompleted += Background_RunWorkerCompleted;
background.ProgressChanged += Background_ProgressChanged;
}
The error says that the "InitializeComponent" doesn't exist in the current context.

C# textfile only contains last string written to file with StreamWriter

I'm writing a Chat Program in C# (Windows Forms Application), the solution contains to projects which both consist of one form ( see picture ). While sending messages to each other works, I'm trying to record the conversation session in a .txt file named dateTime.txt using StreamWriter. Creating the file if it does not exist yet works, but whenever I open the text file, it only contains the last string that was written to it instead of containing the whole "conversation".
Does anybody know how to fix this?
This is the code of one of the forms, but since the forms do exactly the same, the code is the same too so i'm only posting the code of one Form. Would be great if somebody knows what I have to change so the whole conversation is recorded in the text file.
namespace Assignment3Client
{
public partial class Chat : Form
{
NamedPipeClientStream clientPipe = new NamedPipeClientStream("pipe2");
NamedPipeServerStream serverPipe = new NamedPipeServerStream("pipe1");
string msg = String.Empty;
string msgStr;
string name;
byte[] ClientByte;
public Chat()
{
InitializeComponent();
}
private void btnStartChat_Click(object sender, EventArgs e)
{
this.Text = "Waiting for a connection....";
if (txtBoxName.Text.Length == 0)
{
MessageBox.Show("please enter a name first.");
}
else
{
name = txtBoxName.Text;
clientPipe.Connect();
serverPipe.WaitForConnection();
if (serverPipe.IsConnected)
{
this.Text = "You are connected, " + name + "!";
btnStartChat.Enabled = false;
btnSend.Enabled = true;
txtBoxMsg.Enabled = true;
txtBoxMsg.Focus();
receiveWorker.RunWorkerAsync();
}
}
}
private void btnSend_Click(object sender, EventArgs e)
{
msg = "[" + name + ": " + DateTime.Now + "] " + txtBoxMsg.Text;
txtBoxChat.AppendText(msg + "\n");
FileWriter(msg);
sendWorker.RunWorkerAsync(msg); //start backgroundworker and parse msg string to the dowork method
txtBoxMsg.Clear();
txtBoxMsg.Focus();
}
private void sendWorker_DoWork(object sender, DoWorkEventArgs e)
{
Byte[] msgByte = System.Text.Encoding.GetEncoding("windows-1256").GetBytes(msg);
serverPipe.Write(msgByte, 0, msg.Length);
}
private void receiveWorker_DoWork(object sender, DoWorkEventArgs e)
{
ClientByte = new Byte[1000];
int i;
for (i = 0; i < ClientByte.Length; i++)
{
ClientByte[i] = 0x20;
}
clientPipe.Read(ClientByte, 0, ClientByte.Length);
msgStr = System.Text.Encoding.GetEncoding("windows-1256").GetString(ClientByte);
receiveWorker.ReportProgress(i, msgStr);
}
private void receiveWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if ((string)e.UserState == String.Empty)
{ MessageBox.Show("no message"); }
else
{
string message = (string)e.UserState;
txtBoxChat.AppendText(message);
FileWriter(message);
txtBoxChat.BackColor = System.Drawing.Color.DarkBlue;
txtBoxChat.ForeColor = System.Drawing.Color.White;
}
}
private void receiveWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (clientPipe.IsConnected)
{
receiveWorker.RunWorkerAsync();
}
else
{
txtBoxMsg.Enabled = false;
btnSend.Enabled = false;
MessageBox.Show("Connection lost");
}
}
private void Chat_Activated(object sender, EventArgs e)
{
txtBoxChat.BackColor = new System.Drawing.Color();
txtBoxChat.ForeColor = new System.Drawing.Color();
}
private void exitMenuStrip_Click(object sender, EventArgs e)
{
this.Close();
}
private void conMenuSrip_Click(object sender, EventArgs e)
{
}
private void errMenuStrip_Click(object sender, EventArgs e)
{
}
public void FileWriter(string message)
{
string path = #"C:\Users\selin\Documents\TAFE\Term 3\dateTime.txt";
FileStream conLog;
if (!File.Exists(path))
{
conLog = new FileStream(path, FileMode.Create);
}
else
{
conLog = new FileStream(path, FileMode.Open);
}
StreamWriter writer = new StreamWriter(conLog);
writer.WriteLine(message);
writer.AutoFlush = true;
writer.Close();
MessageBox.Show("written to file" + message);
}
}
}
in FileWriter(string message) change
conLog = new FileStream(path, FileMode.Open);
to
conLog = new FileStream(path, FileMode.Append);

C# Launcher based on WebClient

I'm creating simple launcher for my other application and I need advise on logical part of the program. Launcher needs to check for connection, then check for file versions (from site), compare it with currently downloaded versions (if any) and if everything is alright, start the program, if not, update (download) files that differs from newest version. The files are:
program.exe, config.cfg and mapFolder. The program.exe and mapFolder must be updated, and config.cfg is only downloaded when there is no such file. Additionaly mapFolder is an folder which contains lots of random files (every new version can have totally different files in mapFolder).
For the file version I thought I would use simple DownloadString from my main site, which may contain something like program:6.0,map:2.3, so newest program ver is 6.0 and mapFolder is 2.3. Then I can use FileVersionInfo.GetVersionInfo to get the version of current program (if any) and include a file "version" into mapFolder to read current version.
The problem is I dont know how to download whole folder using WebClient and what's the best way to do what I want to do. I've tried to download the mapFolder as zip and then automatically unpack it, but the launcher need to be coded in .net 3.0.
Here is my current code, that's just a prototype to get familiar with whole situation, dont base on it.
`
WebClient wc = new WebClient();
string verifySite = "google.com/downloads/version";
string downloadSite = "google.com/downloads/program.exe";
Uri verifyUri, downloadUri = null;
string userVer, currVer = "";
string downloadPath = Directory.GetCurrentDirectory();
string clientName = "program.exe";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(FileDownloaded);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(FileDownloadProgress);
chckAutorun.Checked = Properties.Settings.Default.autorun;
checkConnection();
if(!checkVersion())
downloadClient();
else
{
pbDownload.Value = 100;
btnPlay.Enabled = true;
lblProgress.Text = "updated";
if (chckAutorun.Checked)
btnPlay.PerformClick();
}
}
private bool checkConnection()
{
verifyUri = new Uri("http://" + verifySite);
downloadUri = new Uri("http://" + downloadSite);
WebRequest req = WebRequest.Create(verifyUri);
try
{
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
return true;
}
catch { }
verifyUri = new Uri("https://" + verifySite);
downloadUri = new Uri("https://" + downloadUri);
req = WebRequest.Create(verifyUri);
try
{
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
return true;
}
catch { }
return false;
}
private void downloadClient()
{
try
{
wc.DownloadFileAsync(downloadUri, Path.Combine(downloadPath, clientName));
}
catch { }
}
private bool checkVersion()
{
lblProgress.Text = "checking for updates";
try
{
currVer = FileVersionInfo.GetVersionInfo(Path.Combine(downloadPath, clientName)).FileVersion;
}
catch {
currVer = "";
}
try
{
userVer = wc.DownloadString(verifyUri);
}
catch {
userVer = "";
}
return currVer == userVer && currVer != "";
}
private void FileDownloaded(object sender, AsyncCompletedEventArgs e)
{
btnPlay.Enabled = true;
lblProgress.Text = "updated";
if (chckAutorun.Checked)
btnPlay.PerformClick();
}
private void FileDownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
long received = e.BytesReceived / 1000;
long toReceive = e.TotalBytesToReceive / 1000;
lblProgress.Text = string.Format("{0}KB {1}/ {2}KB", received, Repeat(" ", Math.Abs(-5 + Math.Min(5, received.ToString().Length))*2), toReceive);
pbDownload.Value = e.ProgressPercentage;
}
private void btnPlay_Click(object sender, EventArgs e)
{
btnPlay.Enabled = false;
if(checkVersion())
{
lblProgress.Text = "Starting...";
Process.Start(Path.Combine(downloadPath, clientName));
this.Close();
}
else
{
downloadClient();
}
}
public static string Repeat(string instr, int n)
{
if (string.IsNullOrEmpty(instr))
return instr;
var result = new StringBuilder(instr.Length * n);
return result.Insert(0, instr, n).ToString();
}
private void chckAutorun_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.autorun = chckAutorun.Checked;
Properties.Settings.Default.Save();
}`
I've managed to achieve what I need by enabling autoindex on web server and download string of files in folder ending with .map .
string mapSite = wc.DownloadString(new Uri("http://" + mapsSite));
maps = Regex.Matches(mapSite, "<a href=\"(.*).map\">");
foreach (Match m in maps)
{
string mapName = m.Value.Remove(0, 9).Remove(m.Length - 11);
downloaded = false;
wc.DownloadFileAsync(new Uri("http://" + mapsSite + mapName), Path.Combine(downloadPath, #"mapFolder/" + mapName));
while (!downloaded) { }
}

Wait for download to complete

I'm trying to create a simple program to download few files. I've tried some ready-made solutions I found on the web but I can't manage to make it work the way I want it to. I'm using this:
private void startDownload(string toDownload, string saveLocation)
{
Thread thread = new Thread(() =>
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(new Uri(toDownload), saveLocation);
});
thread.Start();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
labelPercentage.Text = "Downloading " + Convert.ToInt32(percentage) + "% - " + Convert.ToInt32(bytesIn / 1024) + " / " + Convert.ToInt32(totalBytes / 1024) + " kB";
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
});
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
textBoxLog.AppendText("OK");
});
}
I'd like to make the program continue (download next file / show the "OK" message / do whatever is in the next line of code) AFTER the download has finished.
In the current form, if I'd put eg.
private void button1_Click(object sender, EventArgs e)
{
startDownload(url, localpath + #"\file.zip");
textBoxLog.AppendText("the cake is a lie");
}
it's showing me this text first and "OK" later.
I'm beginning with c#/.net and I've never learned object-oriented programming before so it's kind of double challenge for me and I can't figure it out by myself. I would be really grateful for relatively easy explanation.
You can have startDownload wait for the asynchronous file download through Application.DoEvents() like this:
private bool downloadComplete = false;
private void startDownload(Uri toDownload, string saveLocation)
{
string outputFile = Path.Combine(saveLocation, Path.GetFileName(toDownload.AbsolutePath));
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(toDownload, outputFile);
while (!downloadComplete)
{
Application.DoEvents();
}
downloadComplete = false;
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// No changes in this method...
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
textBoxLog.AppendText("OK");
downloadComplete = true;
});
}
And the download queue...
private void button1_Click(object sender, EventArgs e)
{
FireDownloadQueue(urls, localpath);
textBoxLog.AppendText("the cake is a lie");
}
private async void FireDownloadQueue(Uri[] toDownload, string saveLocation)
{
foreach (var url in urls)
{
await Task.Run(() => startDownload(url, localpath));
}
}
However, I think you're better off reading about HttpWebRequest and writing your own downloader class with proper checks and events...
Here's a pretty good example by Hemanshu Bhojak (Source) that you can expand upon:
public class Downloader
{
public async Task Download(string url, string saveAs)
{
var httpClient = new HttpClient();
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));
var parallelDownloadSuported = response.Headers.AcceptRanges.Contains("bytes");
var contentLength = response.Content.Headers.ContentLength ?? 0;
if (parallelDownloadSuported)
{
const double numberOfParts = 5.0;
var tasks = new List<Task>();
var partSize = (long)Math.Ceiling(contentLength / numberOfParts);
File.Create(saveAs).Dispose();
for (var i = 0; i < numberOfParts; i++)
{
var start = i*partSize + Math.Min(1, i);
var end = Math.Min((i + 1)*partSize, contentLength);
tasks.Add(
Task.Run(() => DownloadPart(url, saveAs, start, end))
);
}
await Task.WhenAll(tasks);
}
}
private async void DownloadPart(string url, string saveAs, long start, long end)
{
using (var httpClient = new HttpClient())
using (var fileStream = new FileStream(saveAs, FileMode.Open, FileAccess.Write, FileShare.Write))
{
var message = new HttpRequestMessage(HttpMethod.Get, url);
message.Headers.Add("Range", string.Format("bytes={0}-{1}", start, end));
fileStream.Position = start;
await httpClient.SendAsync(message).Result.Content.CopyToAsync(fileStream);
}
}
}
Example usage:
Task.Run(() => new Downloader().Download(downloadString, saveToString)).Wait();
With something along the lines of:
public class Downloader
{
public event EventHandler DownloadProgress;
DownloaderEventArgs downloaderEventArgs;
public void DownloadStarted(DownloaderEventArgs e)
{
EventHandler downloadProgress = DownloadProgress;
if (downloadProgress != null)
downloadProgress(this, e);
}
// ...
}
class DownloaderEventArgs : EventArgs
{
public string Filename { get; private set; }
public int Progress { get; private set; }
public DownloaderEventArgs(int progress, string filename)
{
Progress = progress;
Filename = filename;
}
public DownloaderEventArgs(int progress) : this(progress, String.Empty)
{
Progress = progress;
}
}
startDownload initiates the download on a new thread, so when you invoke startDownload it starts the thread and the rest of the code after that continues immediately because it is on a separate thread. That is why you are seeing "the cake is a lie" before the "OK".

Creating a multi-thread webdownload via WebClient / BeginInvoke Method

I have actually the following code:
private Stopwatch _sw;
public void DownloadFile(string url, string fileName)
{
string path = #"C:\DL\";
Thread bgThread = new Thread(() =>
{
_sw = new Stopwatch();
_sw.Start();
labelDownloadAudioStatusText.Visibility = Visibility.Visible;
using (WebClient webClient = new WebClient())
{
webClient.DownloadFileCompleted +=
new AsyncCompletedEventHandler(DownloadCompleted);
webClient.DownloadProgressChanged +=
new DownloadProgressChangedEventHandler(DownloadStatusChanged);
webClient.DownloadFileAsync(new Uri(url), path + fileName);
}
});
bgThread.Start();
}
void DownloadStatusChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.BeginInvoke((MethodInvoker) delegate
{
int percent = 0;
if (e.ProgressPercentage != percent)
{
percent = e.ProgressPercentage;
progressBarDownloadAudio.Value = percent;
labelDownloadAudioProgress.Content = percent + "%";
labelDownloadAudioDlRate.Content =
(Convert.ToDouble(e.BytesReceived)/1024/
_sw.Elapsed.TotalSeconds).ToString("0.00") + " kb/s";
Thread.Sleep(50);
}
});
}
private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker) delegate
{
labelDownloadAudioDlRate.Content = "0 kb/s";
labelDownloadAudioStatusText.Visibility = Visibility.Hidden;
});
}
My problem is that in a previous version without the outer thread, the whole GUI freezes sporadically and the GUI is liquid when the download is finished. So I googled around and found this: https://stackoverflow.com/a/9459441/2288470
An answer was to pack everything into a separate thread which performs the interaction with DownloadFileAsync, but I got the fault, that the BeginInvoke method can not be found.
When using WPF, the BeginInvoke method is not exposed by the Window class, like it is for Form in WinForms. Instead you should use Dispatcher.BeginInvoke.
Working code:
private Stopwatch _sw;
public void DownloadFile(string url, string fileName)
{
string path = #"C:\DL\";
Thread bgThread = new Thread(() =>
{
_sw = new Stopwatch();
_sw.Start();
labelDownloadAudioStatusText.Visibility = Visibility.Visible;
using (WebClient webClient = new WebClient())
{
webClient.DownloadFileCompleted +=
new AsyncCompletedEventHandler(DownloadCompleted);
webClient.DownloadProgressChanged +=
new DownloadProgressChangedEventHandler(DownloadStatusChanged);
webClient.DownloadFileAsync(new Uri(url), path + fileName);
}
});
bgThread.Start();
}
void DownloadStatusChanged(object sender, DownloadProgressChangedEventArgs e)
{
Dispatcher.BeginInvoke((MethodInvoker) delegate
{
int percent = 0;
if (e.ProgressPercentage != percent)
{
percent = e.ProgressPercentage;
progressBarDownloadAudio.Value = percent;
labelDownloadAudioProgress.Content = percent + "%";
labelDownloadAudioDlRate.Content =
(Convert.ToDouble(e.BytesReceived)/1024/
_sw.Elapsed.TotalSeconds).ToString("0.00") + " kb/s";
Thread.Sleep(50);
}
});
}
private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{
Dispatcher.BeginInvoke((MethodInvoker) delegate
{
labelDownloadAudioDlRate.Content = "0 kb/s";
labelDownloadAudioStatusText.Visibility = Visibility.Hidden;
});
}
Invoke method and BeginInvoke method is implemented on System.Windows.Forms.Control Class. If you are not writing code in such as Form Class, you cannot use this method. To resolve this problem, inherit your Job Class from System.Windows.Forms.Control Class, then you could use BeginInvoke method. Please note that you have to create instance on main thread.
public class JobClass : System.Windows.Forms.Control {
.....
}

Categories