// overloaded UpdateCell, takes a cell as the parameter private void UpdateCell(Cell cellToUpdate) { // remove old dependencies RemoveDependencies(cellToUpdate); // first check if the cell is empty // i.e. the user deleted the text from the cell if (string.IsNullOrEmpty(cellToUpdate.Text)) { cellToUpdate.Value = ""; } // if the text doesn't begin with an = else if (cellToUpdate.Text[0] != '=') { double cellValue; // if the cell contains a double if (double.TryParse(cellToUpdate.Text, out cellValue)) { // build the ExpTree to set the cell's variable ExpTree userExpTree = new ExpTree(cellToUpdate.Text); cellValue = userExpTree.Eval(); userExpTree.SetVar(cellToUpdate.Name, cellValue); // update the value to the double cellToUpdate.Value = cellValue.ToString(); } else { // otherwise the value is just set to the text cellToUpdate.Value = cellToUpdate.Text; } } // need to evaluate an expression here else { // parse the text to get the expression string exp = cellToUpdate.Text.Substring(1); // build an ExpTree, eval to add variables ExpTree userExpTree = new ExpTree(exp); userExpTree.Eval(); // get the variable names string[] varNames = userExpTree.GetVarNames(); // loop through each variable name in the array foreach (string variable in varNames) { // get the cell and add its value to the dictionary double value = 0.0; Cell relevantCell = GetCell(variable); // try to parse out the double double.TryParse(relevantCell.Value, out value); // set the variable userExpTree.SetVar(variable, value); } // set the value to the computed value of the ExpTree cellToUpdate.Value = userExpTree.Eval().ToString(); // add the dependencies AddDependencies(cellToUpdate, varNames); } // if there are cells that depend on the one we just updated if (m_dependencies.ContainsKey(cellToUpdate)) { // update all dependent cells UpdateDependencies(cellToUpdate); } // and notify subscribers that the cell property changed // need to pass the sender which is the cell // passing the this reference would pass the spreadsheet CellPropertyChanged(cellToUpdate, new PropertyChangedEventArgs("CellChanged")); }
// overloaded UpdateCell, takes a cell as the parameter private void UpdateCell(Cell cellToUpdate) { // remove old dependencies RemoveDependencies(cellToUpdate); // first check if the cell is empty // i.e. the user deleted the text from the cell if (string.IsNullOrEmpty(cellToUpdate.Text)) { cellToUpdate.Value = ""; } // if the text doesn't begin with an = else if (cellToUpdate.Text[0] != '=') { double cellValue; // if the cell contains a double if (double.TryParse(cellToUpdate.Text, out cellValue)) { // build the ExpTree to set the cell's variable ExpTree userExpTree = new ExpTree(cellToUpdate.Text); cellValue = userExpTree.Eval(); userExpTree.SetVar(cellToUpdate.Name, cellValue); // update the value to the double cellToUpdate.Value = cellValue.ToString(); } else { // otherwise the value is just set to the text cellToUpdate.Value = cellToUpdate.Text; } } // need to evaluate an expression here else { // flag to check for errors bool errors = false; // parse the text to get the expression string exp = cellToUpdate.Text.Substring(1); // build an ExpTree, eval to add variables ExpTree userExpTree = new ExpTree(exp); userExpTree.Eval(); // get the variable names string[] varNames = userExpTree.GetVarNames(); // loop through each variable name in the array foreach (string variable in varNames) { // get the cell and add its value to the dictionary double value = 0.0; Cell relevantCell = GetCell(variable); // check for valid cells // CASE ONE: BAD REFERENCE if (relevantCell == null) { // display that the cell has a bad reference and notify subscribers cellToUpdate.Value = "!(bad reference)"; CellPropertyChanged(cellToUpdate, new PropertyChangedEventArgs("CellChanged")); // set the error flag to true errors = true; } // CASE TWO: SELF-REFERENCE else if (cellToUpdate.Name == variable) { // display that the cell has a self-reference and notify subscribers cellToUpdate.Value = "!(self reference)"; CellPropertyChanged(cellToUpdate, new PropertyChangedEventArgs("CellChanged")); // set the error flag to true errors = true; } // if there's an error, get out of the function if (errors == true) { // if there are cells that depend on the one we just updated if (m_dependencies.ContainsKey(cellToUpdate)) { // update all dependent cells UpdateDependencies(cellToUpdate); } return; } // try to parse out the double double.TryParse(relevantCell.Value, out value); // set the variable userExpTree.SetVar(variable, value); // add the cell to the HashSet to check for circular references this.visitedCells.Add(relevantCell); } // set the value to the computed value of the ExpTree cellToUpdate.Value = userExpTree.Eval().ToString(); // add the dependencies AddDependencies(cellToUpdate, varNames); // check for circular references if (CheckForCircularReferences(cellToUpdate)) { // display that the cell has a circular-reference and notify subscribers cellToUpdate.Value = "!(circular reference)"; CellPropertyChanged(cellToUpdate, new PropertyChangedEventArgs("CellChanged")); // set the error flag to true errors = true; } // if there's an error, get out of the function if (errors == true) { return; } } // if there are cells that depend on the one we just updated if (m_dependencies.ContainsKey(cellToUpdate)) { // update all dependent cells UpdateDependencies(cellToUpdate); } // and notify subscribers that the cell property changed // need to pass the sender which is the cell // passing the this reference would pass the spreadsheet CellPropertyChanged(cellToUpdate, new PropertyChangedEventArgs("CellChanged")); // clear the visited cells HashSet at a successful cell change this.visitedCells.Clear(); }