Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setting ComboBox.SelectedValue to null cause a ArgumentNullException?

Why does setting the SelectedValue of a ComboBox to null cause an ArgumentNullException?

The Exception only occurs if the ComboBox is actually part of a Form. I can set SelectedValue to all kinds of values or types that don't make sense, but I can't set it to null.

It's not that SelectedValue can not be null. In fact, its value is null at the time I'm trying to set it to null.

In my real code, this doesn't happen in the constructor, and I'm not excplicitly setting it to null. The code is using a variable which happens to be null. I can fix it by checking of the variable isn't null before trying to set the SelectedValue. But what I don't understand is why I can't set it to a null value.

Code edit: DataSource now contains an item where the ValueMembers value is actually null

using System.Collections.Generic;
using System.Windows.Forms;

public class Form1 : Form {
    public Form1() {
        var comboBox1 = new ComboBox();
        Controls.Add(comboBox1);
        comboBox1.ValueMember = "Key";
        comboBox1.DisplayMember = "Value";
        comboBox1.DataSource = new List<Record> {
            new Record {Key = "1", Value = "One"}, 
            new Record {Key = null, Value = "null"}
        };
        comboBox1.SelectedItem = null;          // no problem
        comboBox1.SelectedValue = "";           // no problem
        comboBox1.SelectedValue = new object(); // no problem
        comboBox1.SelectedValue = null;         // ArgumentNullException!!
    }
}

public class Record {
    public string Key { get; set; }
    public string Value { get; set; }
}
like image 735
comecme Avatar asked May 15 '13 07:05

comecme


2 Answers

Inspecting the implementation of the property in Reflector it looks like this:

public object SelectedValue
{
    get
    {
        if ((this.SelectedIndex != -1) && (this.dataManager != null))
        {
            object item = this.dataManager[this.SelectedIndex];
            return this.FilterItemOnProperty(item, this.valueMember.BindingField);
        }
        return null;
    }
    set
    {
        if (this.dataManager != null)
        {
            string bindingField = this.valueMember.BindingField;
            if (string.IsNullOrEmpty(bindingField))
            {
                throw new InvalidOperationException(SR.GetString("ListControlEmptyValueMemberInSettingSelectedValue"));
            }
            PropertyDescriptor property = this.dataManager.GetItemProperties().Find(bindingField, true);
            int num = this.dataManager.Find(property, value, true);
            this.SelectedIndex = num;
        }
    }
}

So this seems to hinge on this.dataManager not being null.

If this.dataManager isn't null, the setter will call Find() with key set to the value that you're setting SelectedValue to:

internal int Find(PropertyDescriptor property, object key, bool keepIndex)
{
    if (key == null)
    {
        throw new ArgumentNullException("key");
    }
    if (((property != null) && (this.list is IBindingList)) && ((IBindingList) this.list).SupportsSearching)
    {
        return ((IBindingList) this.list).Find(property, key);
    }
    if (property != null)
    {
        for (int i = 0; i < this.list.Count; i++)
        {
            object obj2 = property.GetValue(this.list[i]);
            if (key.Equals(obj2))
            {
                return i;
            }
        }
    }
    return -1;
}

Which will throw an exception if key is null.

I'm guessing that dataManager is only set to non-null when the ComboBox is inserted into a container (e.g. a Form) which is why it doesn't blow up when it's not in a container.

(In fact, dataManager will be set to non-null when you set the Control.DataSource property to non-null.)

However, this doesn't seem quite right, because you reported a NullReferenceException and this clearly throws an ArgumentNullException.

[EDIT] It was indeed an ArgumentNullExeption; OP has been updated accordingly.

like image 72
Matthew Watson Avatar answered Nov 02 '22 15:11

Matthew Watson


My guess was that this may be a miss on what should be an ArgumentNullException rather than a NullReferenceException (thrown in the property setter's implementation).

On quickly checking the code you provided (plus a Main method with var form1 = new Form1()), though, I find that I do not actually get a NullReferenceException like you describe but rather an ArgumentNullException like I expect I should.

Are you sure that you noted the exception type correctly?

UPDATE:

As Matthew Watson describes, the parameter indicated by the ArgumentNullException is, in fact, key.

like image 38
J0e3gan Avatar answered Nov 02 '22 13:11

J0e3gan