Click here to Skip to main content
15,887,267 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
In the following code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SQLite;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
    public partial class List : Form
    {
        public List()
        {
            InitializeComponent();
        }

        private void List_Load(object sender, EventArgs e)
        {
            comboBox1.SelectedIndex = 1;
		}

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
			var cmd = new SQLiteCommand("select * from students", DB.Connection);
			var ad = new SQLiteDataAdapter(cmd);
			var dt = new DataTable();
			ad.Fill(dt);
			listBox1.DataSource = dt;
			listBox1.DisplayMember = "name";
		}

		private void btnAdd_Click(object sender, EventArgs e)
		{
			Debug.Assert(listBox1.DataSource is DataTable);
			var dt = listBox1.DataSource as DataTable;
			dt.Rows.Add();
			btnEdit.Enabled = btnRemove.Enabled = dt.Rows.Count != 0;
		}

		private void btnEdit_Click(object sender, EventArgs e)
		{
			Debug.Assert(listBox1.SelectedItem is DataRowView);
			new StudentsForm2(listBox1.SelectedItem as DataRowView).ShowDialog(this);
		}

		private void btnRemove_Click(object sender, EventArgs e)
		{
			Debug.Assert(listBox1.DataSource is DataTable);
			var dt = listBox1.DataSource as DataTable;
			dt.Rows.RemoveAt(listBox1.SelectedIndex);
			btnEdit.Enabled = btnRemove.Enabled = dt.Rows.Count != 0;
		}

		private void List_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Escape)
			{
				Close();
			}
		}

    }
}

when the table is empty, I get the following exception:
Quote:
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in System.Windows.Forms.dll

Additional information: InvalidArgument=Value of '0' is not valid for 'SelectedIndex'.

in method btnAdd_Click when it calls dt.Rows.Add(). comboBox1 holds tables names, but since I only have one table at the moment it's not used unless for comboBox1_SelectedIndexChanged to be called.

Here's the stack trace at the point the exception is thrown:
Quote:
at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at System.Windows.Forms.ListBox.set_SelectedIndex(Int32 value)
at System.Windows.Forms.ListControl.DataManager_PositionChanged(Object sender, EventArgs e)
at System.Windows.Forms.CurrencyManager.OnPositionChanged(EventArgs e)
at System.Windows.Forms.CurrencyManager.ChangeRecordState(Int32 newPosition, Boolean validating, Boolean endCurrentEdit, Boolean firePositionChange, Boolean pullData)
at System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
at System.Data.DataView.OnListChanged(ListChangedEventArgs e)
at System.Data.DataView.IndexListChanged(Object sender, ListChangedEventArgs e)
at System.Data.DataView.IndexListChangedInternal(ListChangedEventArgs e)
at System.Data.DataViewListener.IndexListChanged(ListChangedEventArgs e)
at System.Data.Index.<>c.<onlistchanged>b__88_0(DataViewListener listener, ListChangedEventArgs args, Boolean arg2, Boolean arg3)
at System.Data.Listeners`1.Notify[T1,T2,T3](T1 arg1, T2 arg2, T3 arg3, Action`4 action)
at System.Data.Index.OnListChanged(ListChangedEventArgs e)
at System.Data.Index.OnListChanged(ListChangedType changedType, Int32 index)
at System.Data.Index.InsertRecord(Int32 record, Boolean fireEvent)
at System.Data.Index.ApplyChangeAction(Int32 record, Int32 action, Int32 changeRecord)
at System.Data.Index.RecordStateChanged(Int32 record, DataViewRowState oldState, DataViewRowState newState)
at System.Data.DataTable.RecordStateChanged(Int32 record1, DataViewRowState oldState1, DataViewRowState newState1, Int32 record2, DataViewRowState oldState2, DataViewRowState newState2)
at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Boolean suppressEnsurePropertyChanged, Int32 position, Boolean fireEvent, Exception& deferredException)
at System.Data.DataTable.InsertRow(DataRow row, Int64 proposedID, Int32 pos, Boolean fireEvent)
at System.Data.DataRowCollection.Add(Object[] values)
at WindowsFormsApplication1.List.btnAdd_Click(Object sender, EventArgs e) in C:\Users\hamidi\Documents\Visual Studio 2010\Projects\m_rezaee\WindowsFormsApplication1\WindowsFormsApplication1\List.cs:line 44
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.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.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at WindowsFormsApplication1.Program.Main() in C:\Users\hamidi\Documents\Visual Studio 2010\Projects\m_rezaee\WindowsFormsApplication1\WindowsFormsApplication1\Program.cs:line 18
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()


