绑定数据更改时Winforms列表框不更新

时间:2009-04-20 14:07:24

标签: c# winforms multithreading data-binding listbox

下图显示了我的代码的工作原理。当我按下按钮2时,列表框会更新,但不会在我按下按钮1时更新。为什么呢?

pseudo code

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

需要注意的一件有趣的事情是,如果我先按button1然后再按button2,当我点击button2时会显示button1点击生成的数据。所以似乎doFoo生成的数据在某处缓冲,然后在按下button2后推送到列表框。

修改

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

如何在添加到列表类内部列表的同时保留逻辑,同时在列表更改时仍然更新gui?

编辑2:

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

虽然Lucero的建议仍然解决了这个问题,但我希望能找到一些不需要表格来了解dll或CDllWrapper的内容。

模型(ListBoxDataBindingSource等)应该对视图(列表框,按钮,标签等)一无所知

4 个答案:

答案 0 :(得分:2)

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

试试这个:将AddNumber()方法移动到表单并使用Invoke()(由Control继承)在正确的线程中添加项目。这可能会解决这个问题。

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

像这样:

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

答案 1 :(得分:1)

我知道这是旧的,虽然我有一个非常类似的问题。

以下是解决方案:BindingList not updating bound ListBox

答案 2 :(得分:0)

不要让setFP将回调设置为lbDataBindingSource.AddNumber,而是在代码中创建一个私有方法来处理回调,然后从该回调中调用lbDataBindingSource.AddNumber。

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

    cdll.setFP(FPCallback);
}

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

答案 3 :(得分:0)

我需要调用我的视图模型将内容添加到bindinglist中,所以我需要编写一个匿名函数

参考Lucero的答案和帖子: Anonymous method in Invoke call

我的代码:

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