了解代表

时间:2009-09-22 09:33:15

标签: c#

这不是我第一次遇到代表,而且我和上次以及之前的时间一样困惑。所以我一劳永逸地想要解决delgate混淆问题。

我的问题如下:

拥有一个只显示带有一些boud项目的ListView的图形用户界面,我想从数据连接加载数据,这需要一些时间,以增加使用我已实现BackgroundWorker和doWork的应用程序的舒适度-method我想获取数据并显示它。

这就是我想要的方式

  • 创建BackgroundWorker并为doWork事件指定doWork_fetchData()方法
  • 调用我的Worker实例的Async方法
  • 更新ListView,而不会在下载数据期间“冻结”用户界面。

现在这是Cross-Thread-Invoking,我想通过Delegates来解决这个问题。在this tutorial之后,我找到了一个工作代表,但是它没有解决问题,在我的委托中我无法更改我的ListView,它仍然说它在另一个线程上。

我想找到一个关于代表的Easy explenation以及如何使用它们来解决我的问题。另外,我应该考虑或设计不同的软件吗?

3 个答案:

答案 0 :(得分:6)

通常BackgroundWorker使用ReportProgress与UI线程进行通信。您可以在启动后台工作程序之前连接一个委托以接收这些进度事件,然后在UI线程上报告进度,您可以安全地更改ListView

Windows窗体中的另一个替代方法是调用Control.InvokeControl.BeginInvoke,传入将更新UI的委托。该委托将在UI线程上执行。有关此示例,请参阅my threading tutorialJoe Albahari's

WPF中的相应内容是Dispatcher - 再次,InvokeBeginInvoke。您可以访问具有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);