/// <summary> /// Will read a text's formula and then subscribe to all the referenced cell's in the formula. /// </summary> /// <param name="cell">Cell that uses other cells.</param> private void SubscribeCellDependency(SpreadsheetCellValue cell) { if (cell.Text == string.Empty || !cell.Text.StartsWith("=") || cell.Value == "!(bad reference)" || cell.Value == "!(self reference)" || cell.Value == "!(circular reference)") { return; // Subscribe to nothing if the cell text is empty. } string cellText = cell.Text.Substring(1, cell.Text.Length - 1); string[] words = cellText.Split('+', '-', '/', '*', '(', ')'); // Splits all the variables and constants. int lengthLoop = words.Length; for (int i = 0; i < lengthLoop; i++) { if (CheckIfLetter(words[i])) { string cellCoordinate = words[i].ToUpper(); // Set the A1,B1... to a string variable char letter = cellCoordinate[0]; int rowIndex = Convert.ToInt32(letter) - 65; string numCol = cellCoordinate.Substring(1, cellCoordinate.Length - 1); int colIndex = Convert.ToInt32(numCol) - 1; cell.SubscribeToCell(ref this.cellGrid[colIndex, rowIndex]); // Subscribe to Dependency Changed Event. } } }
/// <summary> /// Initializes a new instance of the <see cref="Spreadsheet"/> class. /// </summary> /// <param name="numRows">Set number of rows in spreadsheet.</param> /// <param name="numColumns">Set number of columns in spreadsheet.</param> public Spreadsheet(int numRows, int numColumns) { this.rowCount = numRows; this.columnCount = numColumns; this.cellGrid = new SpreadsheetCellValue[numRows, numColumns]; for (int i = 0; i < numRows; i++) { for (int j = 0; j < numColumns; j++) { SpreadsheetCellValue newCell = SpreadsheetCellValue.CreateCell(i, j); this.cellGrid[i, j] = newCell; this.cellGrid[i, j].PropertyChanged += this.SpreadsheetCellValue_PropertyChanged; } } }
/// <summary> /// This will identify the text of a cell and depending if the text string starts with "=" will update the value of the cell. /// If the string starts with "=" this will set the value of the cell to equal another cell's value. Otherwise, the value /// will be set equal to the text. /// </summary> /// <param name="sender.">Spreadsheet.</param> /// <param name="e">Cell argument.</param> private void SpreadsheetCellValue_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { SpreadsheetCellValue cell = (SpreadsheetCellValue)sender; string evalutedText = cell.Text.ToUpper(); char columnCharacter = Convert.ToChar(cell.ColumnIndex + 65); string cellName = columnCharacter.ToString().ToUpper() + (cell.RowIndex + 1).ToString(); // Converts cell location to a cellName try { this.cellDependencies[cellName] = CreateCellVariableList(evalutedText); // Add cell variables to cellName list. } catch { } if (e.PropertyName == "Text") { if (CheckText(evalutedText)) { if (CheckBadReference(evalutedText)) { cell.Value = "!(bad reference)"; } else if (CheckSelfReference(evalutedText, cellName)) { cell.Value = "!(self reference)"; } else if (this.CheckCircleReference(cellName, cellName)) { cell.Value = "!(circular reference)"; } else { string newValue = this.EvaluateText(evalutedText); this.expressionTree.SetVariable(cellName, Convert.ToDouble(newValue)); // This is assuming that the user inputs the formula without errors and adds the cell value to the dictionary cell.Value = newValue; // Evaluates the cell text if it starts with "=" and returns the double as a string } } else { string cellValue = cell.Text; double number; if (double.TryParse(cellValue, out number)) { this.expressionTree.SetVariable(cellName, number); // If cell value can be parsed to double, set cellName, double } else { this.expressionTree.SetVariable(cellName, 0); // If cell value cannot be parsed to double, set cellName, 0 (default) } cell.Value = cell.Text; // If the string does not start with "=" then the string value will be set to the text of the cell. } this.SubscribeCellDependency(cell); this.PropertyChangedValue(sender, new PropertyChangedEventArgs("Value")); } else if (e.PropertyName == "BGColor") { this.PropertyChangedValue(sender, new PropertyChangedEventArgs("BGColor")); // Fire off property changed event for color. } }
/// <summary> /// This function will allow the cell to subscribe to a referenced cell dependency. /// </summary> /// <param name="cell">Refereneced cell that this.cell will subscribe to.</param> public void SubscribeToCell(ref SpreadsheetCellValue cell) { cell.DependencyChanged += this.SpreadsheetCellValue_DependencyChanged; }