C# WinForms ComboBox 数据绑定问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-07-31 10:32:15  来源:igfitidea点击:

WinForms ComboBox data binding gotcha

提问by Darren Kopp

Assume you are doing something like the following

假设您正在执行以下操作

List<string> myitems = new List<string>
{
    "Item 1",
    "Item 2",
    "Item 3"
};

ComboBox box = new ComboBox();
box.DataSource = myitems;

ComboBox box2 = new ComboBox();
box2.DataSource = myitems

So now we have 2 combo boxes bound to that array, and everything works fine. But when you change the value of one combo box, it changes BOTH combo boxes to the one you just selected.

所以现在我们有 2 个组合框绑定到该数组,一切正常。但是当您更改一个组合框的值时,它会将两个组合框更改为您刚刚选择的组合框。

Now, I know that Arrays are always passed by reference (learned that when i learned C :D), but why on earth would the combo boxes change together? I don't believe the combo box control is modifying the collection at all.

现在,我知道数组总是通过引用传递(在我学习 C :D 时了解到这一点),但是为什么组合框会一起改变?我不相信组合框控件正在修改集合。

As a workaround, don't this would achieve the functionality that is expected/desired

作为一种解决方法,这不会实现预期/所需的功能

ComboBox box = new ComboBox();
box.DataSource = myitems.ToArray();

采纳答案by Robert H?glund

This has to do with how data bindings are set up in the dotnet framework, especially the BindingContext. On a high level it means that if you haven't specified otherwise each form and all the controls of the form share the same BindingContext. When you are setting the DataSourceproperty the ComboBoxwill use the BindingContextto get a ConcurrenyMangagerthat wraps the list. The ConcurrenyManagerkeeps track of such things as the current selected position in the list.

这与 dotnet 框架中数据绑定的设置方式有关,尤其是BindingContext. 在高层次上,这意味着如果您没有另外指定每个表单和表单的所有控件共享相同的BindingContext. 当您设置DataSource属性时,ComboBox将使用BindingContext来获取ConcurrenyMangager包装列表的 。在ConcurrenyManager跟踪这样的事情在列表中的当前选择的位置。

When you set the DataSourceof the second ComboBoxit will use the same BindingContext(the forms) which will yield a reference to the same ConcurrencyManageras above used to set up the data bindings.

当您设置DataSource第二个时ComboBox,它将使用相同的BindingContext(表单),这将产生对与ConcurrencyManager上面用于设置数据绑定的相同的引用。

To get a more detailed explanation see BindingContext.

要获得更详细的解释,请参阅BindingContext

回答by Quibblesome

A better workaround (depending on the size of the datasource) is to declare two BindingSourceobjects (new as of 2.00) bind the collection to those and then bind those to the comboboxes.

更好的解决方法(取决于数据源的大小)是声明两个BindingSource对象(从 2.00 开始的新对象)将集合绑定到这些对象,然后将它们绑定到组合框。

I enclose a complete example.

我附上一个完整的例子。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        private BindingSource source1 = new BindingSource();
        private BindingSource source2 = new BindingSource();

        public Form1()
        {
            InitializeComponent();
            Load += new EventHandler(Form1Load);
        }

        void Form1Load(object sender, EventArgs e)
        {
            List<string> myitems = new List<string>
            {
                "Item 1",
                "Item 2",
                "Item 3"
            };

            ComboBox box = new ComboBox();
            box.Bounds = new Rectangle(10, 10, 100, 50);
            source1.DataSource = myitems;
            box.DataSource = source1;

            ComboBox box2 = new ComboBox();
            box2.Bounds = new Rectangle(10, 80, 100, 50);
            source2.DataSource = myitems;
            box2.DataSource = source2;

            Controls.Add(box);
            Controls.Add(box2);
        }
    }
}

If you want to confuse yourself even more then try always declaring bindings in the constructor. That can result in some reallycurious bugs, hence I always bind in the Load event.

如果您想让自己更加困惑,请尝试始终在构造函数中声明绑定。这可能会导致一些非常奇怪的错误,因此我总是在 Load 事件中绑定。