繁体   English   中英

了解代表

[英]Understanding Delegates

这不是我第一次遇到代表,而且我和上次以及之前的时间一样困惑。 因此,我一劳永逸地想要彻底清除delgate混乱。

我的问题如下

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

这就是我想要的

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

现在这是Cross-Thread-Invoking,我想通过Delegates来解决这个问题。 本教程之后 ,我得到了一个有效的委托, 它没有解决问题,在我的委托中我无法更改我的ListView,它仍然说它在另一个线程上。

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

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

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

在WPF中相当于Dispatcher - 再次, InvokeBeginInvoke 您可以使用Dispatcher属性访问控件的Dispatcher

您无法直接从其他线程更改ui控件,需要在进行更改之前检查Control.InvokeRequired属性。

在msdn上查看此示例

查看此代码,它可以满足您的需求:

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM