简体   繁体   中英

Understanding Delegates

It's not the first time I come across delegates and I am as confused as I were the last time and the time before that. So once and for all I want to get the delgate-confusion cleared up.

My problem is as followed

Having a Graphical User Interface which only displays a ListView with some boud items, I want to load the data from a Data Connection which takes some time, to increase the comfort of using the application I have instancieted a BackgroundWorker and in the doWork-method I want to fetch the data and display it.

This is how I want it

  • Create BackgroundWorker and appoint doWork_fetchData() method to the doWork event
  • Call the Async method of my Worker instance
  • Have the ListView updated without the User Interface beeing "frozen" during download of data.

Now this is Cross-Thread-Invoking and I wanted to solve this with Delegates which brings me here. Following this tutorial , I got a working Delegate, However it did not solve the problem, inside my delegate I cannot change my ListView, it still says it is on another thread.

I want to find an Easy explenation on delegates and how to use them to solve my problem. Also, should I think or design my software different?

Normally BackgroundWorker communicates with the UI thread using ReportProgress . You would hook up a delegate to receive those progress events before launching the background worker, and then the progress would be reported on the UI thread, where you're safe to change your ListView .

The other alternative in Windows Forms is to call Control.Invoke or Control.BeginInvoke , passing in a delegate which will update the UI. That delegate will be executed on the UI thread. For an example of this, see my threading tutorial or Joe Albahari's .

The equivalent of this in WPF is the Dispatcher - again, Invoke and BeginInvoke . You can access the dispatcher for a control with the Dispatcher property.

You can't change a ui control from a different thread directly, you need to check the Control.InvokeRequired property before you make a change.

See this example on msdn

Checkout this code, it does what you need:

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

And for WPF something similar is required. Note this is not working code. As I don't use WPF I can't vouch that this is solid code, but it should give you an idea. You may need to create an type derived from EventArgs to encapsulate your listview and listviewitems.

If I get time, I'll edit this post so that it works, but that will have to wait until this evening!

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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