WinForms thread safe control access

◇◆丶佛笑我妖孽 提交于 2019-12-19 10:10:57

问题


I get error Control accessed from a thread other than the thread it was created on when I try to access WinForms control. I know that all modifications of control should be performed in UI thread (requiring BeginInvoke(), etc.), but I need my control to be read only.

Here is my simplified code:

string text = textBox.Text;

What is the pattern for accessing WinForms control's properties values from another thread?


回答1:


For something as trivial as this, you don't have to use BeginInvoke specifically, you could use Invoke as well, but yes you do need to invoke the call on the UI thread. You can use some magic to hide the nasty details in a couple method calls and then use extension methods to make it cleaner. For example, let says I wanted to extend the TextBox control with a couple theadsafe methods for getting and setting the Text property. I might do something like this:

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

Then in another thread you could call the textbox like so:

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:


You must use BeginInvoke. If you need to get a value back (eg, the Text contents of the control), you may use EndInvoke to wait for completion.

That said, you may want to consider doing things the other way; have the GUI thread 'push' data over to background worker threads. This helps reduce the chance of racing against user input, and leads to a cleaner design with a clear separation of GUI and core logic.



来源:https://stackoverflow.com/questions/6092519/winforms-thread-safe-control-access

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!