Two-way binding with Windows Forms ComboBox throws NullReferenceException when changed

不问归期 提交于 2020-01-05 12:02:32

问题


I have a Windows Forms application, and one of the forms has a couple of ComboBoxes that are both bound to the same BindingList of objects I have mapped via Entity Framework.

The Form_Load event calls this:

private void SetFacilityDropdowns()
{
    dbContext.Facilities.Load();
    var bindingSource = dbContext.Facilities.Local.ToBindingList();
    Dictionary<ComboBox, string> selectedDropDownsAndBoundFields = new Dictionary<ComboBox, string>
        {
            {FacilityId,    DataConstants.Facility.FacilityId},
            {FacilityName,  DataConstants.Facility.FacilityName}
        };
    SetDropdowns(bindingSource, selectedDropDownsAndBoundFields);            
}

The SetDropdowns method looks like this:

private static void SetDropdowns<T>(BindingList<T> dataSource, Dictionary<ComboBox, string> dropdownsAndBoundFields)
{
    if (dropdownsAndBoundFields == null)
    {
        return;
    }

    foreach (var dropdown in dropdownsAndBoundFields)
    {
        dropdown.Key.DataSource = dataSource;
        dropdown.Key.DisplayMember = dropdown.Value;
        dropdown.Key.ValueMember = dropdown.Value;
        dropdown.Key.AutoCompleteSource = AutoCompleteSource.ListItems;
        dropdown.Key.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
        dropdown.Key.SelectedIndexChanged += Dropdown_SelectedIndexChanged;
    }
}

Everything looks fine, and both ComboBoxes appear to contain all of the items that I would expect them to. However, there are a few Facility objects from the Facilities table where the FacilityName property is null. This appears in the ComboBox as an empty string, although I don't know if it is only displayed that way or if it gets converted when it is bound.

Normally, when I change the FacilityName dropdown, the FacilityId dropdown changes to its matching value. However, when I change FacilityName to one of the null/empty string values, I get a NullReferenceException thrown. It appears to be thrown by the Windows Forms UI thread, so I can't set a breakpoint in any of the ComboBox "changed" events, because the exception gets thrown before any of the events get fired.

Any idea why this is happening?

EDIT:

Here is a stack trace:

>   NITS.exe!NITS.Program.CurrentDomain_UIThreadException(object sender, System.Threading.ThreadExceptionEventArgs t) Line 50   C#
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.OnThreadException(System.Exception t) + 0x8e bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProcException(System.Exception e) + 0x16 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(System.Exception e) + 0xa bytes 
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x9b bytes   
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.Control.SendMessage(int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x21 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Control.ReflectMessageInternal(System.IntPtr hWnd, ref System.Windows.Forms.Message m) + 0x3b bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Control.WmCommand(ref System.Windows.Forms.Message m) + 0x1b bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x3b7 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) + 0x2a bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m) + 0x5e bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x11 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x35 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x80 bytes   
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(ref System.Windows.Forms.Message m) + 0x56 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Control.DefWndProc(ref System.Windows.Forms.Message m) + 0xa bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseDown(ref System.Windows.Forms.Message m, System.Windows.Forms.MouseButtons button, int clicks) + 0x3a bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x8da bytes 
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.WndProc(ref System.Windows.Forms.Message m) + 0x864 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x11 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x35 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x80 bytes   
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) + 0x24d bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x155 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x4a bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) + 0x31 bytes  
    NITS.exe!NITS.Program.Main() Line 37 + 0x1d bytes   C#
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x6b bytes    
    Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27 bytes  
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x6f bytes   
    mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0xa7 bytes  
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x16 bytes  
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x41 bytes    
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes   
    [Native to Managed Transition]  

The exception being thrown looks like this:

System.NullReferenceException Object reference not set to an instance of an object. System.String get_Text()    at System.Windows.Forms.ComboBox.get_Text()
   at System.Windows.Forms.ComboBox.WmReflectCommand(Message& m)
   at System.Windows.Forms.ComboBox.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

回答1:


Your main exception is obviously

System.NullReferenceException Object reference not set to an instance of an object. System.String get_Text() at System.Windows.Forms.ComboBox.get_Text()

which leads me to believe that your combobox is trying to set the DisplayMember property to a null value. Since you said yourself you're not sure if the empty columns coming back from your database are represented as empty strings or null in the Facility class, you can explicity convert them in your getters. In addition, if you are passing in a Nullable to your FacilityID property, you need to convert it to an int so the combobox can handle it.

So, in your Facility class.

    public class Facility
    {
        private string _facilityName;
        private int _facilityID;

        public string FacilityName
        {
            get
            {
                if (_facilityName == null)
                    return String.Empty;
                else
                    return _facilityName;
            }
            set { _facilityName = value; }
        }

        public int FacilityID
        {
            get { return _facilityID; }
            set { _facilityID = value == null ? default(int) : value};
        }
    }

Using this, you'll make sure that you never have your control attempting to bind to a null value, and it should rid you of the exception.




回答2:


You can try maybe to use IntelliTrace to get more info?



来源:https://stackoverflow.com/questions/23273064/two-way-binding-with-windows-forms-combobox-throws-nullreferenceexception-when-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!