How to multithreading this jobs? - c#

My idea is if finished download this messages then add them to ListView. But if this code we will waiting very long and program will be not responding. Can you help me?
private void MailTree_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
MailList.Items.Clear();
for (int i = 0; i < client.Folders.Count; i++)
{
(ContextMenuListView.Items[1] as ToolStripMenuItem).DropDownItems[i].Click += new EventHandler(MainForm_Click);
}
if (MailTree.SelectedNode.Text == Username)
{
webBrowser1.Visible = false;//webBrowser1.DocumentText = "Hello Baby";
AttachmentList.Visible = false;
groupBox1.Visible = false;
}
else
{
webBrowser1.Visible = true;
groupBox1.Visible = true;
try
{
messages = client.Folders[MailTree.SelectedNode.Text].Search("ALL", false); // Search mail in your choossen Folder
AmoutOfMail = messages.Count(); //Amout of Mail in this Folder
for (int i = 0; i < AmoutOfMail; i++)
{
mes = messages[i];
SaveMail(mes); // dowload mes and store message
ListViewItem item = new ListViewItem();
Mime m = EncodingMail(MailTree.SelectedNode.Text, mes); // read mes from place store message
item.Text = mes.MessageUid.ToString();
item.SubItems.Add(m.MainEntity.Subject);
ReturnMime(m);
if (mailfromname != null)
item.SubItems.Add(mailfromname);
else
item.SubItems.Add(mailfrom);
item.SubItems.Add(m.MainEntity.Date.ToString());
item.SubItems.Add(mailfrom);
MailList.Items.Add(item);
}
}
catch (Exception)
{ }
}
}

Yes.
Look into the Tasks library to offload whatever you want onto a different thread.
Just make sure that you use Controls.InvokeRequired to place the callback code back onto the UI thread. You should never modify the UI from a different thread than the UI thread.

Related

Thread manipulation in C#

Hello I recently started learning c# in Visual Studio..
I am trying to make a background process for my app.
I created a process and started it but I can't pause it without breaking my application.
public void WorkThreadFunction()
{
run = true;
for (int i = 0; i < 100; i++)
{
string message = "\r\n"+i+" Running...";
if (txtBox.InvokeRequired == true)
txtBox.Invoke((MethodInvoker)delegate { txtBox.Text += message; });
else
txtBox.Text += message;
Thread.Sleep(1000);
}
}
private void btnCapture_Click(object sender, EventArgs e)
{
Thread thread = new Thread(WorkThreadFunction);
if (run == false)
{
btnCapture.Text = "Abort";
lblStatus.Text = "Thread status: " + thread.ThreadState;
thread.Start();
}
else
{
btnCapture.Text = "Capture";
lblStatus.Text = "Thread status: " + thread.ThreadState;
//thread.Abort(); thread.Unset(); Thread.Sleep(999999); thread.WaitOne();
txtBox.Text += "Work!";
}
}
Also thread.ThreadState always returns "Unstarted"...
I tried using "ManualResetEvent" but this just freezes my app...
Help? :S
That's correct, you check ThreadState before calling Start(), thus it's unstarted.
As an unrelated note, you don't need that InvokeRequired check, it's always required in this context.

C# Progressbar & Textbox Not Updating

