数据库组合框失败和更多

介绍 本文将逐步深入 研究一个常用的。net构造(数据绑定)。首先,本文设置一个简单的程序,该程序使用DisplayMember和ValueMember属性将一组对象绑定到一个ComboBox。其次,它说明了这种做法经常会失败。在那之后,我们将看到解决问题的方法,并了解为什么在控件中,在Visual Studio中,在某些地方可能会有错误。 背景 我在很长一段时间以前发现了这个问题,但一直无法确定为什么会出现这个问题,因为这是一个更大的程序的一部分。所以,我决定写一个具体的程序和文章,提供具体的细节。 如何将对象的值直接绑定到组合框。发生什么问题、错误和失败。为什么这些问题经常发生。 使用的代码 在阅读本文时,您将看到代码经过了许多细微的修改,以向您展示在此过程中会发生什么。附加的代码实现了数组,ToString()覆盖了Animal类。读完这篇文章,你就会明白了。 最后的代码是一个基本的Windows窗体项目与一个额外的类,保持非常简单的努力,以创建一个清楚的例子,正在发生: 下面是动物类: 隐藏,收缩,复制Code

class Animal
{
    private string commonName;
    private string species;
    private int speciesId;
    // Creates a class (global) randomizer used
    // to generate a unique id for each species
    static Random rnd = new Random();

    public Animal(string inSpecies, string inCommonName)
    {
        // original code
        this.speciesId = rnd.Next();
        species = inSpecies;
        commonName = inCommonName;
    }

    public int SpeciesId
    {
        get
        {
            return speciesId;
        }
    }
    public string Species
    {
        get
        {
            return species;
        }
    }
    public string CommonName
    {
        get
        {
            return commonName;
        }
    }
}

头足类动物的细节 通过使用Animal类,可以很容易地将动物列表绑定到ComboBox。在有ComboBox的表单代码中,我们将创建一个动物数组,然后将它们绑定到ComboBox。它看起来如下: 隐藏,复制Code

public partial class Form1 : Form
{
    // set up an array to hold some animals
    Animal[] allAnimals = new Animal[10];
    public Form1()
    {
        InitializeComponent();
        // initialize some animals
        InitAnimals();

        
        comboBox1.DisplayMember = "CommonName";
        comboBox1.ValueMember = "SpeciesId";
        comboBox1.DataSource = allAnimals;
    }

    private void InitAnimals()
    {
        //create 3 animals and add them to the array.
        allAnimals[0] = new Animal("Fidelis Caninus", "Dog");
        allAnimals[1] = new Animal("Felinus Catticus", "Cat");
        allAnimals[2] = new Animal("Elephantos Largus", "Elephant");

    }
}

这段代码将生成一个将动物对象绑定到ComboBox的应用程序,如下所示: 第二个图像:显示一个空项目 还请注意,第二幅图像显示的是程序第一次启动时的样子。好的方面是这个组合框有一个空项目。换句话说,用户还没有选择一个选项。这可能看起来还不重要,但当我们试图解决下面的问题时,它会很重要。所以,现在,只要记住它。 现在,让我们添加一个事件处理程序,以便选择其中一项来做一些事情。在Visual Studio中,确保选择了ComboBox,然后切换到窗体的属性对话框中的事件视图,并添加selectedindexchangeevent。你会得到一个方法,看起来像: 隐藏,复制Code

private void comboBox1_SelectedIndexChanged_1(object sender, EventArgs e)
{
    Animal currentAnimal = (Animal)comboBox1.SelectedItem;
    MessageBox.Show(this,currentAnimal.Species);
}

当运行程序并在组合框中选择一个项目时,事件处理程序将触发,获取当前选中的项目,将其强制转换为一个动物对象,并显示该动物的物种名称。它看起来如下所示,取决于您选择的项目: 我们为什么要Cast这个项目? 我们对从ComboBox返回的项进行了强制转换,因为我们告诉它将该项存储在ComboBox的列表中,但ComboBox只是将其存储为一个对象——所有对象的母对象。因为我们从特定的(动物)对象中有特定的属性,所以我们将它转换为它的真实类型。 看起来很好 所以,你可能会注意到它似乎工作得很好。但是你们有些人可能已经注意到了一个问题。问题:有一个数组有一些空元素。我将数组的大小定义为10,但我只newed了三个动物对象。 工作:除非你改变订单 好了,你看到代码真的能工作,那么这有关系吗?现在,我们假设这无关紧要。但是,让我们更改一行代码,并显示它将导致代码中断。 隐藏,复制Code

public Form1()
{
    InitializeComponent();
    
    //My private method to create some animals
    InitAnimals();

    comboBox1.DataSource = allAnimals;
    // set the Animal property which will be used as the DisplayMember
    comboBox1.DisplayMember = "CommonName";
    // set the Animal property which will be used as the ValueMember
    comboBox1.ValueMember = "SpeciesId";
}

