[英]Update UI from a different thread in a different class
我有包含要更改的列表框的主窗體類。 該框將填充以費時的方法創建的項目。 現在看起來像這樣(手動創建示例,可能不是有效的C#):
List<string> strings = StaticClassHelper.GetStrings(inputString);
foreach(string s in strings)
{
listBox1.Add(s);
}
//meanwhile, in a different class, in a different file...
public static List<string> GetStrings(inputString)
{
List<string> result = new List<string>();
foreach(string s in inputString.Split('c'))
{
result.Add(s.Reverse());
Thread.Sleep(1000);
}
return result;
}
我想做的是在找到新字符串時定期更新列表框。 當線程方法位於同一類中時,我發現其他答案可行,因此您可以設置事件處理程序。 我在這里做什么?
這是我喜歡的方式,我在這樣的表單上創建一個方法:
public void AddItemToList(string Item)
{
if(InvokeRequired)
Invoke(new Action<string>(AddItemToList), Item);
else
listBox1.Add(Item);
}
在這種情況下,我更喜歡調用以確保同步添加項目,否則它們可能會混亂。 如果您不關心訂單,則可以使用BeginInvoke
,它將更快一點。 由於此方法是公共的,因此只要您可以獲取對表單的引用,就可以從應用程序中的任何類進行所有操作。
這樣做的另一個優點是,可以從UI線程或非UI線程調用它,並且它會確定是否需要Invoke
。 這樣,您的調用方就不必知道他們在哪個線程上運行。
更新為了解決您對如何獲得對Form
的引用的評論,通常在Windows Forms應用程序中,您的Program.cs文件如下所示:
static class Program
{
static void Main()
{
MyForm form = new MyForm();
Application.Run(form);
}
}
這通常是我要做的,特別是在“單一表單”應用程序的情況下:
static class Program
{
public static MyForm MainWindow;
static void Main()
{
mainWindow = new MyForm();
Application.Run(form);
}
}
然后,您可以使用以下任何地方在幾乎任何地方訪問它:
Program.MainWindow.AddToList(...);
包含ListBox的類需要公開一種添加字符串的方法-由於此方法可能在其他線程上調用,因此需要使用
listBox1.Invoke( ...)
創建線程安全的調用機制
您是否可以將GetStrings重寫為迭代器? 然后,在您的UI中,您可以啟動一個后台線程,該線程在GetStrings的結果上進行迭代,每次都更新列表框。 就像是:
public static System.Collections.IEnumerable GetStrings(inputString)
{
foreach(string s in inputString.Split('c'))
{
yield return s.Reverse();
Thread.Sleep(1000);
}
}
在用戶界面中(假設使用C#4):
Task.Factory.StartNew(() =>
{
foreach (string s in StaticClassHelper.GetStrings(inputString))
{
string toAdd = s;
listBox1.Invoke(new Action(() => listBox1.Add(toAdd)));
}
}
可能更清潔的解決方法,但這應該可以為您提供所需的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.