从类更新UI(多线程)
本文关键字:多线程 UI 更新 | 更新日期: 2023-09-27 17:53:30
可能重复:
如何从C#中的另一个线程更新GUI?
如何从线程类更新UI?无法从线程访问更新表单控件。我想根据每个特定线程的进度更新我的UI。
class MyClass
{
public delegate void CountChangedEventHandler(int vCount, int vIndex);
public event CountChangedEventHandler CountChanged;
private int count;
private int index;
public MyClass(int index)
{
this.index = index;
}
public int Count
{
get { return this.count; }
set
{
this.count = value;
if (this.CountChanged != null)
this.CountChanged(value, this.index);
}
}
public void DoWork(object o)
{
for (int i = 0; i < 10000; i++)
{
this.Count = i;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 3; i++)
{
MyClass myCount = new MyClass(i);
myCount.CountChanged += new MyClass.CountChangedEventHandler(UpdateUI);
ListViewItem lvi = new ListViewItem();
lvi.Text = "Thread #" + i.ToString();
lvi.SubItems.Add("");
listView1.Items.Add(lvi);
ThreadPool.QueueUserWorkItem(new WaitCallback(myCount.DoWork));
}
}
private void UpdateUI (int index, int count)
{
listView1.Items[index].SubItems[0].Text = count.ToString();
}
}
您需要使用Invoke
或BeginInvoke
将UI访问封送回UI线程。
我建议在这种情况下使用Invoke
,因为这会阻止你的循环过于超前:
private void UpdateUI (int index, int count)
{
Invoke( ( MethodInvoker ) (
() => listView1.Items[index].SubItems[0].Text = count.ToString()
) );
}
有多种方法可以实现这一点。这里有几个选项:
1( BackgroundWorker-你可以在网上找到很多关于如何使用它的例子,只要你在这个过程中只需要将进度(整数(传递回UI,这是可以接受的。
2( 带有计时器的消息队列-为您提供了将进度返回到UI的选项。
下面是我编写的WPF应用程序中选项2的一个示例,它将字符串传递回UI,当然,您可以用任何想要的自定义对象替换字符串。此外,需要.NET 3.0或更高版本:
private static List<string> MessageQueue = new List<string>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DispatcherTimer messageQueueTimer = new DispatcherTimer();
messageQueueTimer.Tick += messageQueueTimer_Elapsed;
messageQueueTimer.Interval = new TimeSpan(1); //1 tick
messageQueueTimer.Start();
}
protected void messageQueueTimer_Elapsed(object sender, EventArgs e)
{
lock(MessageQueue)
{
//Read message from queue and remove it.
}
}
//WriteLine can be called from any asyncronous method spawed from the UI.
public void WriteLine(string message)
{
lock(MessageQueue)
{
//Insert message into the queue.
}
}
还有其他几种方法可以实现这一点,但这应该让你开始。希望这能有所帮助!