I've seen some great answers here and was wondering if someone could help me out.
Here's my code:
namespace expandGUIWPF
{
public static string getSHA256b64(string filepath)
{
byte[] bytes = SHA256.Create().ComputeHash(File.ReadAllBytes(filepath));
return Convert.ToBase64String(bytes);
}
private void btnRun_Click(object sender, RoutedEventArgs e)
{
{
string folder = txtFolder.Text;
string filelist = folder + "\\FileList.txt";
string[] test = Directory.GetFiles(folder, "*", System.IO.SearchOption.AllDirectories);
File.WriteAllLines(filelist, test);
int length = File.ReadLines(filelist).Count();
pBar1.Minimum = 1;
pBar1.Maximum = length;
File.WriteAllLines(filelist, test);
using (StreamReader sr = new StreamReader(filelist))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string oldfile = line;
string newfile = oldfile + ".expanded";
string oldhash = "";
string newhash = "";
try
{
ProcessStartInfo startInfo = new ProcessStartInfo(#"C:\test\test.exe", oldfile + " " + newfile);
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);
Thread.Sleep(1000);
if (File.Exists(oldfile))
{
oldhash = getSHA256b64(oldfile);
}
if (File.Exists(newfile))
{
newhash = getSHA256b64(newfile);
File.Delete(oldfile);
File.Move(newfile, oldfile);
}
pBar1.Value = pBar1.Value + 1;
txtLog.AppendText(oldfile + "\r\n Old: " + oldhash + "\r\n New: " + newhash + "\r\n");
if (!(oldhash == newhash))
{
txtLog.AppendText("Successfully expanded file \r\n");
}
else
{
txtLog.AppendText("Unable to expand file \r\n");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
}
}
}
The problem is that my progressbar isn't updating. I know a little C# but I'm a beginner to WPF and can't get my head around setting up a background worker to update my UI. Would someone be able to give me a few pointers please? Currently the app works fine, but the progressbar jumps to 100% finished and all of the text suddenly appears.
Thanks in advance!
Tom
First you'll want your background worker to handle the processes in its DoWork event. Within that event you can call the ProgressChanged event to update the progress bar. Below is an example:
private void btnRun_Click(object sender, RoutedEventArgs e)
{
if(workerThread.IsBusy == false) // Make sure someone doesn't click run multiple times by mistake
{
pBar1.Value = 0;
workerThread.RunWorkerAsync();
}
}
private void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
// Definitions and so forth
pBar1.Minimum = 0;
pBar1.Maximum = length;
int status = 0;
using (StreamReader sr = new StreamReader(filelist))
{
string line;
while ((line = sr.ReadLine()) != null)
{
// Try/Catch work here
status++;
workerThread.ReportProgress(status);
}
}
private void workerThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pBar1.Value = e.ProgressPercentage;
}
Just understand that the thread that's running the Form is the same one that will be used to update the form's controls. So if you have 'stuff' to do - like encrypting / decrypting lines from a file - you need to perform those items on another thread with a callback, otherwise the form display wont update until it's done with your stuff to do. You can raise events from inside a worker thread -- and catch them using an event handler on the main (form) thread to update the progress bar.
It seems that your UI thread is being blocked, in windows forms programming you have one message pump and while you main thread (UI) is doing something else it has to wait before it can process messages. You can fix this problem by setting up a background worker to send updates
For more information on UI thread and the message pump see this
http://www.codeproject.com/Articles/10311/What-s-up-with-BeginInvoke
For infomation on the backgroundworker thread see this
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Small Example code
// This event handler is where the time-consuming work is done.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}

Background Worker Locking Main Thread - Windows Forms C#

I have a background worker that I use to create files in the background.
I had it working so that the files were created and the UI was still responsive.
I made some changes and now I can't figure out why the background worker is locking my main thread.
Here are my background worker methods. I don't have a progress changed event.
private void filecreator_bgw_DoWork(object sender, DoWorkEventArgs e)
{
if (filecreator_bgw.CancellationPending == true)
{
e.Cancel = true;
}
else
{
myManager.createFiles((SelectedFileTypes) e.Argument);
}
}
private void filecreator_bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
//status_label.Text = "Canceled!";
}
else if (e.Error != null)
{
//status_label.Text = "Error: " + e.Error.Message;
}
else
{
// Check the file manager object to see if the files were created successfully
status_label.Text = "COMPLETE";
file_statusLabel.Text = "Files Created: " + DateTime.Now.ToShortTimeString();
System.Threading.Thread.Sleep(5000);
status_label.Text = "Click Create Files to Begin";
createfiles_button.Enabled = true;
}
}
Here is the method to create the files.
public void createFiles(SelectedFileTypes x)
{
if (string.IsNullOrEmpty(Filename) || (x.isCSV == false && x.isTAB == false && x.isXML == false))
{
filesCreated = false;
return;
}
// Declare the streams and xml objects used to write to the output files
XDocument xmlFile;
StreamWriter swCSV;
StreamWriter swTAB;
CSVFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
Path.GetFileNameWithoutExtension(Filename) + "CSV_TEST.csv";
swCSV = new StreamWriter(CSVFilename);
TABFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
Path.GetFileNameWithoutExtension(Filename) + "TAB_TEST.csv";
swTAB = new StreamWriter(TABFilename);
XMLFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
Path.GetFileNameWithoutExtension(Filename) + "XML_TEST.csv";
xmlFile = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment("Crosswalk"));
xmlFile.Add(new XElement("ACCOUNTS"));
// String array for use when creating xml nodes
string[] splits;
// String used to read in a line from the input file
string line = "";
// Use a try and catch block, if any errors are caught, return false
try
{
// Read each line in the file and write to the output files
using (StreamReader sr = new StreamReader(Filename))
{
int i = 0;
while ((line = sr.ReadLine()) != null)
{
if (x.isCSV)
{
swCSV.WriteLine(line.Replace(delim, ","));
}
if (x.isTAB)
{
swTAB.WriteLine(line.Replace(delim, "\t"));
}
if (x.isXML)
{
if (i <= 0)
{
i++;
continue;
}
splits = line.Split(new string[] { delim }, StringSplitOptions.RemoveEmptyEntries);
xmlFile.Root.Add(
new XElement("ACCOUNTS",
from s in header
select new XElement(s, splits[Array.IndexOf(header, header.Where(z => z.Equals(s, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault())])
)
);
}
}
// Dispose of all objects
swCSV.Close();
swCSV.Dispose();
swTAB.Close();
swTAB.Dispose();
if (x.isXML)
{
//xmlFile.Save(Path.GetFullPath(Filename) + Path.GetFileNameWithoutExtension(Filename) + "_TEST.xml");
xmlFile.Save(XMLFilename);
}
}
}
catch (Exception)
{
filesCreated = false;
return;
}
// Return true if file creation was successfull
filesCreated = true;
}
In the do work method, I build a simple struct to determine what output file types should be made and then I pass it to the method. If I comment out that call to create the files, the UI still does not respond.
In the create files method, I build out the files based on the input file that I am transforming. I do use a LINQ statement to help build out XML tags, but the arrays holding the tags values are small, 3-5 elements depending on the file chosen.
Is there a simple solution, or should I re-design the method. If I have to re-design, what are things I should keep in mind to avoid locking the main thread.
Thanks
Here is how I call the runworkerasync method:
private void createfiles_button_Click(object sender, EventArgs e)
{
SelectedFileTypes selVal = new SelectedFileTypes();
foreach (var structVal in outputformats_checkedListBox.CheckedItems)
{
if (structVal.ToString().Equals("CSV", StringComparison.InvariantCultureIgnoreCase))
selVal.isCSV = true;
if (structVal.ToString().Equals("TAB", StringComparison.InvariantCultureIgnoreCase))
selVal.isTAB = true;
if (structVal.ToString().Equals("XML", StringComparison.InvariantCultureIgnoreCase))
selVal.isXML = true;
}
// Call the FileManager object's create files method
createfiles_button.Enabled = false;
filecreator_bgw.RunWorkerAsync(selVal);
}
UPDATE:
I updated the call to start the worker and then the call to create the files using the argument passed into the worker.
You cannot interact with most UI controls directly from a BackgroundWorker. You need to access outputformats_checkedListBox.CheckedItems from the UI thread and pass the resulting SelectedFileTypes object into the BackgroundWorker as a parameter.
Also, pleas enote that your cancellation logic really didn't do much. In order for it to work well, you need to check CancellationPending throughout the process, not just when starting.
Here is a rough example of how you should start the worker:
private void StartWorker()
{
SelectedFileTypes selVal = new SelectedFileTypes();
foreach (var structVal in outputformats_checkedListBox.CheckedItems)
{
if (structVal.ToString().Equals("CSV", StringComparison.InvariantCultureIgnoreCase))
selVal.isCSV = true;
if (structVal.ToString().Equals("TAB", StringComparison.InvariantCultureIgnoreCase))
selVal.isTAB = true;
if (structVal.ToString().Equals("XML", StringComparison.InvariantCultureIgnoreCase))
selVal.isXML = true;
}
filecreator_bgw.RunWorkerAsync(selVal);
}
private void filecreator_bgw_DoWork(object sender, DoWorkEventArgs e)
{
SelectedFileTypes selVal = (SelectedFileTypes)e.Argument;
myManager.createFiles(selVal);
}

UnauthorizedAccessException on MediaElement in DatagramSocket.ReceivedMessage

I want start my mediaElement (instance of MediaElement class) at when first pack of data came. So I wrote it like that.
private void SocketOnMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
if (isPaused) return;
if (!isStarted)
{
mediaElement.Play();
isStarted = true;
}
var r = args.GetDataReader();
var l = r.UnconsumedBufferLength;
var buff = new byte[l];
r.ReadBytes(buff);
if (System.Text.Encoding.UTF8.GetString(buff, 0, buff.Length) != "stop")
{
AudioSteam.AddBytes(buff);
}
else
{
mediaElement.Pause();
isStarted = false;
Debug.WriteLine("stop");
}
buff = null;
}
Of course elier I set source for mediaElement (MediaStreamSource).
var socket = new DatagramSocket();
socket.MessageReceived += SocketOnMessageReceived;
await socket.BindServiceNameAsync("4444");
HostName multicast = new HostName("230.0.0.1");
socket.JoinMulticastGroup(multicast);
isPaused = true;
isStarted = false;
AudioSteam = new Sine440AudioStreamSource(44100);
mdiaElement.SetSource(AudioSteam);
At first I get System.IO.FileNotFoundException then System.UnauthorizedAccessException at mediaElement.Start(); I have no idea why.
Any suggestion will be appreciated.
It's turns out that DatagramSocket.ReceivedMessage method is running at other thread so If you want access variables out of method scope you need to use Dispatcher.BeginInvoke()
Dispatcher.BeginInvoke(() =>{
//Code
});
All in all I resign for that approach.

