none
請問如何不用invoke,只需要註冊事件後,就可以跨執行緒修改TextBox值? RRS feed

  • 問題

  • 各位前輩好,

    最近在寫Socket時,遇到了一些問題,

    希望前輩們可以指導我一下。

    我主要的問題是:

    如何不用在Form中使用invoke,在form的TextBox可以出現"Client Connected"?


    方法1是可行的,也是我看了許多文章找到的,

    但是請問有沒有辦法讓方法2的概念可行?

    就像BackGroundWorker一樣,我只需要註冊事件後,就可以直接用方法2。

    先謝謝有回答的各位前輩。

    自訂class

        public class Server
        {
            public TcpListener ServerSocket { get; private set; }
            public Thread ServerListenThread { get; private set; }
            public List<ClientConnection> ClientList { get; private set; }
    
            public Server(IPAddress inAddress, int inPort)
            {
                this.ServerSocket = new TcpListener(inAddress, inPort);
                this.ClientList = new List<ClientConnection>(0);
            }
    
            public void StartConnection()
            {
                this.ServerSocket.Start();
                this.ServerSocket.BeginAcceptTcpClient(new AsyncCallback(this.AcceptedTcpClientCallback), null);
            }
    
            public void AcceptedTcpClientCallback(IAsyncResult inResult)
            {
                TcpClient client = this.ServerSocket.EndAcceptTcpClient(inResult);
    
                ClientConnection connection = new ClientConnection();
                this.ClientList.Add(connection);
    
                if (ClientConnected != null)
                {
                    this.ClientConnected(null, null);
    
                }
            }
        }
    

    form

            Server server;
    
            private void btnStartConnection_Click(object sender, EventArgs e)
            {
                server = new Server(IPAddress.Parse(this.txtbxAddress.Text), 
                server.ClientConnected += new EventHandler(server_ClientConnected);
    
    
                server.StartConnection();
            }
    
            void server_ClientConnected(object sender, EventArgs e)
            {
                //方法1
                this.Invoke(new MethodInvoker(delegate()
                    {
                        this.txtbxMessage.AppendText("Client Connected");
                    }
                ));
    
                ////方法2
                //this.txtbxMessage.AppendText("Client Connected");
            }

    2015年1月13日 上午 10:11

解答

所有回覆

  • 跨執行緒的 UI 存取,只能使用 Invoke 或 BeginInvoke,否則你就會收到跨執行緒違規的錯誤。

    BackgroundWorker 也是在背後做掉這些事。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2015年1月14日 上午 04:37
    版主
  • 感謝小朱前輩的回答,

    我會問這個問題,是因為這篇文章原因 C# \ VB .NET Multi-user Communication Library (TCP)

    我只需要註冊之後,接下來事件啟動就可以修改TextBox的值,

    看的時候就覺得很奇怪,明明是跨執行緒,應該會出現錯誤才對,但是該程式沒有…!

    後來研究一下,發現裡面有使用到SynchronizationContext,

    但是對於SynchronizationContext我不太了解,看了MSDN後也有點霧裡看花的感覺。

    ===

    另外可能我打意思讓人有點誤會,

    我是希望不要在Form那邊寫Invoke或BeginInvoke,

    如果要寫也是希望在自訂class裡面寫,希望保持在Form裡面只要註冊自訂class事件接下來就可以了。

    但我也不太知道該怎麼修改自訂class,看了上面的文章,

    也覺得SynchronizationContext看不太懂。

    謝謝小朱前輩的回答



    • 已編輯 笨嘎嘎 2015年1月14日 上午 05:59
    2015年1月14日 上午 05:49
  • 你可以在 Form 加入私有方法,這個方法 Invoke 修改文字盒。

    則任一個work thread 呼叫這個方法即可。


    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    2015年1月14日 下午 03:03
  • 可以用 SynchronizationContext 類別 來替代

    參考以下文章

    http://www.dotblogs.com.tw/clark/archive/2013/05/04/102772.aspx


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。


    2015年1月17日 下午 06:38
    版主
  • 有一個偷懶的做法, 那就是使用Ctrl+F5組合鍵以不偵錯的方式執行您的專案, 就不會檢查是否有跨執行緒的動作了
    2015年1月18日 上午 08:31
  • 感謝心冷熱情熄、Bill、this三位前輩的回答。

    ===

    回復心冷大熱情熄前輩,

    因為我是最後做出一個類似控制項的東西,所以可能的話,希望就像

    backgroundWork一樣,宣告後,將事件註冊後就可以用,

    而不需要再method裡面再呼叫invoke的方法。

    ====

    回復this前輩,

    這樣的做法感覺治標不治本,不過學到Ctrl+F5=不偵錯,謝謝你。

    ===

    回復Bill前輩,

    感謝你提供的網址,學到了不少,

    後來又去找 SynchronizationContext 相關資料後,發現是的確我要的,

    這樣子就可以將事件註冊後,不用再另外打invoke(方法1),直接修改(方法2)就可以了。

    謝謝你。

    2015年1月19日 上午 01:11
  • 在 windows 中,只有 gdi thread 可以更新螢幕,從這角度來看,重點不是做成 backgroundworker ,而是避免 gdi thread 不要工作過量。

    不然你呼叫啥都沒用,因為 gdi thread 根本沒空理你。

    而 backgroundworker 因為沒強調這觀念,反而常常被人誤用,讓 gdi thread 全載在跑,讓 backgroundworker 去背景排隊,排到天荒地老永遠輪不到,甚至 buffer 滿了被擠掉,那還不如直接強制更新。


    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    2015年1月19日 下午 01:52