8

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; }
}
comecme
  • 6,086
  • 10
  • 39
  • 67
  • Do you have code linked to SelectedIndexChanged event or some other event triggered by the change of the current value? – Steve May 15 '13 at 07:38
  • See if this question can help. http://stackoverflow.com/questions/2864065/c-sharp-set-combo-item-with-selectedvalue/2864119 – Cheng Chen May 15 '13 at 07:52
  • @Steve: No. The above sample code is a complete working example showing the exception. – comecme May 15 '13 at 08:26

5 Answers5

6

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.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • +1 for quick and thorough "rubber glove" analysis as it were. I noted that the exception thrown is actually `ArgumentNullException`...but didn't note initially that `key` was the offending parameter, that the setter itself was not the source of the exception. Strong work. :} – J0e3gan May 15 '13 at 08:03
  • 1
    I'm sorry, the exception thrown is indeed the ArgumentNullException. I will change my post. – comecme May 15 '13 at 08:28
  • 1
    So the question now becomes why the Find method doesn't accept `null` as its `key` value. It *is* possible to create a `Record` with a `key` of `null` and add it to the `DataSource`. But you wouldn't be able to set `SelectedValue` to that value. – comecme May 15 '13 at 08:32
  • @comecme: The answer to why `Find` doesn't accept a `null` for `key` is right in the opening of its body - `if (key == null) { throw new ArgumentNullException("key"); }`. – J0e3gan May 15 '13 at 08:38
  • 4
    @J0e3gan I see that. That's why the code is throwing the exception. But _why_ is that line in there? I've updated my code to show that's it's perfectly fine to have an item where the DataMember property has a `null` value. I would expect to be able to set the SelectedValue to `null` as it is a valid value in this case. – comecme May 15 '13 at 08:44
2

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.

J0e3gan
  • 8,740
  • 10
  • 53
  • 80
0

Perhaps it's because if the property ValueMember of SelectedValue is Nothing, then the SelectedValue will return .ToString() on the SelectedItem.

Paul Zahra
  • 9,522
  • 8
  • 54
  • 76
0

On the button_click, this code fonctionned and deleted ArgumentNullException :

if (comboBoxPays.SelectedValue == null)
{
  id_pays = 0;
}
else
  id_pays = int.Parse(comboBoxPays.SelectedValue.ToString());
Gie
  • 1,907
  • 2
  • 24
  • 49
0

I know this is an old question, but I have the same error right now and I have find that I cannot set SelectedValue = null but I did managed to set it to DBNull.Value

GuidoG
  • 11,359
  • 6
  • 44
  • 79