This will probably sound strange for some of you, but I can not figure out right way to read joystick input without blocking my UI form. I have found this example on internet:
static void Main()
{
// Initialize DirectInput
var directInput = new DirectInput();
// Find a Joystick Guid
var joystickGuid = Guid.Empty;
foreach (var deviceInstance in directInput.GetDevices(DeviceType.Gamepad,
DeviceEnumerationFlags.AllDevices))
joystickGuid = deviceInstance.InstanceGuid;
// If Gamepad not found, look for a Joystick
if (joystickGuid == Guid.Empty)
foreach (var deviceInstance in directInput.GetDevices(DeviceType.Joystick,
DeviceEnumerationFlags.AllDevices))
joystickGuid = deviceInstance.InstanceGuid;
// If Joystick not found, throws an error
if (joystickGuid == Guid.Empty)
{
Console.WriteLine("No joystick/Gamepad found.");
Console.ReadKey();
Environment.Exit(1);
}
// Instantiate the joystick
var joystick = new Joystick(directInput, joystickGuid);
Console.WriteLine("Found Joystick/Gamepad with GUID: {0}", joystickGuid);
//Query all suported ForceFeedback effects
var allEffects = joystick.GetEffects();
foreach (var effectInfo in allEffects)
Console.WriteLine("Effect available {0}", effectInfo.Name);
//Set BufferSize in order to use buffered data.
joystick.Properties.BufferSize = 128;
// Acquire the joystick
joystick.Acquire();
// Poll events from joystick
while (true)
{
joystick.Poll();
var datas = joystick.GetBufferedData();
foreach (var state in datas)
Console.WriteLine(state);
}
}
I have installed sharpdx and I can see joystick axis output in console.
Now I want to display each axis data in separate textbox on my UI. So I changed few lines of code:
joystick.Poll();
var data = joystick.GetBufferedData();
foreach (var state in data)
{
if (state.Offset == JoystickOffset.X)
{
textBox1.Text = state.Value.ToString();
}
}
So this should pass data to textbox. If I write here Console.Writeline(state.Value) I will get data I want to display. Problem is, that this while loop blocks UI.
I would like to put this while loop in private void timer_tick and set maybe 10 milliseconds refresh rate. But I don't know how to access variables like var joystick in separate function. I have also read that this can be done with asynchronous programming. Sadly I am stuck now.
Can anybody help me with as simple solution as possible to this problem? Code example would be great.
Suppose you code with WinForm (deduced from blocking my UI form in your question).
Add a timer to your Form from the designer.
And add these lines in the Form's .ctor:
public partial class JoyStickForm : Form
{
public JoyStickForm()
{
InitializeComponent();
// ...Other initialization code has been stripped...
// Instantiate the joystick
var joystick = new Joystick(directInput, joystickGuid);
//Console.WriteLine("Found Joystick/Gamepad with GUID: {0}", joystickGuid);
timer1.Interval = 100;
timer1.Tick += (s, e) =>
{
joystick.Poll();
var lastState = joystick.GetBufferedData().Last(); //only show the last state
if (lastState != null)
{
if (lastState.Offset == JoystickOffset.X)
{
textBox1.Text = lastState.Value.ToString();
}
}
};
//start the timer
timer1.Enabled = true;
}
}
Explanations:
A refreshing rate of 100 times per second is unnecessarily fast, remember the refreshing rate of most monitors is about 60 Hz. I set it as 100 ms (10 refreshes per second), which is acceptable.
Using lambda expression, you have access to the variables like var joystick from the timer's tick handler.
In each freshing, only the last state in the data is displayed to the TextBox.
Related
I am in a bottleneck finishing a GUI in Windows Forms C#.
I am 100% new doing this and I think that I am mixing and messing around. Someone could help me please?
I am embedding an artificial vision application (developed in HALCON software and exported to C#). I resume this app in one class with one method having three outputs (couple of images and a string).
I put this class inside a while loop with other classes to iterate and interact with the outputs from the vision app till state statusFile is 1 to exit the loop.
Firstly I was using only the mean thread and my GUI got unresponsive when inside the while loop was getting into the vision.
Snippet of Start button:
public string pathFile { get; set; } // THIS DATA COMES FROM PREVIOUS WFORM
public DataTable dataLonas { get; set; }
public string namePro { get; set; }
public Thread Run_thread = null, run1 = null;
public static AutoResetEvent myResetEvent
= new AutoResetEvent(false); // initially set to false.
public VentanaIniciarProceso3()
{
InitializeComponent();
}
private void button_start_process_Click(object sender, EventArgs e)
{
string name_button = button_start_process.Text;
if (name_button == "Start")
{
boton_iniciar_proceso1.Text = "Pause"; // CHANGE THE LABEL
// instead having more buttons
run1 = new Thread(t => //HERE THE NEW THREAD
{
while (statusFile == 0) //
{
HObject ho_IMAGE_OPERARIOS = null;
HObject ho_ActualImageTrim = null;
HTuple hv_READ_OCR_STRING = new HTuple();
// HALCON CLASS
(hv_READ_OCR_STRING, ho_ActualImageTrim, ho_IMAGE_OPERARIOS) =
LONASapp.action(hv_AcqHandle, hv_AcqHandle_2, pathFile, namePro);
string codigo = hv_READ_OCR_STRING.ToString();
// EVAL CODE
int aux_aviso = EvalCodigoBeta.analizarAvisoBeta(codigo,
dataLonas, pathFile, namePro);
// EVAL FILE CLASSFICHERO.
// statusFichero para 1 o 0
// Variable que indique si fuerza operario
statusFile = EvalFichero.checkCarga(dataLonas, pathFile, namePro);
statusFile = ContinuarSalirProyecto.continuarSalir(statusFile);
// IF statusFile==1 It Will exit
}
})
{ IsBackground = true };
run1.Start(); // START IN BACKGROUND THE LOOP WITH THE CLASSES
}
else if (name_button == "Pause")
{
myResetEvent.WaitOne(); // SAME BUTTON WITH LABEL CHANGED TRYING
// TO PAUSE THE THREAD
boton_iniciar_proceso1.Text = "Resume";
}
else
{
myResetEvent.Set(); // SAME BUTTON WITH LABEL CHANGED
// TO "RESUME" TO UNPAUSE
boton_iniciar_proceso1.Text = "Pause";
}
}
After doing this change, the GUI gets responsive which is nice and the correct way I am sure is using different threads. But when clicking again to the button which has changed the label to "Pause", it does not pause the thread run1, it continues… and now the GUI gets paused/unresponsive when cause of myResetEvent.WaitOne();
Could I ask you for help please? I am confused also and do not know where to continue or what to change…
Thanks a lot in advance. I really want to close this thing after 5 days not coming with the good idea.
I am using slimdx to interpret xbox controller button presses. I poll every 200ms to read the xbox button states and all works for me. I use
JoystickState state = Joystick.GetCurrentState();
// get buttons states
bool[] buttonsPressed = state.GetButtons();
Is there anyway to generate events on the button press instead of polling? To explain imagine if my poll time was 5 seconds. And the user presses a button in the 2nd second and releases it. In the next poll time my application will never know that the button was pressed
No - in DirectX you must poll. To do this efficiently you want to create a polling thread, and have a class which raises cross thread events to your consuming thread.
I know this is 4 years old but the answer is incorrect. The most efficient way may be to poll, but you can raise an event when you poll.
This is a work in progress but it should get someone started. Save this as a new class, it derives from a Timer, so once you add this to your project, build it, and drag it onto the Form you want to use it, you can then subscribe to the buttonPressed event.
public class GamePadController : Timer
{
public delegate void ButtonPressedDelegate(object sender, int ButtonNumber);
public event ButtonPressedDelegate ButtonPressed;
List<DeviceInstance> directInputList = new List<DeviceInstance>();
DirectInput directInput = new DirectInput();
List<SlimDX.DirectInput.Joystick> gamepads = new List<Joystick>();
SlimDX.DirectInput.JoystickState state;
public GamePadController()
{
this.Interval = 10;
this.Enabled = true;
this.Tick += GamePadController_Tick;
RefreshGamePads();
}
private void RefreshGamePads()
{
directInputList.Clear();
directInputList.AddRange(directInput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly));
gamepads.Clear();
foreach (var device in directInputList)
{
gamepads.Add(new SlimDX.DirectInput.Joystick(directInput, directInputList[0].InstanceGuid));
}
}
private void GamePadController_Tick(object sender, EventArgs e)
{
foreach (var gamepad in gamepads)
{
if (gamepad.Acquire().IsFailure)
continue;
if (gamepad.Poll().IsFailure)
continue;
if (SlimDX.Result.Last.IsFailure)
continue;
state = gamepad.GetCurrentState();
bool[] buttons = state.GetButtons();
for (int i = 0; i < buttons.Length; i++)
{
if (buttons[i])
{
if (ButtonPressed != null)
{
ButtonPressed(gamepad, i);
}
}
}
gamepad.Unacquire();
}
}
}
}
I am reading data values from a serial port and plotting the data in realtime on a zedgraph control using invoke and delegate. I would like to click a disconnect button that will stop the plotting and when a connect button is pressed, the plotting will resume. My problem is when I reconnect, the plotting will not be displayed at 1 point per second. There will be unexpected behavior that sometimes includes a delay that will not plot for 2 seconds and the next second it will plot 2 points at the same time. Sometimes it will not plot for 3 seconds and the next second, it will plot 3 points at the same time and sometimes it will work fine plotting 1 point per second. Sometimes it will plot twice or three times per second. This problem occurs only when I disconnect and then reconnect. My GUI response also begins to get worse with every time I disconnect and reconnect until finally not responding.
When I click disconnect, I clear the zedgraph but don't close the serial port. When I re-click connect again, the serial port will begin sending data again and continue to plot, calling control.invoke every time a new data point is plotted onto the zedgraph. Is the problem that I am calling invoke too many times and how would I get around this? I need to plot in realtime, so each time I receive a data point, plot it on the zedgraph right away.
Here is how I connect to the serial port:
private void btnConnect_Click_1(object sender, EventArgs e)
{
curveUSB = myPaneUSB.AddCurve("Load", listUSB, Color.Black, SymbolType.Circle);
isConnected = true;
DateTime startTime = DateTime.Now;
txtStartTime.Text = startTime.ToString();
sw.Start();
createCSVFile(startTime);
try
{
if (!serialPort1.IsOpen)
{
serialPort1.PortName = cmbPort.Items[cmbPort.SelectedIndex].ToString();
//Other Serial Port Property
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.DataBits = 8;
serialPort1.BaudRate = 9600;
//Open our serial port
serialPort1.Open();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Thread.Sleep(100); //Always sleep before reading
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceivedHandler);
// Save the beginning time for reference
tickStart = Environment.TickCount; //used the calculate the time
setGraphAxis(myPaneUSB, zgControlUSB);
//Disable Connect button
btnConnect.Enabled = false;
//Enable Disconnect button
btnDisconnect.Enabled = true;
}
Invoke and serialPort1_DataReceivedHandler:
private void serialPort1_DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
if (isConnected == true)
{
txtUSBLoad.Invoke(new EventHandler(delegate
{
strRawData = serialPort1.ReadLine();
txtUSBLoad.Text = strRawData + loadUnit;
Display_Data(strRawData, curveUSB, listUSB, zgControlUSB);
}));
}
}
Display_Data function to display the plot:
private void Display_Data(String data, LineItem curve, IPointListEdit list, ZedGraphControl zgControl)
{
ts = sw.Elapsed;
tsBT = swBT.Elapsed;
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}",tsBT.Hours, tsBT.Minutes, tsBT.Seconds);
elapsedTimeBT = String.Format("{0:00}:{1:00}:{2:00}", tsBT.Hours, tsBT.Minutes, tsBT.Seconds);
txtElapsedTime.Text = elapsedTime;
txtBTElapsedTime.Text = elapsedTimeBT;
if (zgControl.GraphPane.CurveList.Count <= 0) //Make sure that the curvelist has at least one curve
return;
curve = zgControl.GraphPane.CurveList[0] as LineItem; //Get the first CurveItem in the graph
if (curve == null)
return;
list = curve.Points as IPointListEdit; //Get the PointPairList
if (list == null) //If this is null, it means the reference at curve.Points does not
return; //support IPointListEdit, so we won't be able to modify it
time = (Environment.TickCount - tickStart) / 1000.0; //Time is measured in seconds
//Get current time
now = DateTime.Now;
timestamp = now.ToOADate();
list.Add(timestamp, Convert.ToDouble(data));
if(fileWriter.BaseStream != null){ //If fileWriter is open, then write to file, else don't write
fileWriter.WriteLine(String.Format("{0:yyyy-MM-dd_HH-mm-ss}", now) + "," + data); //writes the timestamp and data to the CSV file
}
if (Convert.ToDouble(data) > tempLoad) //Checks if the current load is the maximum load
{
tempLoad = Convert.ToDouble(data);
txtMaxLoad.Text = tempLoad.ToString() + " " + loadUnit;
txtBTMaxLoad.Text = tempLoad.ToString() + " " + loadUnit;
}
//if ((Convert.ToDouble(data) > dblThreshold) && (emailAlerts == true)) {
if ((Convert.ToDouble(data) > 50) && (emailAlerts == true))
{
sendEmail(Convert.ToDouble(data));
}
XDate dateTime = curve[0].X;
zgControl.AxisChange(); //changes the x-axis
zgControl.Invalidate(); //Force a redraw
}
Disconnect button:
private void btnDisconnect_Click_1(object sender, EventArgs e)
{
zgControlUSB.GraphPane.CurveList.Clear();
if (fileWriter != null)
{
fileWriter.Close();
}
isConnected = false;
btnConnect.Enabled = true;
btnDisconnect.Enabled = false;
txtUSBLoad.Text = initText;
DateTime endTime = DateTime.Now;
txtEndTime.Text = endTime.ToString(); //displays the time stamp when the plotting stops
sw.Stop(); //stops the stop watch
}
When I disconnect, I do not close the serial port because the problem is worse when I do and I read that it is not good to always close and reopen a serial port. Instead, I used an isConnected flag to start and stop plotting.
Any help is appreciated! Thanks in advance!
Calling txtUSBLoad.Invoke() will switch processing onto the GUI thread (the same thread that is used to handle user input and draw the controls). By putting all the processing inside the call to Invoke() you are effectively swamping the GUI thread.
If your serial updates are frequent enough this will result in delayed interactions/re-drawing of the GUI.
You have a few options here, the first thing is to keep all the processing in the thread that receives the messages from the serial port. Look at all the visual controls that you are updating and the determine what data they need to be updated and process as much of that before calling Invoke(). Create a class to hold the data.
This might be too slow which will mean that you'll have a backlog of serial data building up which you can't process in time. If so, you can conflate the incoming data if you're ok with losing updates. You'll have to see if this applies to your situation.
If you want to try and parallelise the processing of the incoming data look into TPL Dataflow for an example of how to create a processing pipeline for the data.
I have the code below where it update the data within listview, I was trying to pass parameter into main code which update the listview table.
I have external code that can send burst data stream and it shown same value on the list.
Below is based on anonymous method which work but earlier data get overwritten.
The listview is too slow which slow down main program (not listed here) the burst data goes to this code and use separate thread to handle the display (about 20 set). The burst data is about 20 set of dataTX array, etc.
I'm open for suggestion how to fix this.
==========================================================================
public void LIN_Request_Add_Message(bool isCRCIncluded) // This Add new line for request based message.
{
byte[] dataTX = new byte[10];
dataTX = myLinTools.LinArrayTXArray();
DateTime d = DateTime.Now;
this.ReqAddMessageThread = new Thread(delegate() { ReqAddMessageThreadProc(isCRCIncluded, dataTX, d); }); //anonymous method
this.ReqAddMessageThread.Start();
}
#endregion
private void ReqAddMessageThreadProc(bool isCRCIncluded, byte[] dataTX, DateTime d)
{
if (this.OutputView.InvokeRequired)
{
test1Callback del = new test1Callback(ReqAddMessageThreadProc);
this.Invoke(del, new object[] { isCRCIncluded, dataTX,d });
return;
}
if (this.Visible == true)
{
SendMessage(this.Handle, WM_SETREDRAW, false, 0);
}
int length = myLinTools.LINDataLength;
int pCRC = 0;
elem = new ListViewItem(m_Item.ToString());
elem.SubItems.Add(d.Date.ToShortDateString());
elem.SubItems.Add(d.ToShortTimeString() + ":" + d.Second.ToString());
elem.SubItems.Add("");
for (int i = 0; i < length + 1; i++)
{
elem.SubItems.Add(dataTX[i].ToString("X2"));
pCRC = i;
}
for (int i = length; i < 8; i++)
{
elem.SubItems.Add(" "); // fill gaps
}
if (isCRCIncluded == true) // Does the message contains processed CRC data?
{
elem.SubItems.Add(dataTX[pCRC + 1].ToString("X2"));
}
else // No, then make one for display only!!
{
Byte CRC = myLinTools.CRC_Processor(false);
elem.SubItems.Add(CRC.ToString("X2"));
}
this.OutputView.Items.Add(elem);
this.OutputView.EnsureVisible(m_Item);
if (myLinTools.IsRequestResponse == true) // Request Message Only
{
if (this.Visible == true) // Is form open?
{
SendMessage(this.Handle, WM_SETREDRAW, true, 0);
this.Refresh();
}
}
m_Item++;
}
=================================================================================
Thanks KazR, I modified the code which worked fine, however it slow down the other high level program (call it main program), that making data transfer to this program that display data. One of the requirement that the main program stream the data without delay or pause cause by listview in this display program. That why I'm looking for way to use thread, so it release the control back to main program and thus operates faster, but however there is issue in keep data from being over-written by next thread, since listview is slow. Perhaps I should consider a buffer, which update only when there is no activity in main program.
I do not wish to use virtual, I'm open for alternative suggestion.
==================================================================================
delegate void ReqAddMessageTCallback(bool isCRCIncluded, byte[] dataTX, DateTime d);
#region//==================================================LIN_Request_Add_Message
public void LIN_Request_Add_Message(bool isCRCIncluded) // This Add new line for request based message.
{
byte[] dataTX = new byte[10];
dataTX = myLinTools.LinArrayTXArray();
DateTime d = DateTime.Now;
ReqAddMessageThreadProc(isCRCIncluded, dataTX, d);
}
#endregion
#region//==================================================ReqAddMessageThreadProc
private void ReqAddMessageThreadProc(bool isCRCIncluded, byte[] dataTX, DateTime d)
{
if (this.OutputView.InvokeRequired)
{
ReqAddMessageTCallback del = new ReqAddMessageTCallback(ReqAddMessageThreadProc);
this.BeginInvoke(del, new object[] { isCRCIncluded, dataTX, d });
return;
}
if (this.Visible == true)
{
SendMessage(this.Handle, WM_SETREDRAW, false, 0);
}
int length = myLinTools.LINDataLength;
int pCRC = 0;
elem = new ListViewItem(m_Item.ToString());
From your code example it appears that you're creating a new Thread object each time you receive data and all this thread is doing is calling the ReqAddMessageThreadProc method. Assuming that calls to LIN_Request_Add_Message are not being made in the main UI thread, you could try removing the Thread creation & start calls, replace them with a direct call the ReqAddMessageThreadProc and use BeginInvoke rather than Invoke.
e.g.
public void LIN_Request_Add_Message(bool isCRCIncluded) // This Add new line for request based message.
{
byte[] dataTX = new byte[10];
dataTX = myLinTools.LinArrayTXArray();
DateTime d = DateTime.Now;
ReqAddMessageThreadProc(isCRCIncluded, dataTX, d);
}
#endregion
private void ReqAddMessageThreadProc(bool isCRCIncluded, byte[] dataTX, DateTime d)
{
if (this.OutputView.InvokeRequired)
{
test1Callback del = new test1Callback(ReqAddMessageThreadProc);
this.BeginInvoke(del, new object[] { isCRCIncluded, dataTX,d });
return;
}
etc...
The BeginInvoke call is the async version of Invoke, this should negate the need to use separate new Thread objects each time you receive new data.
You should make your ListView virtual. Then you can operate at full speed with your threads and the listview will display only the items which are currently visible. If you do append things to the ListView and not force to make it visible every time something is added you can let the user decide when he does want to scroll down. He does see when things are appended because the scrollbar is becoming smaller and smaller while items are added.
This way you can display millions of entries without any issues and you will get rid of ivoking, redrawing, refreshing the listview via SendMessage. Here is a virtual list view sample how you can change it.
By doing so your code will become simpler and faster because you do not mix background data processing with UI stuff. E.g. sorting can be done at raw data array level without doing anything in the UI except to trigger it.
I have this tricky task I've been trying to achieve for quiet sometime but till now I couldn't think of anything to make it work. anyway here is the scenario...
I have a winform application contains a listview and a button.
the listview contains 1 column which holds the data I need to pass to my functions later on. the column contains lets say 50 rows containing a list of links.
Now I have this function which I'm using to fetch and grab the contents of these links (5 links at a time) with parallel multithreaded mode using (Task Parallel Library):
//List<int> currentWorkingItem //contains the indices of the items in listview
//List<string> URLsList //contains the URLs of the items in listview
Parallel.ForEach(URLsList, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, (url, i, j) =>
{
//show to user this link is currently being downloaded by highlighting the item to green...
this.BeginInvoke((Action)(delegate()
{
//current working item
mylistview.Items[currentWorkingItem[(int)j]].BackColor = green;
}));
//here I download the contents of every link in the list...
string HtmlResponse = GetPageResponse(url);
//do further processing....
});
Now the above code works perfectly... but sometimes I want the user to abort certain thread which is currently running and continue with the rest of the threads in the list... is that achievable in this? if so please help me out.. I'd really appreciate any solution or suggestions..
Try using Task library with cancellation tokens. I find it more elegant and safer approach to do your thing. Here is a quote good example of doing that:
using System;
using System.Threading.Tasks;
using System.Threading;
namespace CancelTask
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press 1 to cancel task");
var cTokenSource = new CancellationTokenSource();
// Create a cancellation token from CancellationTokenSource
var cToken = cTokenSource.Token;
// Create a task and pass the cancellation token
var t1 = Task<int>.Factory.StartNew(()
=> GenerateNumbers(cToken), cToken);
// to register a delegate for a callback when a
// cancellation request is made
cToken.Register(() => cancelNotification());
// If user presses 1, request cancellation.
if (Console.ReadKey().KeyChar == '1')
{
// cancelling task
cTokenSource.Cancel();
}
Console.ReadLine();
}
static int GenerateNumbers(CancellationToken ct)
{
int i;
for (i = 0; i < 10; i++)
{
Console.WriteLine("Method1 - Number: {0}", i);
Thread.Sleep(1000);
// poll the IsCancellationRequested property
// to check if cancellation was requested
if (ct.IsCancellationRequested)
{
break;
}
}
return i;
}
// Notify when task is cancelled
static void cancelNotification()
{
Console.WriteLine("Cancellation request made!!");
}
}
}
Original article could be found here: http://www.dotnetcurry.com/ShowArticle.aspx?ID=493
ok after struggling with this I finally found an efficient and an easy solution for this..
it required me only a hashtable which contains the indicies of the selected items in the listview and a simple bool value. the index is the key and the bool (true, false) is the value. the bool value is like an (on/off) switch indicates that the current loop is aborted or not.. so in order to abort specific thread simple I need to pass the key(the index) of the selected item on my listview to the foreach loop and check if the bool switch is on or off and that's basically it...
so my final code will be like this:
//I declared the hashtable outside the function so I can manage it from different source.
private Hashtable abortingItem;
Now when I click grab button it should fill the hashtable with the selected indicies...
abortingItem = new Hashtable();
for (int i = 0; i < myURLslist.SelectedItems.Count(); i++)
{
//false means don't abort this.. let it run
abortingItem.Add(myURLslist.SelectedItems[i].index, false);
}
//here should be the code of my thread to run the process of grabbing the URLs (the foreach loop)
//..........................
now if I need to abort specific item all I need is to select the item in the listview and click abort button
private void abort_Click(object sender, EventArgs e)
{
if (abortingItem != null)
{
for (int u = 0; u < myURLslist.SelectedIndices.Count; u++)
{
//true means abort this item
abortingItem[myURLslist.SelectedIndices[u]] = true;
}
}
}
In my foreach loop all I need is a simple if else statement to check if the bool is on or off:
//List<int> currentWorkingItem //contains the indices of the items in listview
//List<string> URLsList //contains the URLs of the items in listview
Parallel.ForEach(URLsList, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, (url, i, j) =>
{
//aborting
if (!(bool)abortingItem[currentWorkingItem[(int)j]])
{
//show to user this link is currently being downloaded by highlighting the item to green...
this.BeginInvoke((Action)(delegate()
{
//current working item
mylistview.Items[currentWorkingItem[(int)j]].BackColor = green;
}));
//here I download the contents of every link in the list...
string HtmlResponse = GetPageResponse(url);
//do further processing....
}
else
{
//aborted
}
});
that's simply it..