简体   繁体   中英

Winforms listbox not updating when bound data changes

The image below shows how my code works. When I press button2 the listbox is updated, but not when I press button1. Why?

伪代码

Is the problem threading related? If it is, where should I add the call to (Begin)Invoke?

One interesting thing to note is that if I first press button1 and then button2 the data generated by the button1 click is shown when I click button2. So it seems like the data generated by doFoo is buffered somewhere, and then pushed to the listbox once I press button2.

EDIT:

I tried adding AddNumber to the form code, and added a call to Invoke when listBox1.InvokeRequired returns true. This solves the problem, but isn't the nicest of designs. I don't want the GUI to have to "worry" about how to add items to a list that's part of the model.

How can I keep the logic behind adding to the list internal to the list class, while still updating the gui when the list changes?

EDIT 2:

Now that we have confirmed that this is a threading issue I've updated the image to more closely reflect the design of the actual code I'm working on.

While Lucero's suggestion still solves the problem, I was hoping for something that doesn't require the form to know anything about the dll or CDllWrapper.

The model (ListBoxDataBindingSource etc) should know nothing at all about the view (listboxes, buttons, labels etc)

My guess is that this is due to the update message being handled on the wrong thread. Background: each thread has its own message queue. Messages posted into the message queue will land in the same thread as the caller by default. Therefore, the callback will maybe post a message on the wrong thread.

Try this: move the AddNumber() method to the form and use Invoke() (inherited by Control) to add the item in the correct thread. This may get rid of the issue.

Edit to reflect your followup: The UI doesn't have to know about your component. What you need is just a proper synchronization between adding the item to your list and the UI, since UI updates will oly work if the thread matches. Therefore, you might want to supply the Control to your class which wraps the BindingList, and then do the Invoke on the list itself. This makes the list worry about triggering the upate on the UI thread and does take the worry from both the UI and the external component of invoking the handler on the correct thread.

Like this:

internal class ListBoxDataBindingSource {
  private readonly Control uiInvokeControl;
  private readonly BindingList<Item> list = new BindingList<Item>();

    public ListBoxDataBindingSource(Control uiInvokeControl) {
      if (uiInvokeControl == null) {
            throw new ArgumentNullException("uiInvokeControl");
      }
        this.uiInvokeControl = uiInvokeControl;
        CDIIWrapper.setFP(AddNumber);
    }

    public void AddNumber(int num) {
      Item item = new Item(num.ToString());
        if (uiInvokeControl.InvokeRequired) {
            uiInvokeControl.Invoke(list.Add, item);
        } else {
            list.Add(item);
        }
    }

    private BindingList<Item> List {
        get {
            return list;
        }
    }
}

I know this is old, although I had a very similar problem.

Here was the solution: BindingList not updating bound ListBox .

I need to call my view model to add things to the bindinglist, so I need to write an anonymous function

Reference to Lucero's Answer and following post: Anonymous method in Invoke call

My Code:

listBox.Invoke((Action)delegate
{
    MyViewModel.AddItem(param1, param2);
});

Instead of having the setFP set the callback to lbDataBindingSource.AddNumber, create a private method in your code to handle the callback and then call lbDataBindingSource.AddNumber from that callback.

void MyForm_Load(object sender, EventArgs e)
{
    //...

    cdll.setFP(FPCallback);
}

private void FPCallback(int num)
{
    lbDataBindingSoruce.AddNumber(num);
}

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