【问题标题】:"Cross-thread operation is not valid" exception when trying to get value of comboBox尝试获取组合框的值时出现“跨线程操作无效”异常
【发布时间】:2013-08-06 17:28:11
【问题描述】:
"Cross-thread operation is not valid" exception

我多次遇到此异常,但所有这些时间我都是在设置控件的值。那次我使用了一个名为SetControlPropertyThreadSafe() 的函数解决了这个问题,该函数仅由stackoverflow.com 上的某个人建议。但是这次我在尝试获取组合框的值时遇到了这个异常。代码如下:

 string cat;
        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text.Trim().Length > 20)
            {
                System.Threading.Thread t = new System.Threading.Thread(addQuickTopic);
                t.Start();
            }
            else
                MessageBox.Show("The length of the title must be greater than 20", "Title length invalid", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }
        public string tTitle="";
        void addQuickTopic()
        {
            Global.SetControlPropertyThreadSafe(button1, "Text", "Working...");
            Global.SetControlPropertyThreadSafe(button1, "Enabled", false);
            Topic t = new Topic();
            t.setTitle(textBox1.Text);
            t.setDescription(" ");
            t.setDesID(Global.getMd5Hash(Common.uid+DateTime.Today.ToString()+DateTime.Today.Millisecond.ToString()));
            t.setUsrID(Common.uid);
            t.setReplyToID("");
            t.setConDate("0");
            cat = CategoryList.SelectedValue.ToString();

如您所见,我直接获取 textBox1.Text 而不应用任何线程安全操作。但是在最后一行尝试获取组合框的选定值时,我得到了这个异常。那么有人可以建议我在这种情况下该怎么做吗?以下是用于设置控件值的线程安全函数的代码:

public static void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue)
        {
            try
            {
                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 });
                }
            }
            catch (Exception)
            { }
        }

我是否需要创建一个类似的get 函数?还是有其他可用的解决方案?

【问题讨论】:

标签: c# .net multithreading winforms thread-safety


【解决方案1】:

现在,您从TextBox 获取值,通过:t.setTitle(textBox1.Text);。这也会失败。

我是否需要创建一个类似的 get 函数?还是有其他可用的解决方案?

是的,您需要一个 get 选项。但是,我建议不要使用反射和文本,并对其进行修改以使用通用方法和 lambda。

public static void SetControlPropertyThreadSafe<T>(T control, Action<T> action) where T : Control
    {
            if (control.InvokeRequired)
            {
                control.Invoke(action);
            }
            else
            {
                action();
            }
    }

这将允许您编写这个强类型,即:

Global.SetControlPropertyThreadSafe(button1, b => b.Text = "Working...");

你也可以做一个强类型的get方法:

public static U GetControlPropertyThreadSafe<T,U>(T control, Func<T,U> func) where T : Control
{
     if (control.InvokeRequired)
     {
         return (U)control.Invoke(func, new object[] {control});
     }
     else
     {
         return func(control);
     }
}

然后让你写:

 t.setTitle(Global.GetControlPropertyThreadSafe(textBox1, t => t.Text));

您也可以使用相同的方法来获取和设置组合框项目。

【讨论】:

  • 我在模板和线程方面没有那么先进。我像cat=Global.GetControlPropertyThreadSafe(CategoryList, cl =&gt; cl.SelectedValue).ToString(); 一样使用它,但它给了我Parameter count mismatch. 异常,您的代码在return func() 行中也有语法错误说Delegate func does not take 0 arguments 所以我用func(control) 替换它作为试用版。请告诉我正确的实现方式。
  • @ShivaPareek 我编辑以修复语法错误。试试看:cat=Global.GetControlPropertyThreadSafe(CategoryList, cl =&gt; cl.SelectedValue.ToString());
  • 感谢@ReedCopsey,它现在已经启动并运行了。
【解决方案2】:

您需要一个类似的 get 函数,如果需要,它会调用 Invoke。 这取决于 GUI 的线程模型,该模型规定所有与 GUI 交互的方法只能由 GUI 线程调用。

如果您尝试阅读、写作或做其他事情,这并不重要。如果您不在 GUI 线程上,则必须使用 Invoke。

【讨论】:

    猜你喜欢
    • 2016-04-19
    • 2021-02-09
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2021-09-10
    相关资源
    最近更新 更多