【问题标题】:C# WinForms (.NET 3.5): ComboBox returns null reference after first selectionC# WinForms (.NET 3.5):ComboBox 在第一次选择后返回空引用
【发布时间】:2015-10-21 08:29:57
【问题描述】:

注意:这是一个普通的 WinForms 应用程序。没有 WPF 或 WCF 或其他任何东西。

大家好,我正在开发一个 WinForms (.NET 3.5) 应用程序,但遇到了一个问题。我正在尝试根据所选州获取城市(两者都在 2 个不同的 ComboBox-es 中,DropDownStyle 设置为 DropDownList)。

我已经使用SelectedValue 属性在SelectedIndexChanged 事件处理程序中实现了这个逻辑。 DataSource 是从 DB 方法返回的 DataTableSelectedValue 返回 DataRowView 的实例。

在表单构造函数中,我填充状态组合框并使用SelectedIndex 属性以编程方式设置默认状态选择;然后它转到事件处理程序,正确执行,并为该州填充城市 ComboBox

现在问题来了,当我更改选定状态构建后,当表单启动并运行时,使用我的鼠标。这再次转到事件处理程序,但SelectedValue 属性返回一个空引用。请帮忙。我附上下面的代码。

private void comboFindState_SelectedIndexChanged(object sender, EventArgs e)
        {

            DataRowView selectedState;
            int selectedStateId;
            DataTable citiesTable;

            selectedState = comboFindState.SelectedValue as DataRowView;


            if (selectedState != null) //Is true the first time around when the event is
            //triggered due to programmatic change of the index.
            //Then null afterwards, on change via mouse click.
            {
                selectedStateId = Convert.ToInt32(selectedState.Row["State Code"]);
                citiesTable = DatabaseHelper.getStateCities(selectedStateId);

                comboFindCity.DataSource = citiesTable; //Same binding for state ComboBox
                //in the form's constructor;
                comboFindCity.DisplayMember = "City"; //only here it says "State",
                comboFindCity.ValueMember = "City Code";// and here it says "State Code".

                comboFindCity.SelectedIndex = 0; //Same thing in the form's constructor for
                //setting default selected index of state ComboBox.
            }
            else
            {
                //just populates an error TextBox saying 'No Cities Found'
            }
        }

请注意,所有这些都发生在状态 ComboBox 中,该状态已被填充。城市ComboBox第二次都没有进入范围,所以不存在数据库问题。

编辑:仅供参考,我从绝对开始为 tcomboFindState 设置了ValueMember 属性。所以这不是它不起作用的原因。另请注意,它第一次运行正常,因此证明 ValueMember 设置正确。

【问题讨论】:

  • 您可以尝试将 comboFindState.SelectedValue 替换为 comboFindState.SelectedItem 吗?
  • 瞧!有用!你先生/女士,应该被称为我的救世主。但是,我仍然不明白为什么 SelectedValue 第二次没有工作。对这个问题有什么想法吗?
  • 正如 Fabio 解释的那样,问题出在 DataSource 属性的使用上。您需要设置 ValueMember。
  • 我已经设置了ValueMember 属性。与 Fabio 的代码的唯一区别是我首先设置了DataSource,然后设置了ValueMember。这似乎是合乎逻辑的事情,否则如果DataSource 为空,编译器将如何知道“状态代码”的含义?如果不同,请解释。
  • 您可以在DataSource之前或之后两种方式设置ValueMember。如果您在分配DataSource 之后设置ValueMember,则可能会使用数据源属性/列对新的ValueMember 进行一些额外的检查。

标签: c# winforms combobox .net-3.5


【解决方案1】:

只需正确使用DataSource,无需解决方法。
在将DataSource 设置属性ValueMember 设置为您用于获取城市的列名之前

comboFindState.ValueMember = "State Code";
comboFindState.DisplayMember = "StateName"; //will be displayed in the combobox
comboFindState.DataSource = yourDataTableOfStates;

然后SelectedValue 会将State Code 的值返回为整数类型(装箱在 Object 类型中)
null 如果comboFindState.SelectedIndex = -1

private void comboFindState_SelectedIndexChanged(object sender, EventArgs e)
{
    if (comboFindState.SelectedValue != null)
    {
        int selectedStateId = (int)comboFindState.SelectedValue;
        DataTable citiesTable = DatabaseHelper.getStateCities(selectedStateId);

        //Your code after getting list of the cities
    }
}

另外
如果您要设置ValueMember,那么您可以使用SelectedValueChanged 事件

...关于 cmets...
如果 DataSource 为空,编译器如何知道“状态代码”的含义?如果不一样,请解释一下
编译器与这个问题无关。这发生在运行时 当您设置ValueMemberDataSourcenull(之前)。然后ValueMember 的值将被保存并仅在您调用SelectedValue 时使用。
如果在DataSource 的属性/列中找不到ValueMember,则返回整个选定对象,如果DataSourceDataTable,则返回DataRowView

当您设置ValueMemberDataSource 不是null(之后)。
如果DataSource 的类型中存在属性/列,则将检查ValueMember 的新值。如果不存在,则抛出ArgumentException

【讨论】:

  • 然后 SelectedValue 将返回 State Code 的值作为整数类型(装箱在 Object 类型中) - 这不会发生。它返回一个 DataRowView 对象。如果我尝试直接将 SelectedValue 对象转换或强制转换为 int 或 string,它会抛出 InvalidCastException。这是最让我烦恼的。它不是返回一个标量值,而是返回一个 DataRowView 对象。我认为这是由于将DataTable 设置为DataSource
  • 设置comboFindState.ValueMember = "State Code";是正确的
  • 另外,你介意解释一下为什么ValueMember应该设置在之前 DataSource吗?当基础数据甚至不可用时指定一些相对值似乎不合逻辑。
  • 设置comboFindState.ValueMember = "State Code";。从绝对开始。因此出现了问题。
猜你喜欢
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多