从不同类中的不同线程更新UI
本文关键字:线程 更新 UI 同类 | 更新日期: 2023-09-27 18:21:20
我有一个主表单类,其中包含一个我想要更改的列表框。该框中填充了以耗时的方法创建的项目。现在看起来是这样的(手工发明一个例子,可能不是有效的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
ing。这样,你的调用者就不需要知道他们在哪个线程上运行。
更新为了解决您对如何获得Form
引用的评论,通常在Windows窗体应用程序中,您的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);
}
}
在UI中(假设C#4):
Task.Factory.StartNew(() =>
{
foreach (string s in StaticClassHelper.GetStrings(inputString))
{
string toAdd = s;
listBox1.Invoke(new Action(() => listBox1.Add(toAdd)));
}
}
也许是更干净的方法,但这应该能让你找到你想要的。