Resolved Help with Parallel.ForEach Loop

centaur

Member
Joined
Dec 17, 2017
Messages
12
Location
Houston
Programming Experience
3-5
This is the first time I use a Parallel.ForEach loop and hoping I can get some help with it. So basically within the Parallel.ForEach loop, I'm doing unit coversions but in the example code below, I am just getting the To / From units to be concatenated which would then be used to select the correct conversion formula. Below is an example. There's more code than what I'm showing but I don't think it's needed to get the help I'm looking for.
The code works great when the if (tmp_cbox.Name == "P1_Units_CBox") block is true but when the else if (tmp_cbox.Name == "Viscosity_Units_CBox") in red text below is true, I get the following error:
Message=Cross-thread operation not valid: Control 'Viscosity_Type_CBox' accessed from a thread other than the thread it was created on.
To give a little more detail, in the else-if block that's causing the error, there are two (2) comboboxes that are looked at. Viscosity_Type_CBox combobox allows the user to choose whether Dynamic or Kinematic viscosity is to be used. The Viscosity_Units_CBox combobox is then updated to include the units based on the Viscosity_Type_CBox selection.

I would appreciate any help you could provide in getting this to work properly and getting an understanding to the cause of the eror. I'm aware of BackgroundWorker but not sure how to use it. If there are better ways than BackgroundWorker, please suggest. Thank you!!


C#:
Parallel.ForEach(unit_list, unit =>
    // Call to Get_From_To_Unit_Concat with return of the To / From units concatenated
    tmp_concat_units = Get_From_To_Unit_Concat(pre_selected_unit, unit, unit_list, tmp_cbo);                 
});

//****************************************************************

private string Get_From_To_Unit_Concat(string temp_curr_unit, string unit, List<string> tmp_umits_list, ComboBox tmp_cbox)
{
    string pre_selected_unit = string.Empty;
    string post_selected_unit = string.Empty;
    List<string> get_cbo_list = new List<string>();   
    
    if (tmp_cbox.Name == "P1_Units_CBox")
    {
        get_cbo_list = new List<string> { "psig", "psia", "barg", "bara", "kg_cm2_g", "kg_cm2_a", "kPa_g", "kPa_a", "in_wc_g", "mm_wc_g", "Pa_g", "Pa_a", "MPa_g", "MPa_a" };
    }
    [COLOR=rgb(184, 49, 47)]else if (tmp_cbox.Name == "Viscosity_Units_CBox")
    {
        if (Viscosity_Type_CBox.SelectedIndex == 0)
            get_cbo_list = new List<string> { "cP", "mPa_s", "lbm_ft_s", "kg_m_s", "Pa_s" };
        else if (Viscosity_Type_CBox.SelectedIndex == 1)
            get_cbo_list = new List<string> { "cSt", "SSU", "mm2_s", "ft2_s" };
    }[/COLOR]
    
    // code continues........
 
Solution
Don't access UI controls from secondary threads, instead gather the data you need from the controls first (do that before the Parallel.ForEach) and pass that to the worker. In the code you posted the method needs the tmp_cbox.Name string and the Viscosity_Type_CBox.SelectedIndex int values as input, in addition to the other parameters. You could create a 'InputData' class that holds the necessities as a unit, so you would only need a single input parameter.
Don't access UI controls from secondary threads, instead gather the data you need from the controls first (do that before the Parallel.ForEach) and pass that to the worker. In the code you posted the method needs the tmp_cbox.Name string and the Viscosity_Type_CBox.SelectedIndex int values as input, in addition to the other parameters. You could create a 'InputData' class that holds the necessities as a unit, so you would only need a single input parameter.
 
Solution
For future reference, please flag a post as the solution if it provides the resolution to your problem and mark the thread Resolved if it is resolved. That lets us know that you don't need any further assistance without our having to open the thread, which is a time-saver for those of us who help a lot.
 
Back
Top Bottom