What I have tried:

I couldn't find any clue about why it happens.
Posted
Updated 20-Nov-18 22:42pm
v2
Comments
Eric Lynch 18-Nov-18 16:20pm    
If you run this in the debugger, that should help you to isolate the exact line at which the exception occurs. Sharing this information may help us to help you.

While not the cause of your problem, I do note one thing you should fix. Many classes are IDisposable (e.g. SQLiteCommand and SQLiteDataAdapter). In general, if a class is IDisposable, you should either wrap it in a "using" statement or eventually call the Dispose method. Otherwise, you will leak resources.

Another thing...it is unlikely that, in List_Load, when you set the value of comboBox.SelectedIndex to 1, that this is a valid value. At the time the form is loading, unless you pre-populated the combo-box, this would not be valid, since the combo-box would be empty. A value of 1 implies there are at least two elements. A value of 0 implies there is at least one element. When no elements are present, SelectedIndex is traditionally -1, though you should not set it to this value either.
ilostmyid2 18-Nov-18 23:22pm    
Thanks Eric for taking time in reviewing my code and for your notes about it. I updated the question and added the stack trace at the point the debugger specifies as the source of the exception. I hope this info may help. As I told before the exception is pointed by compiler to be at line I call dt.Rows.Add().
About disposing the IDisposable objects, I thought GC will dispose them later. You mean it doesn't?
About the combobox content, I fill it with two items in .Designer.
Eric Lynch 18-Nov-18 23:49pm    
The debugger will usually point you at the exact line a bit easier...hence the suggestion. Getting a bit sleepy, so I'll have to take a look at the stack trace tomorrow.

Regarding GC, its great at reclaiming allocated memory...at some point after instances pass out of scope.

IDisposable solves a different problem. With IDisposable, there is often an unmanaged resource (network connection, file handle, etc.) associated with the instance. GC seldom does anything to reclaim these resources. So, if a class implements IDisposable, you really should call the Dispose method (usually implicitly via a using statement) to avoid leaking these resources.

Honestly, this cleanup is often (not always) a bit of legacy baggage at the boundary of where .NET began and traditional windows APIs continued.

C# is really helpful in this respect. The using statement guarantees that disposal occurs even in the presence of exceptions. Of course, your always free to use try/finally blocks, and call Dispose yourself, to accomplish a similar, but less concise, outcome :)
Eric Lynch 19-Nov-18 10:03am    
I took a look at your stack trace and I have to admit that I am a bit mystified. From the stack trace, as you mention, the exception appears to occur during the call to dt.Rows.Add. This call, for some reason, internally results in a change in the selected index for some ListBox (possibly listBox1). However, by the time that call occurs something has changed such that the proposed index value is no longer valid.

I tried to re-produce the circumstances with my own code, but was unable. There seems to be something that is not evident in the code that you have shared.

So, regrettably, I'm left guessing a little bit. I think this one may be difficult to debug.

My first guess is that, like you, I'm missing something obvious. If that's the case, I may be the wrong one to help you :)

Another possibility is that you have a mis-wired event. I'd check all of the events, for the components on your form, to be certain that they are ALL wired to the method you expect. Also, it might be worth improving your question to share this wiring. Its not evident in your code.

Another guess, perhaps you are not sharing all of the current or relevant code for your form? I'd check that and improve your question, if necessary.

