Search code examples
c#.netwinformsdata-bindingbindingsource

Binding to IList, but getting "Complex DataBinding accepts as a data source either an IList or an IListSource"


If you run the following code without debugging (or with "Enable Just My Code" active), it will seem to work. But if you start it with debugger and with "Enable Just My Code" turned off, you will get this exception (which is then swallowed by library code):

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: 

Here's a minimal version of my code:

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

}

The problem appears to be with the data binding. If I comment out the line comboBox.DataBindings.Add(new Binding("DataSource", bindingSource, "Options", true));, the exception does not occur.

I found many references to this exception online, but it seems that in all those cases, the problem was that the data source was not an IList (as stated by the exception message). In this case, however, Options is an IList. So I'm at a loss to explain the exception.

I noticed that the exception does not occur if I remove the ErrorProvider. But I can't figure out why that is; and I need the error provider in my actual program.

I'm working in Visual Studio 2015, targeting .NET 4.6.


Solution

  • It looks like you are declaring your DataBinding while your bindingSource is still inside a BeginInit - EndInit block. Try moving that line to after the EndInit line, or in the OnLoad override instead:

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