Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

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:

Posted

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

}

Posted

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

Posted (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 by RobEmDee
Posted
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()

Posted
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?!

Posted

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

Posted
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.

Posted

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","");

Posted

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.

Posted

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

Posted

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

Posted

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

Posted (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 by thomas10001

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...