views:

26

answers:

2

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.

+1  A: 

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
I can't imagine how.... :(
yonan2236
ok thanks, i'll try...
yonan2236
I did exactly what you said, but I got this error (Illegal Cross Thread Operation) for the comboBox1.
yonan2236
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
this is my edited code base from your post...:
yonan2236
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
dataGridViewComboBoxColumn1.ValueMember = valueMember; dataGridViewComboBoxColumn1.DisplayMember = displayMember; }
yonan2236
and it's throwing Illegal Cross Thread Operation
yonan2236
The invokeRequired stuff has to go before anything else in the function
JamesMLV
A: 

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 : http://stackoverflow.com/questions/661561/how-to-update-gui-from-another-thread-in-c

Aamod Thakur
ok sir, I will try yours.
yonan2236
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
Did you try this : this.Invoke((MethodInvoker)delegate { dataGridViewComboBoxColumn1.Datasource= datasource; // runs on UI thread dataGridViewComboBoxColumn1.DisplayMember = "DMembr"; // runs on UI thread});
Aamod Thakur
hmm... yes, but my problem is setting DisplayMember and ValueMember of my DataGridViewComboBoxColumn from different thread...
yonan2236
are you getting any error?
Aamod Thakur
did it work for u?
Aamod Thakur