簡體   English   中英

C#多線程多類GUI應用程序,我這樣做對嗎?

[英]C# Multithread multiclass gui app, am I doing this right?

我創建了以下項目,向大家展示我打算如何做事。 但是我的主要項目將更大,並且將有多個班級。 我只是想讓它正常工作,所以我知道我在編碼時正在使用良好的做法。

好的,讓我們開始:),所以我的表單有一個名為“ button1”的按鈕和一個名為“ textBox1”的文本框,並且我有一個名為“ Class1”的類,其中有一個方法為“ testtest()”,我只是將Thread.Sleep在testtest方法中,這樣我就可以發現它在另一個線程上運行。

這是我的表格代碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Test
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    delegate void Class1Deligate();

    private void button1_Click(object sender, EventArgs e)
    {
      Class1 c = new Class1();
      Class1Deligate testMethod = new Class1Deligate(c.testtest);
      testMethod.BeginInvoke(endTestMethod, testMethod);
    }

    void endTestMethod(IAsyncResult ar)
    {

    }
  }
}

這是我的第一課代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Test
{
  class Class1
  {
    public void testtest()
    {
      Thread.Sleep(8888);
      MessageBox.Show("Done");
    }
  }
}

我是否正確創建新線程? 有人可以告訴我在運行時如何從class1中的testtest方法更新textbox1嗎? 我發表了較早的文章,並告訴我使用Dispatcher,但是由於某種原因,看來Dispatcher類對我不可用。

最好的祝福

我不認為您實際上是在開始一個線程。 delegate.BeginInvoke可能使用內部ThreadPool進行投標。 另外,我不認為您應該在沒有適當的EndInvoke調用之后調用BeginInvoke (否則,將不會釋放從BeginInvoke調用返回的對IAsyncResult的引用)。

如果您想要一個新線程,則可以使用Thread類創建一個新線程

Thread t = new Thread(c.testtest);
t.IsBackground = true; // end if main thread ends
t.Start();

請注意,如果您使用上述的Thread類並使用GUI,則需要在GUI線程上附加一個方法來更新它。 您可以使用Control.Invoke調用來實現

public void updateGUI(object state) {
    if (control.InvokeRequired) {
        control.Invoke(new Action<object>(updateGUI), state);
        return;
    }
    // if we are here, we can safely update the GUI
}

首先,如果您願意,可以使用ThreadPool類進行線程化。 我通常用它來觸發新線程,例如,

ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);

該鏈接進一步說明了它們。 對於GUI,您需要檢查當前線程是否與UI線程相同(因為只有UI線程才能更新UI),如果不是,請在UI線程上調用一個函數。 UI線程。 可以這樣做

delegate void ChangeFormUnsafeCallback(string text);
private void ChangeFormUnsafe(string text)
{
  // Do stuff to form/controls
}

private void SomeFunction()
{      
  myForm.Invoke(new ChangeFormUnsafeCallback(ChangeFormUnsafe), "foo");
}

您可以進行檢查以查看是否需要調用,但是通常很簡單地知道該函數是否將在UI線程內使用並適當地調用。 根據一般經驗,除非您的函數是由於表單上發生了某些事情(例如,單擊按鈕)而運行的,否則您將需要使用Invoke函數。

阿里亞

使用您的方法(異步委托),您沒有啟動新線程,而是使用了.net線程池中的線程,該線程將在您完成工作時釋放。 調用委托並在完成后被回調的正確方法如下:

    void button1_Click(object sender, EventArgs e)
    {
        Class1 c = new Class1();
        Action action = c.Test;

        action.BeginInvoke(new AsyncCallback(EndTestMethod), null);
    }
    void EndTestMethod(IAsyncResult token)
    {    
        Action callBack = (Action)((AsyncResult)token).AsyncDelegate;
        callBack.EndInvoke(token);
    }

如果您的方法壽命很短並且需要回調,則異步委托方法很有用。 否則,對於更長的運行過程,您可能需要創建並啟動一個新線程。

 Thread t = new Thread(c.Test);
        t.IsBackground = true;
        t.Start();

但是,通過回調發回調用線程的信號將變得冗長,因為您必須自己編寫此代碼。

關於Dispatcher,這是一個WPF類,用於排隊由WPF應用程序中的UI線程處理的操作(以及其他操作)。 從您的代碼看來,您正在編寫Winforms應用程序,因此此類型不合適。

最后,為了更新文本框,您需要檢查是否正在嘗試在創建控件(UI線程)的同一線程上訪問該控件。 這是通過control.invokerequired和control.invoke完成的。 如下:

       void AddText(string text)
    {
        if (textBox1.InvokeRequired)
        {
            textBox1.Invoke((Action<string>)AddText, text);
        }
        textBox1.Text = text;
    }

根據您要完成的工作,可以采取幾種不同的方法。 如果您要執行單個任務而又不阻塞UI線程,則可以使用BackgroundWorker 這將為您提供一種非常簡單的方式來保持UI活潑,並使UI更新變得容易,而無需調用等。

如果要執行很多任務,則可能應該使用ThreadPool 如果您需要為線程分配優先級,否則它們將花費大量時間進行阻塞,那么您應該創建自己的實例線程。

您當然可以繼續使用ThreadPool來做您自己的事情,但是還有其他一些方法可能會更好地滿足您的特定需求。

暫無
暫無

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

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