open differents threads using BackgroundWorker

i build an application how take Pcap file (wireshark file) and play the packets, the play operation is with exe file who get file path and interface int.
private void btnStart_Click(object sender, EventArgs e)
{
shouldContinue = true;
btnStart.Enabled = false;
btnStop.Enabled = true;
groupBoxAdapter.Enabled = false;
groupBoxRootDirectory.Enabled = false;
string filePath = string.Empty;
ThreadPool.QueueUserWorkItem(delegate
{
for (int i = 0; i < lvFiles.Items.Count && shouldContinue; i++)
{
this.Invoke((MethodInvoker)delegate { filePath = lvFiles.Items[i].Tag.ToString(); });
pcapFile = new PcapFile();
pcapFile.sendQueue(filePath, adapter);
}
this.Invoke((MethodInvoker)delegate
{
btnStart.Enabled = true;
btnStop.Enabled = false;
groupBoxAdapter.Enabled = true;
groupBoxRootDirectory.Enabled = true;
});
});
}
the sendQueue code:
public void sendQueue(string filePath, int deviceNumber)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo(#"D:\Downloads\SendQueue\sendQueue.exe");
processStartInfo.Arguments = string.Format("{0} {2}{1}{2}", (deviceNumber).ToString(), filePath, "\"");
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.CreateNoWindow = true;
processStartInfo.UseShellExecute = false;
processStartInfo.ErrorDialog = false;
using (Process process = Process.Start(processStartInfo))
{
process.WaitForExit();
}
}
Doen't look that you need Background worker.
List<string> tags = new List<string>();
foreach (object item in lvFiles.Items)
{
tags.Add(item.tag.ToString());
}
ThreadPool.QueueUserWorkItem(delegate
{
for (int i = 0; i < tags.Count && shouldContinue; i++)
{
sendQueue(tags[i], adapter);
}
//...
}
Your UI thread is most likely blocked because the pcapFile.sendQueue is synchronous. This means even though your async loop queues the play files the UI thread is busy 99.99% of the time playing the file's content. This may or may not be the case since you haven't posted PcapFile's source.
The task to make your UI responsive is a bit more involving, you need to restructure PcapFile to load up a frame (audio? video?) at a time and let the UI thread run the rest of the time or even to work completely in the background.
The form design should also rely on events from PcapFile instead of trying to run it in a BackgroundWorker

Categories