簡體   English   中英

如何修復我的后台解決方案以進行線程安全調用?

[英]How to fix my Background solution to make thread-safe calls?

我試圖從另一個線程設置TextBox的Text屬性。 我在下面得到了這個例外;

"Cross-thread operation not valid: Control 'recTpcTxt' accessed from a thread other than the thread it was created on."

然后,我使用BackgroundWorker解決了此問題。 但是,我遇到了同樣的異常消息。

編輯[1]: 實際上,我自己對此鏈接進行了指導; https://msdn.microsoft.com/zh-CN/library/ms171728(v=vs.110).aspx 我可以使用invokeproperty解決問題。 但是,我無法使用backgroundworker解決問題。

我的解決方案有問題嗎? 如何解決我的解決方案以設置UI變量的某些屬性?

EDIT [2]: 更多代碼可用來澄清問題;

MqttManager.cs;

public partial class MqttManager : Form
    {
        MqttHandler mqttHandler = new MqttHandler();
        public static MqttManager managerInst;

        public MqttManager()
        {
            InitializeComponent();
            managerInst = this;
            ...
        }

        ...

        private BackgroundWorker backgroundWorker;

        public void NotifyUIForRecMsg(string topic, string message)
        {
            object[] objArr = { topic, message };
            this.backgroundWorker.RunWorkerAsync(objArr);
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            System.Threading.Thread.Sleep(5000);
            e.Result = e.Argument;
        }

        private void backgroundWorker_RunWorkerCompleted(
            object sender,
            RunWorkerCompletedEventArgs e)
        {
            object[] res = (object[])e.Result;
            this.recTpcTxt.Text = (String)res[0];
        }
    }

MqttManager.Design.cs;

partial class MqttManager
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            ...

            this.backgroundWorker = new System.ComponentModel.BackgroundWorker();
            this.backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker_DoWork);
            this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker_RunWorkerCompleted);
        }
        #endregion

        ...
     }

MqttHandler.cs;

class MqttHandler
    {
        MqttClient client;

        ...

        /// <summary>
        /// Publish received event handler.
        /// </summary>
        private void client_MqttMsgPublishReceived(Object sender, MqttMsgPublishEventArgs e)
        {
            MqttManager.managerInst.NotifyUIForRecMsg(e.Topic, Encoding.UTF8.GetString(e.Message));
        }
     }

檢查一下: https : //msdn.microsoft.com/zh-cn/library/ms171728(v=vs.110).aspx

基本上,要設置控件屬性,您必須位於同一UI線程中。

這個簡單的解決方案將調用移至UI線程中的textbox1.Text = someText

private void SetText(string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (this.textBox1.InvokeRequired)
    {   
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { text });
    }
    else
    {
        this.textBox1.Text = text;
    }
}

另外,您可以使用textBox1.BeginInvoke而不是Invoke :它將在UI線程中運行,而不會鎖定調用者線程,等待SetText委托完成

[編輯]在您的backgroundWorker中進行:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    object[] arg = (object[])e.Argument;
    SetTextToTextBox(recTpcTxt, (string)arg[0]);
    SetTextToTextBox(recMsgTxt, (string)arg[1]);
}

private void SetTextToTextBox(TextBox toSet, string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (toSet.InvokeRequired)
    {   
        SetTextCallback d = new SetTextCallback(SetText);
        toSet.Invoke(d, new object[] { text });
    }
    else
    {
        toSet.Text = text;
    }
}

[編輯2]正確使用backgroundworker

注冊事件DoWorkRunWorkerCompleted

this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);

退出backgroundWorker1_DoWork之前,請設置eventArgs的result屬性,並在backgroundWorker1_RunWorkerCompleted讀取它們

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    System.Threading.Thread.Sleep(5000);
    e.Result = new string[] { "one", "two" };
}
private void backgroundWorker1_RunWorkerCompleted(
    object sender,
    RunWorkerCompletedEventArgs e)
{
    string[] res = (string[])e.Result;
    this.textBox1.Text = res[0];
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM