【问题标题】:WinForms thread safe control accessWinForms 线程安全控制访问
【发布时间】:2011-05-23 03:22:45
【问题描述】:

当我尝试访问 WinForms 控件时出现错误Control accessed from a thread other than the thread it was created on。我知道控件的所有修改都应该在 UI 线程中执行(需要 BeginInvoke() 等),但我需要我的控件是只读的。

这是我的简化代码:

string text = textBox.Text;

从另一个线程访问 WinForms 控件的属性值的模式是什么?

【问题讨论】:

    标签: winforms thread-safety


    【解决方案1】:

    对于像这样微不足道的事情,您不必专门使用 BeginInvoke,您也可以使用 Invoke,但是是的,您确实需要在 UI 线程上调用调用。您可以使用一些魔法来隐藏几个方法调用中令人讨厌的细节,然后使用扩展方法使其更清晰。例如,假设我想使用几个用于获取和设置 Text 属性的安全方法来扩展 TextBox 控件。我可能会这样做:

    namespace System.Windows.Forms
    {
        public static class TextBoxExtensions
        {        
            public static string GetTextThreadSafe(this TextBox box)
            {
                return GetTextBoxText(box);
            }
    
            public static void SetTextThreadSafe(this TextBox box, string str)
            {
                SetTextBoxText(box, str);
            }
    
            public static string GetTextBoxText(TextBox box)
            {
                if (box.InvokeRequired)
                {
                    Func<TextBox, string> deleg = new Func<TextBox, string>(GetTextBoxText);
                    return box.Invoke(deleg, new object[] { box }).ToString();
                }
                else
                {
                    return box.Text;
                }
            }
    
            public static void SetTextBoxText(TextBox box, string str)
            {
                if (box.InvokeRequired)
                {
                    Action<TextBox, string> deleg = new Action<TextBox, string>(SetTextBoxText);
                    box.Invoke(deleg, new object[] { box, str });
                }
                else
                {
                    box.Text = str;
                }
            }
        }
    }
    

    然后在另一个线程中,您可以像这样调用文本框:

    Thread t = new Thread(new ThreadStart(() =>
    {
        // Threadsafe call to set the text
        SomeTextBox.SetTextThreadSafe("asdf");
        // Threadsafe call to get the text
        MessageBox.Show(SomeTextBox.GetTextThreadSafe());                
    }));
    t.IsBackground = true;
    t.Start();
    

    【讨论】:

      【解决方案2】:

      必须使用 BeginInvoke。如果您需要取回一个值(例如,控件的 Text 内容),您可以使用 EndInvoke 等待完成。

      也就是说,您可能想考虑以另一种方式做事;让 GUI 线程将数据“推送”到后台工作线程。这有助于减少与用户输入竞争的机会,并通过明确分离 GUI 和核心逻辑来实现更简洁的设计。

      【讨论】:

        猜你喜欢
        • 2013-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多