飞机失事 注意,我所做的惟一更改是移动了设置DataSource的那一行:comboBox1。数据源=动物;。在前面,我在设置DisplayMember和ValueMember之后设置了它。现在,我把它放在前面。现在,当您尝试运行程序时,它会立即崩溃。您将看到如下内容: 为什么会崩溃? 为了找出程序崩溃的原因,我使用调试器逐步分析了代码。抛出以下异常: 但是,这没有多大意义。为什么它告诉我值不能为空?我的值不是空的。它是一个非常好的字符串,它指向我的Animal类的ValueMember SpeciesId。另外,如果我把这条线放晚一点,它就行了。 关于数据绑定的微软文档? 也许微软甚至声称你必须按照这个顺序来做?事实上,他们不喜欢。就文档而言,我所创建的应该是好的。但是,它不是。 1解决方案解决方案 第一个也是最明显的解决方案是:不要这样做。换句话说,只需最后设置数据源成员,然后忘记它。但这听起来像是一个完全神奇的解决方案,所以让我们寻找另一个。 第二个解决方案:处理(丢弃)异常 好吧,我们把这个异常扔掉。我只是简单地把线绕起来试试……它处理ArgumentNullException。它看起来是这样的: 隐藏,复制Code

try
{
    comboBox1.ValueMember = "SpeciesId";
}
catch (ArgumentNullException ex)
{

}

并尝试…Catch…工作吗? 它的工作。应用程序是星形的,一切看起来都很好,直到我点击组合框。请看下面两张图片: 奇怪的显示值 发生了什么事?为什么我现在有这些奇数的显示值?这些奇怪的显示值从何而来? 仔细看看动物类 嘿,还记得我在Animal类中生成的ID吗?我这样做是为了模拟一个可能从数据库或类似的地方得到的值。这样做的代码是这样的: 隐藏,复制Code

public Animal(string inSpecies, string inCommonName)
{
    this.speciesId = rnd.Next();
    species = inSpecies;
    commonName = inCommonName;
}

我做了更多的分析并确定,是的,这就是这些值的来源。但为什么它们被设置为DisplayValue呢?如果我选择其中一个值会发生什么?这个程序如你(可能)所期望的那样工作。它是这样的: 第三个解决方案解决方案 好吧,我们试试别的怎么样?我们甚至不要设置愚蠢(是的,我说了愚蠢)comboBox1.ValueMember。我们忽略它。让我们把这行代码注释掉,然后再试一次。以下是代码和结果: 隐藏,复制Code

//comboBox1.ValueMember = "SpeciesId";

同样,一开始一切看起来都很好。然后我把名单放下,然后…什么?现在,它列出了我的名称空间。类名作为显示成员。疯了!但是,它仍然有效,如果你能称之为有效的话。 A Clue and ToString() 至少这给了我一个线索。现在,我想,嘿,这使用的是动物类ToString()方法的默认值。让我们重写ToString()方法,看看我能做什么。因此,我进入Animal类并添加以下重载方法。注意,自动机器人编码器(Visual Studio Helper)尝试添加返回值base.ToString();行代码,但注释掉了。我不想做默认行为。 相反,我告诉它返回我的Animal类的commonName属性。 隐藏,复制Code

public override string ToString()
{
    return this.commonName;
    //return base.ToString();
}

它是有效的,但是等等!应该吗? 这是它现在的样子,当我运行它的时候。 所以它起作用了,但我不认为它应该起作用。微软告诉你,你需要设置这三个项目: comboBox1。DisplayMember = " CommonName "; comboBox1。ValueMember = " SpeciesId "; comboBox1。数据源=动物; 但是,记住,现在我只设置DisplayMember。我甚至没有设置ValueMember,因为我把它注释掉了。为什么我不再需要了?控件如何区分正确的项/值? 这是另一个解决方案 丢失数组,使用列表(集合) 也许这都和使用这个数组有关,这个数组中有些元素仍然是空的?我要修改代码,让它使用一个集合。这是代码: 隐藏,复制Code

// set up a collection to hold some animals
List<animal> allAnimals = new List<animal>();
public Form1()
{
    InitializeComponent();
    
    //My private method to create some animals
    InitAnimals();
    // Please note that in this example,
    // the DataSource is set first.
    // However, with a list it will work.
    comboBox1.DataSource = allAnimals;    
    // set the Animal property which will be used as the DisplayMember
    comboBox1.DisplayMember = "CommonName";
    // set the Animal property which will be used as the ValueMember
    comboBox1.ValueMember = "SpeciesId";

}

private void InitAnimals()
{
    //create 3 animals and add them to the array.
    allAnimals.Add(new Animal("Fidelis Caninus", "Dog"));
    allAnimals.Add(new Animal("Felinus Catticus", "Cat"));
    allAnimals.Add(new Animal("Elephantos Largus", "Elephant"));
}

我还通过删除先前添加的ToString()修改了Animal类。 现在我运行它,我看到的第一件事是 是的,在我看到主要形式之前我就看到了。显然,现在combobox的SelectedItemChanged事件在我启动程序后立即运行。为什么?还有什么地方可以解释这一点?任何地方?有人知道吗? 在此之后,将出现主表单,看起来如下所示: 组合框空白项:它不见了! 还记得我让你们注意组合框里有一个空白条目吗?我做到了。在本文的顶部,我说,“嘿,看,combobox中有一个空白项,因为用户还没有选择。”好吧,我已经让你注意到了,所以我们现在就开始谈论它。你看,它现在不见了。 嘿,你可能认为这没什么大不了的。我们可以避开它。我知道,但为什么没有任何东西与整个捆绑一致呢?这不是很容易吗? 希望能帮助 我希望能帮助那些在不同地方遇到这个问题的人。 历史 02.04.2010—发布了本文和代码的第一版。 本文转载于:http://www.diyabc.com/frontweb/news380.html

原文地址:https://www.cnblogs.com/Dincat/p/13443949.html