Next, I'd take care of the low-hanging fruit. Clean up what you can. For example, Dispose where you should dispose. Also, consider the line dt.Rows.Add(). Is this truly what you mean to do? Add a row where all of the column values are null? This seems odd.

Also, the relationship between your combo-box and list-box seems unusual. When the combo-box changes, you are changing the data source for the list box. It seems you are refreshing the list box entirely independent of the new index value for the combo-box. This is unusual.

Also, in the debugger, I'd set breaks in every single method in your form. Is one getting called at a time that you are not expecting?

I'd use the debugger to take a hard look at your DataTable. Does it have the expected columns, with the expected values, and with the expected constraints?

Admittedly, the suggested code clean up is not very likely to fix your issue. However, the more variables you can eliminate the easier it is to track an issue.

Finally, if you reach the point of desperation, as a last resort, there is another trick I've found helpful in these situations. Start commenting out code until your issue disappears. Then back track, uncommenting, until you figure out the minimum code required to reproduce it. This can at least narrow what you need to consider to fix it.

Hope some of this helps or someone else sees the obvious and points it out.
ilostmyid2 20-Nov-18 0:06am    
In the first paragraph, I prefer "not yet" to "no longer". Maybe this happens before the item is completely added to the list box. For the second and third paragraph, I say that maybe it's a bug rather than a problem in my code.
I couldn't find your meaning with wired or mis-wired event. If some other info is required, tell me to share.
Calling dt.Rows.Add is a technique which add columns with their default values, not null!
Yeah, I change the list box data source with a change in the combobox index, because the combobox holds tables names and evidently when a table is changed a new structure should be shown in the list box.
I thought the same. So I put Debug.WriteLine where I thought might be called during calling dt.Rows.Add(). But I found that no other parts of my code are called.
About the DataTable, there's no explicit expectation in this function. The columns may be whatever they are. Although they're in good manner, it can't be the source of the problem.
Since other parts of my code is not getting involved logically and practically during calling dt.Rows.Add, simplifying them can't affect on the symptom.
Thanks for suggesting the commenting out code method. It works because of the simplifying I mentioned. But as I said, it can't help in this case.
At last, I worry about this being a bug. When I googlized it, someone had suggested to add the handler for SelectedIndexChanged after calling dt.Rows.Add, although it's not called anyway!

Your stack trace has already provided you with the clues you need:
C:\Users\hamidi\Documents\Visual Studio 2010\Projects\m_rezaee\WindowsFormsApplication1\WindowsFormsApplication1\Program.cs:line 18
and
\WindowsFormsApplication1\List.cs:line 44
Go look at what is happening there. stick in a break point at those line and inspect the objects and variables used there
 
Share this answer
 
Comments
ilostmyid2 20-Nov-18 0:06am    
:)
In Visual Studio 2010, when the debugger is told to stop at all exceptions, it does it regardless of whether the exception is handled or not. For example, if you write such a code:

C#
try
{
  throw new Exception("test");
}
catch
{
  // do nothing
}

the debugger stops at the line which throws exception, even if it's caught and handled. Note that this also happens if an exception is thrown inside the codes which don't belong to our own. We may call methods of classes we're not written and we just use them. The methods may have been written in a way that handle exceptions and do something in response. If you call the whole application in this case, you won't get an exception, because it's handled inside the methods. But if you run them via the debugger, you see that these exceptions are thrown.
In this code, it seems that such a thing is happened. I prefer not to uncheck the out of range exception from the Debug/Exceptions... menu. I prefer to be informed if any part of my code is not performing well. But such an exceptions should not be informed, because they're properly handled.
For this, I need to:
1. check all exceptions in Debug/Exceptions... menu of Visual Studio.
2. check the option Enable Just My Code (Managed only) in Tools/Options/Debugging/General.
So, debugger will only stops on exceptions which are thrown by your own code.

PS. I found the info and solution here.
 
Share this answer
 
v4

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900