[英]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.