绑定数据更改时,Winforms列表框不会更新 [英] Winforms listbox not updating when bound data changes

查看:140
本文介绍了绑定数据更改时,Winforms列表框不会更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的图片显示了我的代码如何工作。当我按button2时,列表框被更新,但是当我按下按钮1时不会。为什么?



伪代码http:// i44 .tinypic.com / mj69oj.gif



问题线程是否相关?如果是,我应该在哪里添加调用(Begin)Invoke?



一个有趣的事情要注意的是,如果我首先按button1,然后按钮2,当我点击button2时,button1点击显示。所以看起来好像doFoo生成的数据被缓存在某处,然后按下按钮2就推到列表框中。



编辑: p>

我尝试向表单代码添加AddNumber,当listBox1.InvokeRequired返回true时,调用Invoke。这解决了这个问题,但并不是最好的设计。我不希望GUI不必担心如何将项目添加到模型列表中。



我如何保持添加的逻辑列表类的内部列表,同时更新列表更改时的gui?



编辑2:



现在我们已经确认这是一个线程问题,我已经更新了图像,以更加反映我正在进行的实际代码的设计。



虽然Lucero的建议仍然解决了这个问题,但我希望有一些不需要表单知道dll或CDllWrapper的内容。



模型(ListBoxDataBindingSource等)根本就不应该看到视图(列表框,按钮,标签等)

解决方案

我的猜测这是因为在错误的线程处理更新消息。背景:每个线程都有自己的消息队列。默认情况下,发送到消息队列中的消息将与呼叫者在同一线程中。因此,回调可能会在错误的线程上发布消息。



尝试:将AddNumber()方法移动到窗体并使用Invoke()(继承于Control )将项目添加到正确的线程中。这可能会摆脱这个问题。



编辑以反映您的跟进:
用户界面不必了解您的零件。您需要的只是将项目添加到列表和UI之间的适当同步,因为如果线程匹配,UI更新将会运行。因此,您可能希望将Control提供给包装BindingList的类,然后在列表本身上执行Invoke。这使得列表担心触发UI线程上的upate,并且确实从UI和外部组件中调用正确的线程处理程序。



像这样:

 内部类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>列表{
get {
return list;
}
}
}


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

pseudo code http://i44.tinypic.com/mj69oj.gif

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

这篇关于绑定数据更改时,Winforms列表框不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