【问题标题】:Binding to IList, but getting "Complex DataBinding accepts as a data source either an IList or an IListSource"绑定到 IList,但获取“复杂 DataBinding 接受 IList 或 IListSource 作为数据源”
【发布时间】:2018-04-20 09:54:31
【问题描述】:

如果您在未调试的情况下运行以下代码(或启用“仅启用我的代码”),它似乎可以工作。但是如果你用调试器启动它并关闭“启用我的代码”,你会得到这个异常(然后被库代码吞没):

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。

【问题讨论】:

  • 数据绑定到DataSource?!

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


【解决方案1】:

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

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

【讨论】:

  • @DanielWolf 这是一个很好的观察。我相应地更新了答案。
【解决方案2】:

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

要设置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 或在InitializeComponent 之后调用this.Show() 以强制创建控制句柄并使数据绑定开始工作。我的代码不需要此修复程序。

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

如果您要将DataSource 属性绑定到MainModelOptins 属性,这意味着您将使用组合框更新Options 属性!这也意味着MainModel 类应该实现INotifyPropertyChanged 来通知组合框Options 属性的变化!(记住options 属性是IList)这是完全错误的想法!

那么我如何通知ComboBox 数据源的变化呢?

如果你想通知ComboBox关于数据源的变化,数据源列表应该实现IBindingListBindingList&lt;T&gt; 是实现的一个示例。所以设置comboBox.DataSource = someDataSource;而不是数据绑定到DataSource就足够了。

【讨论】:

  • 不同意绑定到DataSource。绑定也可用于 DataSource - 特别是 ComboBox,如果您希望根据视图模型中的某些条件更改项目。
  • @Fabio 数据源支持IBindingList 就足够了,然后组合框将收到数据源更改的通知。这是复杂数据绑定的工作方式,您提供数据源并为其他一些属性使用数据绑定。
  • @Fabio 如果您要将DataSource 属性绑定到MainModelOptins 属性,这意味着您将使用组合框更新Options 属性!这也意味着MainModel 类应该实现INotifyPropertyChanged 来通知组合框Options 属性的变化!(记住options 属性是IList)这是完全错误的想法!你能明白吗?
  • 同意comboBox.DataSource = someDataSource;,您可以轻松完成工作。您不会通过组合框更新集合,而是从组合框中选择项目。如果MainModel 实现INotifyPropertyChanged,您可以将任何集合(不仅是IBindingListObservableCollection)绑定到组合框。我的观点是,我没有看到为什么 DataSource 不能绑定到集合的一些技术障碍。
  • @Fabio 它有点基于意见,而且范围太广,无法在 cmets 中得出结论。无论如何,这是一次很好的技术讨论:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
相关资源
最近更新 更多