绑定到IList,但获取“Complex DataBinding接受IList或IListSource作为数据源”

时间:2017-11-07 21:02:14

标签: c# .net winforms data-binding bindingsource

如果您在没有调试的情况下运行以下代码(或启用“仅启用我的代码”),它似乎可以正常工作。但是,如果您使用调试器启动它并关闭“启用我的代码”,您将获得此异常(然后被库代码吞噬):

System.ArgumentException occurred
  HResult=-2147024809
  Message=Complex DataBinding accepts as a data source either an IList or an IListSource.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.ListControl.set_DataSource(Object value)
  InnerException: 

这是我的代码的最小版本:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;

static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm(new MainModel()));
    }
}

public class MainModel {
    public IList Options { get; } = new List<string> { "Foo", "Bar" };
}

class MainForm : Form {
    private System.ComponentModel.IContainer components;
    private ComboBox comboBox;
    private BindingSource bindingSource;
    private ErrorProvider errorProvider;

    public MainForm(MainModel mainModel) {
        InitializeComponent();
        bindingSource.DataSource = mainModel;
    }

    private void InitializeComponent() {
        components = new System.ComponentModel.Container();
        bindingSource = new BindingSource(components);
        errorProvider = new ErrorProvider(components);
        ((System.ComponentModel.ISupportInitialize) bindingSource).BeginInit();
        ((System.ComponentModel.ISupportInitialize) errorProvider).BeginInit();
        SuspendLayout();

        bindingSource.DataSource = typeof(MainModel);

        comboBox = new ComboBox();
        comboBox.DataBindings.Add(new Binding("DataSource", bindingSource, "Options", true));
        comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
        Controls.Add(comboBox);

        errorProvider.ContainerControl = this;
        errorProvider.DataSource = bindingSource;

        ((System.ComponentModel.ISupportInitialize) bindingSource).EndInit();
        ((System.ComponentModel.ISupportInitialize) errorProvider).EndInit();
        ResumeLayout(false);
    }

}

问题似乎与数据绑定有关。如果我注释掉comboBox.DataBindings.Add(new Binding("DataSource", bindingSource, "Options", true));行,则不会发生异常。

我在网上发现了许多对此异常的引用,但似乎在所有这些情况下,问题是数据源不是IList(如异常消息所述)。但是,在这种情况下,Options IList。所以我无法解释这个例外。

我注意到,如果删除ErrorProvider,则会发生异常。但我无法弄清楚为什么会这样;我需要在我的实际程序中使用错误提供程序。

我在Visual Studio 2015中工作,面向.NET 4.6。

2 个答案:

答案 0 :(得分:3)

当您的bindingSource仍然在BeginInit - EndInit块中时,看起来您正在声明您的DataBinding。尝试在 EndInit行之后将该行移动到,或者在OnLoad覆盖中移动:

protected override void OnLoad(EventArgs e) {
  base.OnLoad(e);
  comboBox.DataBindings.Add(new Binding("DataSource", bindingSource, "Options", true));
}

答案 1 :(得分:1)

Binding属性添加DataSource是错误的想法。

要设置DataSource,您应该为DataSource分配内容,而不是添加Binding。例如,添加BindingSelectedValue有意义,但对DataSource则无效。

您的代码应为:

bindingSource.DataSource = typeof(MainModel);
bindingSource.DataMember = "Options";

comboBox = new ComboBox();
comboBox.DataSource = bindingSource;
comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
Controls.Add(comboBox);

然后你不会收到任何错误。

注意:如果出于任何原因您只是对如何避免示例中的错误感到好奇,请设置this.Visible = true或在{{1}之后完全调用this.Show()强制创建控制句柄并使数据绑定开始工作。我的代码不需要此修复程序。

为什么数据绑定到InitializeComponent属性不是一个好主意?

如果要将DataSource属性绑定到DataSource的{​​{1}}属性,则意味着您将使用组合框更新Optins属性!这也意味着MainModel类应该实现Options来通知组合框MainModel属性的变化!(请记住,options属性是INotifyPropertyChanged)&#39 ;完全错误的想法!

那么如何通知Options数据源的变化?

如果您想通知IList有关数据源的更改,则数据源列表应实现ComboBoxComboBox是实施的一个例子。因此,设置IBindingList而非数据绑定到BindingList<T>就足够了。