Home - Forums-.NET - FlyGrid.Net (Windows Forms) - Wrong column index in NodeCellChanging event

FlyGrid.Net (Windows Forms)

.NET Datagrid - Fast, highly customizable, industry standards .NET data grid control for WinForms

This forum related to following products: FlyGrid.Net

Wrong column index in NodeCellChanging event
Link Posted: 06-Sep-2006 01:42
I am experiencing wrong FlyGrid behaviour in the following simple test code.

The code assumes that you have created a new empty Form in the VS 2003 project, added a FlyGrid control on it and one Button control.


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

using NineRays.Windows.Forms.Grids;
using NineRays.Windows.Forms;
using NineRays.Windows.Forms.Data;

namespace testFlyGrid
{
  ///
  /// Summary description for Form2.
  ///
  public class Form2 : System.Windows.Forms.Form
  {
    private NineRays.Windows.Forms.FlyGrid flyGrid1;
    private System.Windows.Forms.Button button1;
    ///
    /// Required designer variable.
    ///
    private System.ComponentModel.Container components = null;

    public Form2()
    {
      //
      // Required for Windows Form Designer support
      //
      InitializeComponent();

      //
      // TODO: Add any constructor code after InitializeComponent call
      //
    }

    ///
    /// Clean up any resources being used.
    ///
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if(components != null)
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    #region Windows Form Designer generated code
    ///
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    ///
    private void InitializeComponent()
    {
      this.flyGrid1 = new NineRays.Windows.Forms.FlyGrid();
      this.button1 = new System.Windows.Forms.Button();
      ((System.ComponentModel.ISupportInitialize)(this.flyGrid1)).BeginInit();
      this.SuspendLayout();
      //
      // flyGrid1
      //
      this.flyGrid1.Location = new System.Drawing.Point(136, 40);
      this.flyGrid1.Name = \"flyGrid1\";
      this.flyGrid1.Opacity = 1;
      this.flyGrid1.Size = new System.Drawing.Size(384, 240);
      this.flyGrid1.TabIndex = 0;
      this.flyGrid1.Text = \"flyGrid1\";
      this.flyGrid1.NodeCellChanging += new NineRays.Windows.Forms.NodeCellRefHandler(this.flyGrid1_NodeCellChanging);
      //
      // button1
      //
      this.button1.Location = new System.Drawing.Point(296, 328);
      this.button1.Name = \"button1\";
      this.button1.TabIndex = 1;
      this.button1.Text = \"button1\";
      this.button1.Click += new System.EventHandler(this.button1_Click);
      //
      // Form2
      //
      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
      this.ClientSize = new System.Drawing.Size(640, 413);
      this.Controls.Add(this.button1);
      this.Controls.Add(this.flyGrid1);
      this.Name = \"Form2\";
      this.Text = \"Form2\";
      this.Load += new System.EventHandler(this.Form2_Load);
      ((System.ComponentModel.ISupportInitialize)(this.flyGrid1)).EndInit();
      this.ResumeLayout(false);

    }
    #endregion
Link Posted: 06-Sep-2006 01:44

