【问题标题】:How can I set the Properties of a DataGridViewComboBoxColumn in a thread? (C# Winforms)如何在线程中设置 DataGridViewComboBoxColumn 的属性? (C# Winforms)
【发布时间】:2010-09-29 05:02:18
【问题描述】:

我正在研究委托和简单的线程,我在 ComboBox 控件中进行了尝试,并在 DataGridViewComboBoxColumn 中进行了实验(因为我认为它会是相同的)但似乎没有 Invoke 属性为此种。

如何在线程中设置 DataGridViewComboBoxColumn 属性?
请查看我的代码,这适用于使用线程设置ComboBox 控件的属性:

    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" });
});
    }        

请帮助...提前致谢。

【问题讨论】:

    标签: c# winforms multithreading delegates


    【解决方案1】:

    创建如下所示的函数

    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 });
      }
    }
    

    这样称呼

    // 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);
    

    如果您使用的是 .NET 3.5 或更高版本,您可以将上述方法重写为 Control 类的扩展方法,这样可以简化对以下的调用:

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


    试试这个

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

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

    【讨论】:

    • 我认为这段代码:SetControlPropertyThreadSafe(dgvComboColumn, "Property", Value);不管用。由于 dgvComboColumn 不是 Control 类型,因此它是 DataGridViewComboBoxColumn。 SetControlPropertyThreadSafe() 第一个参数接受 Control 类型。
    • 你试过了吗:this.Invoke((MethodInvoker)delegate { dataGridViewComboBoxColumn1.Datasource= datasource; // 在 UI 线程上运行 dataGridViewComboBoxColumn1.DisplayMember = "DMembr"; // 在 UI 线程上运行 }) ;
    • hmm...是的,但我的问题是从不同的线程设置我的 DataGridViewComboBoxColumn 的 DisplayMember 和 ValueMember...
    【解决方案2】:

    使用您正在使用的 DataGridView 实例的 InvokeRequired 属性和 Invoke 方法。因为这些列链接到特定的 DGV,所以它们应该在同一个线程上。

    编辑:一些示例代码

    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";
    }      
    

    并更改您的线路
    //dataGridViewComboBoxColumn1.Invoke(delegateSetEvents, new object[] { dataSource, "ShortName", "LongName" }); });

    成为
    SetProperties(dataSource, "ShortName", "LongName");

    您希望在 SetProperties 内部进行 InvokeRequired 检查,以确保该方法是线程安全的。否则,如果一个方法在调用 SetProperties 之前没有确保它在正确的线程上,它可能会导致非法跨线程操作

    【讨论】:

    • 我完全按照你说的做了,但是我得到了 comboBox1 的这个错误(非法跨线程操作)。
    • 在哪一行?也许您应该检查 InitValues 是否从正确的线程运行,以便您知道 SetProperties 会正常。
    • private void SetMembers(ArrayList dataSource, string valueMember, string displayMember) { comboBox1.DataSource = dataSource;组合框1.ValueMember = valueMember;组合框1.DisplayMember = displayMember;组合框1.SelectedIndex = 0; if (dataGridView1.InvokeRequired) { dataGridView1.Invoke(new DelegateSetEvents(SetMembers), dataSource, valueMember, displayMember);返回; } dataGridViewComboBoxColumn1.DataSource = dataSource;
    • dataGridViewComboBoxColumn1.ValueMember = valueMember; dataGridViewComboBoxColumn1.DisplayMember = displayMember; }
    • invokeRequired 的内容必须在函数中的任何其他内容之前进行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多