public Spreadsheet(int rows, int cols)
 {
     m_CellsArray = new Cell[rows, cols];
     dependencies = new Dictionary <string, HashSet <string> >();
     for (int i = 0; i < rows; i++)
     {
         for (int j = 0; j < cols; j++)
         {
             // populate cell array with the number of rows and columns hard coded in the
             // load event
             Cell curCell = new m_Cell(i, j);
             curCell.PropertyChanged += CellPropertyChanged;
             m_CellsArray[i, j]       = curCell;
         }
     }
 }
 // Function that updates all the cells of a circular reference to 0
 // Excel has the feature set up this way, so I decided to mimic this
 // NOTE:
 // It's not extensive. For example, if cell B1 holds A1+A2, and A1 holds a
 // circular reference, then B1 will not be changed. But any cells that have a
 // direct reference (i.e. some cell's value =A1) on A1 will be set to 0
 public void updateCells(string originalCell)
 {
     foreach (var cell in dependencies)
     {
         // we have already editted the text of the cell passed in to "!(Circular Reference)"
         // so we continue to the next item in the dictionary of dependencies
         if (originalCell == cell.Key)
         {
             continue;
         }
         // get the cell based on the key
         m_Cell dependentCell = GetCell(cell.Key) as m_Cell;
         // set value and fire property changed
         dependentCell.setValue("0");
         SSPropertyChanged(dependentCell, new PropertyChangedEventArgs("Value"));
     }
 }
        public void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Text")
            {
                // Create new cell instance and have it as a sender
                m_Cell m_c = sender as m_Cell;

                // free the cell of dependents
                FreeCell(m_c.Name);

                if ((m_c.Text.Length > 1) && (m_c.Text != "") && (m_c.Text[0] == '='))
                {
                    ExpTree exp = new ExpTree(m_c.Text.Substring(1));
                    trackDependents(m_c.Name, exp.GetVarNames());
                }
                EvalCell(sender as Cell);
            }
            else if (e.PropertyName == "BGColor")
            {
                // pass the sender to get the currrent cell in the sheetchanged function in form1
                // fire property changed event for the spreadsheet to color
                SSPropertyChanged(sender, new PropertyChangedEventArgs("BGColor"));
            }
        }
        public void EvalCell(Cell CellArg)
        {
            m_Cell m_c = CellArg as m_Cell;

            if (string.IsNullOrEmpty(m_c.Text))
            {
                m_c.setValue("");
                SSPropertyChanged(CellArg, new PropertyChangedEventArgs("Value"));
            }
            else if (m_c.Text[0] == '=' && m_c.Text.Length > 1)
            {
                bool   flag   = false;
                string expStr = m_c.Text.Substring(1);
                // set the expression string and create the tree
                ExpTree exp = new ExpTree(expStr);

                // gets expression variables
                string[] expVars = exp.GetVarNames();

                // sets each variable in the expression
                foreach (string varName in expVars)
                {
                    // check if the cell is valid
                    if (GetCell(varName) == null)
                    {
                        // set value to the error and fire property changed event for the value
                        m_c.setValue("!(Bad Reference)");
                        SSPropertyChanged(m_c, new PropertyChangedEventArgs("Value"));
                        flag = true;
                        break;
                    }

                    // check to see if its a self reference
                    if (varName == m_c.Name)
                    {
                        // set value to the error and fire property changed event for the value
                        m_c.setValue("!(Self Reference)");
                        SSPropertyChanged(m_c, new PropertyChangedEventArgs("Value"));
                        flag = true;
                        break;
                    }

                    // valid variable
                    SetExpVariable(exp, varName);

                    // check for circular reference after we've determined its a valid reference
                    if (CheckCircularRef(varName, m_c.Name))
                    {
                        // set value to the error and fire property changed event for the value
                        m_c.setValue("!(Circular Reference)");
                        SSPropertyChanged(m_c, new PropertyChangedEventArgs("Value"));
                        updateCells(m_c.Name);
                        flag = true;
                        break;
                    }
                }
                if (flag)
                {
                    return;
                }

                // Sets the expression evaluation to the current cells value and fires the property changed event
                m_c.setValue(exp.Eval().ToString());
                SSPropertyChanged(CellArg, new PropertyChangedEventArgs("Value"));
            }
            else // no equals sign present so change the text
            {
                m_c.setValue(m_c.Text);
                SSPropertyChanged(CellArg, new PropertyChangedEventArgs("Value"));
            }
            if (dependencies.ContainsKey(m_c.Name))
            {
                foreach (string name in dependencies[m_c.Name])
                {
                    EvalCell(name);
                }
            }
        }