    private void Form2_Load(object sender, System.EventArgs e)
    {
      flyGrid1.Columns.Items.Add( new Column(\"Column0\") );
      flyGrid1.Columns.Items.Add( new Column(\"Column1\") );
      flyGrid1.Columns.Items.Add( new Column(\"Column2\") );
      flyGrid1.Columns.Items.Add( new Column(\"Column3\") );
      flyGrid1.Columns.Items.Add( new Column(\"Column4\") );

      flyGrid1.Rows.Items.Add(new Node(new object[] { 0, 1, 2, 3, 4 }));
      flyGrid1.Rows.Items.Add(new Node(new object[] { 0, 1, 2, 3, 4 }));
      flyGrid1.Rows.Items.Add(new Node(new object[] { 0, 1, 2, 3, 4 }));
      flyGrid1.Rows.Items.Add(new Node(new object[] { 0, 1, 2, 3, 4 }));
      flyGrid1.Rows.Items.Add(new Node(new object[] { 0, 1, 2, 3, 4 }));
    }

    private bool flyGrid1_NodeCellChanging(object sender, NineRays.Windows.Forms.Data.NodeBase node, int index, ref object value)
    {
      MessageBox.Show(index.ToString());
      return true;
    }

    private void button1_Click(object sender, System.EventArgs e)
    {
      flyGrid1.Rows.Items.Clear();

      int FixedColumnsNumber = 1;
      Column[] toRemove = new Column[flyGrid1.Columns.Items.Count - FixedColumnsNumber];
      for(int i=FixedColumnsNumber; i        toRemove[i-FixedColumnsNumber] = flyGrid1.Columns.Items[i];

      for(int i=0; i        flyGrid1.Columns.Items.Remove(toRemove[i]);

      flyGrid1.Columns.Items.Add( new Column(\"ColumnX\") );
      flyGrid1.Rows.Items.Add(new Node(new object[] { 0, 99 }));
    }
  }
}


Build the project and start the application.
The application form contains 5 columns and several rows. The values in cells could be edited correctly and message box displays correct column index each time the NodeCellChanging event is being fired.
Now click on the button.
There are now only two columns in the grid, the second one contains empty values in its cells, although they were properly provided.
Try to edit empty cells in the ColumnX column.
The message box displays an index value, which is greater then the number of columns in the grid.
The index passed to the NodeCellChanging event should be valid and the column ColumnX must display values correctly.

Could you please fix this issue?
Thank you.

PS: Tested with the last 1.4.0.24 version.
Link Posted: 06-Sep-2006 12:03
This is not a bug, NodeCellChange/NodeCellChanging events provide a visible index of changed column.
To translate this index to the Column object or index in the node cells arrays, use following methods:
1. Columns.GetColumnFromCellIndex
2. Columns.GetColumnFromCellIndex and Columns.FieldMapIndexOf
Link Posted: 06-Sep-2006 21:05
[quote="NineRays"]This is not a bug, NodeCellChange/NodeCellChanging events provide a visible index of changed column.
To translate this index to the Column object or index in the node cells arrays, use following methods:
1. Columns.GetColumnFromCellIndex
2. Columns.GetColumnFromCellIndex and Columns.FieldMapIndexOf


This is obviousely a bug for me so far.
Have you tried to run my example and have you checked the behaviour of Columns.GetColumnFromCellIndex?

GetColumnFromCellIndex returns null in this example:

    private bool flyGrid1_NodeCellChanging(object sender, NineRays.Windows.Forms.Data.NodeBase node, int index, ref object value)
    {
      try
      {
        Column col = flyGrid1.Columns.GetColumnFromCellIndex(index);
        MessageBox.Show(col.Caption);
      }
      catch
      {
        MessageBox.Show("Exception");
      }
      return true;
    }


Actually, the main bug is not the incorrect index passed to the NodeCellChanging event handler but the fact that ColumnX in the example above does not display any data, although they are available.

The reason most probably is that the Columns.Items.Remove() method does not update internal state of the Columns collection properly.
Link Posted: 08-Sep-2006 07:19
I'm sorry for incorrect answer an delivered inconveniences.
Please use Columns.FieldMapColumnFromIndex index in the NodeCellChanging/NodeCellChange event handlers:
[c#]
Column col = flyGrid1.Columns.FieldMapColumnFromIndex(index);
Link Posted: 10-Sep-2006 20:58
[quote="NineRays"]I'm sorry for incorrect answer an delivered inconveniences.
Please use Columns.FieldMapColumnFromIndex index in the NodeCellChanging/NodeCellChange event handlers:
[c#]
Column col = flyGrid1.Columns.FieldMapColumnFromIndex(index);


All right. Using FieldMapColumnFromIndex column is determined well.
To make ColumnX to display values correctly I had to modify the code in the following way:


    private ArrayList GetNewColumnsMap(ColumnCollection columns)
    {
      ArrayList colMap = new ArrayList();
      bool initFieldName = false;
      int i=0;
      foreach(Column column in columns)
      {
        string name;
        if (column.FieldName != null && column.FieldName != string.Empty)
          name = column.FieldName;
        else if (column.Caption != null && column.Caption != string.Empty)
        {
          name = column.Caption;
          initFieldName = true;
        }
        else
        {
          name = i.ToString();
          initFieldName = true;
        }
        colMap.Add(new ColumnFieldTag(column, name));
        i++;
      }
      return colMap;
    }

    private void button1_Click(object sender, System.EventArgs e)
    {
      flyGrid1.BeginInit();
      flyGrid1.Rows.Items.Clear();

      int FixedColumnsNumber = 1;
      Column[] toRemove = new Column[flyGrid1.Columns.Items.Count - FixedColumnsNumber];
      for(int i=FixedColumnsNumber; i        toRemove[i-FixedColumnsNumber] = flyGrid1.Columns.Items[i];

      for(int i=0; i        flyGrid1.Columns.Items.Remove(toRemove[i]);

      flyGrid1.Columns.Items.Add( new Column("ColumnX") );
      flyGrid1.EndInit();

      flyGrid1.Columns.SetColumnMap(GetNewColumnsMap(flyGrid1.Columns.Items));

      flyGrid1.Rows.Items.Add(new Node(new object[] { 0, 99 }));
    }


Code of the GetNewColumnsMap method I have taken from the documentation. It contians some vaguenesses such as
initFieldName is declared and not used. i object is not declared but used. I have modified the code to make it compilable.

Should the Field map be modified automatically on grid Column removal?

Thank you.
Link Posted: 11-Sep-2006 06:45
Thanks for your comments, we'll correct documentation ASAP.

Should the Field map be modified automatically on grid Column removal?

No, field map will refreshed automatically. Field map management functions is necessary for more complex operations, when user need to map fields manually.