WinForms 线程安全控制访问

发布于 2024-11-09 06:13:52 字数 243 浏览 3 评论 0原文

当我尝试访问 WinForms 控件时,出现错误从创建它的线程以外的线程访问控件。我知道控件的所有修改都应该在 UI 线程中执行(需要 BeginInvoke() 等),但我需要我的控件是只读的。

这是我的简化代码:

string text = textBox.Text;

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌梦深 2024-11-16 06:13:52

对于像这样微不足道的事情,您不必专门使用 BeginInvoke,您也可以使用 Invoke,但是您确实需要在 UI 线程上调用该调用。您可以使用一些魔法来隐藏几个方法调用中令人讨厌的细节,然后使用扩展方法使其更清晰。例如,假设我想使用几个用于获取和设置 Text 属性的 theadsafe 方法来扩展 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();

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();
素衣风尘叹 2024-11-16 06:13:52

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

也就是说,您可能需要考虑以其他方式做事;让 GUI 线程将数据“推送”到后台工作线程。这有助于减少与用户输入竞争的机会,并导致 GUI 和核心逻辑清晰分离的更简洁的设计。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文