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

Posted

技术标签:

【中文标题】绑定数据更改时Winforms列表框不更新【英文标题】:Winforms listbox not updating when bound data changes 【发布时间】:2010-10-20 14:00:48 【问题描述】:

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

问题与线程有关吗?如果是,我应该在哪里添加对 (Begin)Invoke 的调用?

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

编辑:

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

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

编辑 2:

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

虽然 Lucero 的建议仍然可以解决问题,但我希望得到一些不需要表单来了解有关 dll 或 CDllWrapper 的任何内容。

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

【问题讨论】:

【参考方案1】:

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

这是解决方案:BindingList not updating bound ListBox。

【讨论】:

谢谢。我很久以前就把这个项目搁置了,但是当我再次拿起它时,我会看看这是否有帮助:)【参考方案2】:

我需要调用我的视图模型向绑定列表添加东西,所以我需要编写一个匿名函数

参考 Lucero 的回答和以下帖子: Anonymous method in Invoke call

我的代码:

listBox.Invoke((Action)delegate

    MyViewModel.AddItem(param1, param2);
);

【讨论】:

【参考方案3】:

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

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

编辑以反映您的后续行动: UI 不必知道您的组件。您需要的只是将项目添加到列表和 UI 之间的适当同步,因为 UI 更新仅在线程匹配时才起作用。因此,您可能希望将 Control 提供给包装 BindingList 的类,然后对列表本身执行 Invoke。这使得列表担心触发 UI 线程上的更新,并且确实消除了 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;
        
    

【讨论】:

我明白问题出在哪里,现在我们只需要想出一个好的解决方案 :) 我正在尝试根据 MVC 模式进行设计,所以让 ListBoxDataBindingSource(模型的一部分)了解控件(视图的一部分)通常被视为不好的做法。 好吧,它并不真正了解控件,而只需要知道 hot 即可将 add 调用编组到正确的线程。您可以创建自己的编组类,该类知道控件并将其传递给列表,以便正确隐藏此方面。 @Tobbe: 也许this answer 我之前的问题之一——Winforms data-binding to business objects in a multi-threaded scenario without InvokeRequired?——在这里适用。)【参考方案4】:

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

void MyForm_Load(object sender, EventArgs e)

    //...

    cdll.setFP(FPCallback);


private void FPCallback(int num)

    lbDataBindingSoruce.AddNumber(num);

【讨论】:

以上是关于绑定数据更改时Winforms列表框不更新的主要内容,如果未能解决你的问题,请参考以下文章

DataGrid 数据绑定/更新中的 WPF 组合框不起作用

当 DataSource 值更改时,WinForms ComboBox 中的项目不会更新

如何在更新数据源时让绑定的 winforms 控件刷新?

将列表绑定到数据源

更改集合时 WPF 组合框不更新

将对象列表数据绑定到 WinForms DataGridView,但不显示某些公共属性