thomas10001 Posted January 20, 2005 Posted January 20, 2005 I have a DataGrid that I have bound to an ArrayList. If I create a new row and save right away everything is fine. But if I select any column in the new row BEFORE saving the first row I get an error message saying: -------------------------------------------------------------------- Error when committing the row to the original data store. Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index Do you want to correct the value? [Yes] [No] If I select [No] I get another errror message saying System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index at System.Collections.ArrayList.get_Item(Int32 index) -------------------------------------------------------------------- After I started to catch the CurrentCellChanged event for the DataGrid I found out that the CurrentRowIndex of DataGrid and Position of CurrencyManager is -1. And if I try to set the value to 0, it gets back to -1 automatically. :( If I would had another row in arraylist (ie if I saved right away, close my window and open it again) and then create a new row. Then I can click in another column without getting this error. I have searched alot on internet and found that there are other having the same problem. But have not got a solution that works. Someone suggested to reinitiate the datasource. Tried that with no success. Is there anyone here who know how to fix this problem? :confused: Quote
barski Posted January 22, 2005 Posted January 22, 2005 I was having some of the same issues when using databinding with arraylist. Someone suggested this article and it cleared things up http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet02252003.asp Quote
thomas10001 Posted January 24, 2005 Author Posted January 24, 2005 I was able to get the (New) adding new rows to work by using the code below. (It has a own defined class DataMapping and DataList which takes care of the columngrid styles and the values for the arraylist) After finding out that (from some other with similar problems) the datasource must be set to a dummy temporarily to get it to work. It is a bit awkward to have to set it to a dummy value! But I cannot get the delete command to work properly. If I delete the last row I get the arrayoutofbounds exception later if I click somewhere in the grid (not in the code below but somewhere undebuggable). But if there is only one single row (which is also last) I don't get the exception. The key seems to be the position. Position gets to -1 sometimes and even if I explicity set it to 0 it doesn't change. Anyone has a clue how to get the delete of the last row to work? If I delete the last row of course Position must be set to one row less otherwise it points outside the array. But I cannot get the position to be updated correctly in this case. private void updateSource(object dataSource) { System.Windows.Forms.DataGrid dg = ((UserControlWinGrid)this.getCurrentUserControl()).getDataGrid(); dg.DataMember = ""; dg.DataSource = dataSource; dg.Refresh(); } private void addArrayList(DataMapping dm) { DataList dl = new DataList(); int pos = dm.arrayList.Add(dl); DataList dl2 = new DataList(); System.Collections.ArrayList al = new ArrayList(); al.Add(dl2); cs = (CurrencyManager)this.BindingContext[dm.arrayList]; if(cs.Position < 0) { this.updateSource(null); this.updateSource(al); // set dummy array this.updateSource(this.getCurrentUserControl().getDataMapping().arrayList); cs.Refresh(); cs.Position = pos; } cs.EndCurrentEdit(); cs.Position = pos; // moved to here 2005-01-22 cs.Refresh(); this.updateSource(null); this.updateSource(al); // set dummy array this.updateSource(this.getCurrentUserControl().getDataMapping().arrayList); } private void deleteArrayList(DataMapping dm,System.Data.DataSet ds,string showTable) { int removeAt = ((UserControlWinGrid)this.getCurrentUserControl()).getDataGrid().CurrentCell.RowNumber; dm.arrayList.RemoveAt(removeAt); //------------------------------------------------------- // try this to get rid of exception cs = (CurrencyManager)this.BindingContext[dm.arrayList]; int position = removeAt-1; cs.Refresh(); if(position < 0) position = 0; //------------------------------------------------------- this.BindingContext[ds,showTable].RemoveAt(removeAt); this.BindingContext[ds,showTable].Position = position; //------------------------------------------------------- // more test code // create a dummy array DataList dl = new DataList(); System.Collections.ArrayList al = new ArrayList(); al.Add(dl); this.updateSource(null); this.updateSource(al); // set dummy array this.updateSource(dm.arrayList); // set back original } Quote
thomas10001 Posted January 24, 2005 Author Posted January 24, 2005 Here is the exception I get. Caused by the "stubborn" Position pointing wrong ************** Exception Text ************** System.IndexOutOfRangeException: Index was outside the bounds of the array. at System.Windows.Forms.DataGrid.Edit(String instantText) at System.Windows.Forms.DataGrid.Edit() at System.Windows.Forms.DataGrid.OnEnter(EventArgs e) at System.Windows.Forms.Control.NotifyEnter() at System.Windows.Forms.ContainerControl.UpdateFocusedControl() :o Quote
RobEmDee Posted January 25, 2005 Posted January 25, 2005 (edited) thomas: I have a less efficient way of tackling your requirements.....but it works. ;) public void DeleteGridRow() { int rowIDX = grid.CurrentCell.RowNumber; if(rowIDX >= 0) { ArrayList list = (ArrayList) grid.DataSource; grid.DataSource = null; list.RemoveAt(rowIDX); grid.DataSource = list; } } public void AddGridRow(object dataItem) { ArrayList list = (ArrayList) grid.DataSource; grid.DataSource = null; list.Add(dataItem); grid.DataSource = list; } Edited January 25, 2005 by RobEmDee Quote
thomas10001 Posted January 25, 2005 Author Posted January 25, 2005 thomas: I have a less efficient way of tackling your requirements.....but it works. ;) I tried the code for delete. But unfortenaly I still get the same exception if I delete the last row (if there are more than one row). The exception happens after the delete has been done, if I click somewhere in the grid. Also I see that the position indicator does not show if I delete the last position. I am using C#. Can it be that there is a problem in C# with grids and arraylists? ************** Exception Text ************** System.IndexOutOfRangeException: Index was outside the bounds of the array. at System.Windows.Forms.DataGrid.Edit(String instantText) at System.Windows.Forms.DataGrid.Edit() at System.Windows.Forms.DataGrid.OnEnter(EventArgs e) at System.Windows.Forms.Control.NotifyEnter() at System.Windows.Forms.ContainerControl.UpdateFocusedControl() Quote
RobEmDee Posted January 25, 2005 Posted January 25, 2005 thomas: How are you triggering the row deletion? e.g. Button on the Form, Select row header and clicking Delete key on keyboard, from a ContextMenu..... Quote
thomas10001 Posted January 27, 2005 Author Posted January 27, 2005 thomas: How are you triggering the row deletion? e.g. Button on the Form, Select row header and clicking Delete key on keyboard, from a ContextMenu..... Hi I have a button on my form which calls my delete method. By the way when my grid is empty the headers don't show. Even though I have initialized the variables in the class that are used in the list. I read somewhere that this was required. Maybe this has something to do with this problem?! Quote
thomas10001 Posted January 27, 2005 Author Posted January 27, 2005 I do both dm.arrayList.RemoveAt(removeAt); and this.BindingContext[ds,showTable].RemoveAt(removeAt); Is it correct that I would have to delete from the dataset as well or should it be handled automatically by the arrayList since its connected to the dataset. However before I do my Update of the dataset I have to copy the values over from my arrayList into the dataset. Is this really the correct way? Thomas Quote
thomas10001 Posted January 27, 2005 Author Posted January 27, 2005 thomas: How are you triggering the row deletion? e.g. Button on the Form, Select row header and clicking Delete key on keyboard, from a ContextMenu..... I have a special class (DataMapping and DataList) for GridColumnStyles I use which is general so I don't have to have a hardcoded class for the items in the grid. I don't know if the problem could be in that code. But it doesn't feel like it is there. I could had posted it here unless it wasn't that much code. Quote
thomas10001 Posted January 27, 2005 Author Posted January 27, 2005 I post a bit of the code here... I post part of the DataList and DataMapping I am using in my example in case the problem lies here. I have several int's double strings etc in my code to make it general. But here I have removed them to make the code shorter. public class DataList { private string myString1 = ""; private int myInt1 = 0; private bool isNullInt1 = true; public DataList() { } public string string1 { get {return myString1;} set {myString1 = value;} } public int int1 { get {return myInt1;} set {myInt1 = value;isNullInt1 = false;} } public bool isNullint1 { get {return isNullInt1;} } } } //----------------------------------------------------------- public class DataMapping { private StringCollection myMappingName; private StringCollection myMappingTable; private StringCollection myMappingColumn; private StringCollection myInternalName; private StringCollection myRelationName; private StringCollection myType; private ArrayList myIndex; private ArrayList dataLists; private int intUsed = 0; private int stringUsed = 0; private int myCount = 0; public ArrayList arrayList { get { return dataLists; } } public void clearDataList() { dataLists.Clear(); } public DataMapping() { this.dataLists = new ArrayList(); this.myMappingName = new StringCollection(); this.myMappingTable = new StringCollection(); this.myMappingColumn = new StringCollection(); this.myInternalName = new StringCollection(); this.myRelationName = new StringCollection(); this.myType = new StringCollection(); this.myIndex = new ArrayList(); } public int getNRelations() { return this.myRelationName.Count; } public string getRelationName(int item) { return this.myRelationName[item]; } public string getTableName(int item) { return this.myMappingTable[item]; } public void Add(string mappingName,string mappingTable,string mappingColumn,string type,string relationName) { addMapping(mappingName,mappingTable,mappingColumn,type); this.myRelationName.Add(relationName); } // mappingName a unique name for this mapping // mappingTable table to find the value // mappingColumn column in mappingTable to find value // type int or string (so far) public void Add(string mappingName,string mappingTable,string mappingColumn,string type) { addMapping(mappingName,mappingTable,mappingColumn,type); this.myRelationName.Add(""); } private void addMapping(string mappingName,string mappingTable,string mappingColumn,string type) { this.myCount++; this.myMappingName.Add(mappingName); this.myMappingTable.Add(mappingTable); this.myMappingColumn.Add(mappingColumn); this.myType.Add(type); // ie: we have "round" as the first mappingname and it is an int string internalName = ""; int index = 0; switch(type) { case "int": intUsed++; index = intUsed; internalName = "int"+intUsed; break; case "string": stringUsed++; index = stringUsed; internalName = "string"+stringUsed; break; } this.myInternalName.Add(internalName); this.myIndex.Add(index); } public string getInternalName(string mappingName) { // returns the internal name corresponding the mappingName int item = this.myMappingName.IndexOf(mappingName); return this.myInternalName[item]; } public string getMappingNameFromColumnName(string columnName) { int item = this.myMappingColumn.IndexOf(columnName); return this.myMappingName[item]; } public string getColumnName(int item) { return this.myMappingColumn[item]; } public string getInternal(int item) { return this.myInternalName[item]; } public string getMapping(int item) { return this.myMappingName[item]; } public string getType(int item) { return this.myType[item]; } public int getIndex(string mappingName) { int item = this.myMappingName.IndexOf(mappingName); int index = 0; index = (int)this.myIndex[item]; return index; } public void AddDataList() { dataLists.Add(new DataList()); } public void setValue(int row,string mappingName,int intValue) { switch(getIndex(mappingName)) { case 1: ((DataList)dataLists[row]).int1 = intValue; break; } } public void setValue(int row,string mappingName,string stringValue) { switch(getIndex(mappingName)) { case 1: ((DataList)dataLists[row]).string1 = stringValue; break; } } public int getIntValue(int row,string mappingName) { switch(getIndex(mappingName)) { case 1: return ((DataList)dataLists[row]).int1; } return 0; } public bool getIsNullInt(int row,string mappingName) { switch(getIndex(mappingName)) { case 1: return ((DataList)dataLists[row]).isNullint1; } return true; } public string getStringValue(int row,string mappingName) { switch(getIndex(mappingName)) { case 1: return ((DataList)dataLists[row]).string1; } return ""; } public int Count { get {return myCount;} } } } //----------------------------------------------------------- Code for columnstyles public void addDataMapping(string mappingName,string mappingTable,string mappingColumn,string type) { dataManager.addDataMapping(mappingName,mappingTable,mappingColumn,type); } public void addDataMapping(string mappingName,string mappingTable,string mappingColumn,string type,string relationName) { dataManager.addDataMapping(mappingName,mappingTable,mappingColumn,type,relationName); } public string getDataInternalName(string mappingName) { return dataManager.getDataInternalName(mappingName); } public void addDataGridTableStyle(DataGrid dataGrid) { gridTableStyle = new DataGridTableStyle(); gridTableStyle.DataGrid = dataGrid; gridTableStyle.HeaderForeColor = System.Drawing.SystemColors.ControlText; // if using dataMappings we have an ArrayList inside the DataMapping object // and mappingName must be "ArrayList" // otherwise mappingName is the name of tables[0] // since we then should only have one table if(this.getDataMapping().Count > 0) gridTableStyle.MappingName = "ArrayList"; else gridTableStyle.MappingName = getDataSet().Tables[0].TableName; dataGrid.TableStyles.Add(gridTableStyle); } public void addGridColumnStyle(string header,string mappingName,int width,bool readOnly,string columnType,string formatString) { DataGridTextBoxColumn column = new DataGridTextBoxColumn(); column.HeaderText = header; // check if we have dataMappings if(this.getDataMapping().Count > 0) column.MappingName = getDataInternalName(mappingName); // the the internal mapping name else column.MappingName = mappingName; // mapping name is the name itself column.Width = width; column.ReadOnly = readOnly; column.TextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.KeyDown); column.TextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.KeyUp); if(!formatString.Equals("")) column.Format = formatString; gridTableStyle.GridColumnStyles.Add(column); } //----------------------------------------------------------- Code to setup my datamapping and columnstyles for my datagrid addDataMapping("bedid","bed","bedid","int"); addDataMapping("roomid","bed","roomid","int"); addDataMapping("bedname","bed","bedname","string"); ... addDataGridTableStyle(this.grid); addGridColumnStyle("BedId","bedid",0,false,"TextBox",""); addGridColumnStyle("RoomId","roomid",0,false,"TextBox",""); addGridColumnStyle("Bed Name","bedname",80,false,"TextBox",""); Quote
RobEmDee Posted January 27, 2005 Posted January 27, 2005 thomas: What are the requirements in place that call for the use of an ArrayList and a DataSet? In my opinion, if the data needs to end up in a DataSet anyways, you should just bypass the complications of the ArrayList and use your DataSet for everything. Quote
thomas10001 Posted January 27, 2005 Author Posted January 27, 2005 Hi I have made a framework where I want to be able to use other controls than a textbox in the grid. ie comboboxes etc. I thought this is the only? way to be able to use other controls. I also do not want the empty insertion row (marked *) which I don't know how to suppress. Thomas Quote
thomas10001 Posted January 27, 2005 Author Posted January 27, 2005 Hi Another reason I just rediscovered is that I have problem to set values (primary keys I have generated if I have datagridtablestyle attached) If I just have a plain dataset, no datagridtablestyle , I do this to set the values in the new row. DataSet ds1 = getDataSet(); BindingManagerBase myMgr = (CurrencyManager) BindingContext[ds1,tableName]; if(myMgr.Count > 0) { // This is the way to set a value in a row which has not been saved yet // and merged into the normal dataset DataRowView tempRowView = (DataRowView) myMgr.Current; if(tempRowView.IsNew) { tempRowView[columnName] = columnValue; System.Console.WriteLine(tableName+"."+columnName+" = "+columnValue); } } But when I have datagridtablestyle the above code doesn't work. I don't know how to get a DataRowView or similar if I have datagridtablestyle . If I knew how to do this I would give up the arraylist for now. Thomas Quote
RobEmDee Posted January 27, 2005 Posted January 27, 2005 thomas: You can control how the underlying DataTable can be used in the DataGrid through manipulating its DefaultView // Data in DataGrid will automatically be Read-Only dataSet1.Tables["Table1"].DefaultView.AllowEdit = false; // Rows in DataGrid cannot be added (no '*' Row) dataSet1.Tables["Table1"].DefaultView.AllowNew = false; // Rows in DataGrid cannot be deleted dataSet1.Tables["Table1"].DefaultView.AllowDelete = false; You make want to check out ComponentOne grids. They come with all of this functionality and a lot more out of the box. I started using them last year and have never looked back since. Hi I have made a framework where I want to be able to use other controls than a textbox in the grid. ie comboboxes etc. I thought this is the only? way to be able to use other controls. I also do not want the empty insertion row (marked *) which I don't know how to suppress. Thomas Quote
thomas10001 Posted January 28, 2005 Author Posted January 28, 2005 (edited) Hi I were able to get set the keys now and having gridstyles. And my delete and add works fine. Thanks. But I am not able to supress the * row with allowNew = false. Is there something that should be set on the datagrid as well to hide/supress it? Thomas Edited January 28, 2005 by thomas10001 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.