这不是我第一次遇到代表,而且我和上次以及之前的时间一样困惑。所以我一劳永逸地想要解决delgate混淆问题。
我的问题如下:
拥有一个只显示带有一些boud项目的ListView的图形用户界面,我想从数据连接加载数据,这需要一些时间,以增加使用我已实现BackgroundWorker和doWork的应用程序的舒适度-method我想获取数据并显示它。
这就是我想要的方式
现在这是Cross-Thread-Invoking,我想通过Delegates来解决这个问题。在this tutorial之后,我找到了一个工作代表,但是它没有解决问题,在我的委托中我无法更改我的ListView,它仍然说它在另一个线程上。
我想找到一个关于代表的Easy explenation以及如何使用它们来解决我的问题。另外,我应该考虑或设计不同的软件吗?
答案 0 :(得分:6)
通常BackgroundWorker
使用ReportProgress
与UI线程进行通信。您可以在启动后台工作程序之前连接一个委托以接收这些进度事件,然后在UI线程上报告进度,您可以安全地更改ListView
。
Windows窗体中的另一个替代方法是调用Control.Invoke
或Control.BeginInvoke
,传入将更新UI的委托。该委托将在UI线程上执行。有关此示例,请参阅my threading tutorial或Joe Albahari's。
WPF中的相应内容是Dispatcher
- 再次,Invoke
和BeginInvoke
。您可以访问具有Dispatcher
属性的控件的调度程序。
答案 1 :(得分:2)
您不能直接从其他线程更改ui控件,在进行更改之前需要检查Control.InvokeRequired
属性。
请参阅msdn上的this example
答案 2 :(得分:0)
查看此代码,它可以满足您的需求:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnFill_Click(object sender, EventArgs e)
{
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerAsync();
}
private delegate void AddItemToListViewDelegate(ListView view, ListViewItem item);
private void AddItemToListView(ListView view, ListViewItem item)
{
if (InvokeRequired)
{
Invoke(new AddItemToListViewDelegate(AddItemToListView), new object[] { view, item });
return;
}
view.Items.Add(item);
}
private delegate void ClearListViewItemsDelegate(ListView view);
private void ClearListView(ListView view)
{
if (InvokeRequired)
{
Invoke(new ClearListViewItemsDelegate(ClearListView), new object[] { view });
return;
}
view.Items.Clear();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
if (i == 0)
ClearListView(listView1);
var item = new ListViewItem();
item.Name = i.ToString();
item.Text = item.Name;
AddItemToListView(listView1, item);
}
}
}
对于WPF,需要类似的东西。请注意,这不是有效的代码。由于我不使用WPF,我不能保证这是可靠的代码,但它应该给你一个想法。您可能需要创建一个派生自EventArgs的类型来封装listview和listviewitems。
如果我有时间,我会编辑这篇文章,以便它可以正常工作,但这必须等到今晚!
using System.Windows.Threading;
...
if (listView1.Dispatcher.Thread != Thread.CurrentThread)
{
listView1.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new EventHandler<ListViewAddEventArgs>(AddItemToListView), sender, new object[] { e } );
return;
}
listView1.Items.Add(e.File);