1

I'm studying delegates and simple threading, I tried it in a ComboBox control, and experimented in a DataGridViewComboBoxColumn (cause I thought it would be the same) but it seems there's no Invoke property for this kind.

How can I set DataGridViewComboBoxColumn properties in a thread?
Please see my code, this works for setting the properties of a ComboBox control using a thread:

    private delegate void DelegateSetProperties(DataTable dataSource, string valueMember, string displayMember);

    Thread thread1;
    DelegateSetProperties delegateSetProperties;

    private void Form1_Load(object sender, EventArgs e)
    {
        delegateSetProperties = new DelegateSetProperties(SetProperties);

        thread1 = new Thread(new ThreadStart(InitValues));
        thread1.IsBackground = true;
        thread1.Start();
    }

    private void SetProperties(DataTable dataSource, string valueMember, string displayMember)
    {
        comboBox1.DataSource = dataSource;
        comboBox1.ValueMember = valueMember;
        comboBox1.DisplayMember = displayMember;
        comboBox1.SelectedIndex = 0;

        //dataGridViewComboBoxColumn1.DataSource = dataSource;
        //dataGridViewComboBoxColumn1.DisplayMember = valueMember;
        //dataGridViewComboBoxColumn1.ValueMember = displayMember";
    }      

    void InitValues()
    {
        var dt = new DataTable
                {
                    TableName = "CATEGORY",
                    Columns = {
                                {"CategoryCode", typeof(string)},
                                {"Name", typeof(string)},
                              }
                };

                dt.Rows.Add("C1", "Category1");
                dt.Rows.Add("C2", "Category2");
                dt.Rows.Add("C3", "Category3");
                // and so on...
        comboBox1.Invoke(delegateSetProperties, new object[] { dt, "CategoryCode", "Name" 
        //dataGridViewComboBoxColumn1.Invoke(delegateSetEvents, new object[] { dt, "CategoryCode", "Name" });
});
    }        

Please help...thanks in advance.

yonan2236
  • 13,371
  • 33
  • 95
  • 141

2 Answers2

1

Use the InvokeRequired property and Invoke method of the DataGridView instance you're working with. Because the columns are linked to a specific DGV, they should be on the same thread.

Edit: Some example code

private void SetProperties(DataTable dataSource, string valueMember, string displayMember)
{
    if (dataGridView1.InvokeRequired){
         dataGridView1.Invoke(new DelegateSetProperties(SetProperties), dataSource, valueMember, displayMember);
         return;
    }

    dataGridViewComboBoxColumn1.DataSource = dataSource;
    dataGridViewComboBoxColumn1.DisplayMember = valueMember;
    dataGridViewComboBoxColumn1.ValueMember = displayMember";
}      

and change your line that says
//dataGridViewComboBoxColumn1.Invoke(delegateSetEvents, new object[] { dataSource, "ShortName", "LongName" }); });

to be
SetProperties(dataSource, "ShortName", "LongName");

You want to do the InvokeRequired check inside of SetProperties to make sure that the method is thread safe. Otherwise, if a method didn't make sure it was on the right thread before calling SetProperties, it could cause an Illegal Cross Thread Operation

JamesMLV
  • 2,236
  • 18
  • 19
  • I did exactly what you said, but I got this error (Illegal Cross Thread Operation) for the comboBox1. – yonan2236 Sep 29 '10 at 05:31
  • On what line? Maybe you should be checking that InitValues is being run from the correct thread, so that you know SetProperties will be okay. – JamesMLV Sep 29 '10 at 05:39
  • private void SetMembers(ArrayList dataSource, string valueMember, string displayMember) { comboBox1.DataSource = dataSource; comboBox1.ValueMember = valueMember; comboBox1.DisplayMember = displayMember; comboBox1.SelectedIndex = 0; if (dataGridView1.InvokeRequired) { dataGridView1.Invoke(new DelegateSetEvents(SetMembers), dataSource, valueMember, displayMember); return; } dataGridViewComboBoxColumn1.DataSource = dataSource; – yonan2236 Sep 29 '10 at 06:11
  • dataGridViewComboBoxColumn1.ValueMember = valueMember; dataGridViewComboBoxColumn1.DisplayMember = displayMember; } – yonan2236 Sep 29 '10 at 06:12
  • The invokeRequired stuff has to go before anything else in the function – JamesMLV Sep 29 '10 at 13:35
1

Create a function as shown below

private delegate void SetControlPropertyThreadSafeDelegate(Control control, string propertyName, object propertyValue);

public static void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue)
{
  if (control.InvokeRequired)
  {
    control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue });
  }
  else
  {
    control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue });
  }
}

Call it like

// thread-safe equivalent of
// myLabel.Text = status;
SetControlPropertyThreadSafe(myLabel, "Text", status);

//In your case get the object of the dgv combo column
SetControlPropertyThreadSafe(dgvComboColumn, "Property", Value);

OR

If you're using .NET 3.5 or above, you could rewrite the above method as an extension method of the Control class, which would then simplify the call to:

    myLabel.SetPropertyThreadSafe("Text", status);
//In your case get the object of the dgv combo column

     dgvComboColumn.SetPropertyThreadSafe("Property", Value);

OR


Try this

this.Invoke((MethodInvoker)delegate {
    dgvComboColumn.FieldName= xColumnName; // runs on UI thread
    dgvComboColumn2.Visible = true; // runs on UI thread
});

Stackoverflow Reference : How to update the GUI from another thread in C#?

Community
  • 1
  • 1
Thakur
  • 1,890
  • 5
  • 23
  • 33
  • I think this code : SetControlPropertyThreadSafe(dgvComboColumn, "Property", Value); will not work. Since dgvComboColumn is not a Control type, it is a DataGridViewComboBoxColumn. SetControlPropertyThreadSafe() first argument accepts a Control type. – yonan2236 Sep 29 '10 at 05:45
  • Did you try this : this.Invoke((MethodInvoker)delegate { dataGridViewComboBoxColumn1.Datasource= datasource; // runs on UI thread dataGridViewComboBoxColumn1.DisplayMember = "DMembr"; // runs on UI thread }); – Thakur Sep 29 '10 at 06:18
  • hmm... yes, but my problem is setting DisplayMember and ValueMember of my DataGridViewComboBoxColumn from different thread... – yonan2236 Sep 29 '10 at 06:28