private void AddDataTableEventHandlers(DataTable dataTable) { dataTable.ColumnChanging += (object sender, DataColumnChangeEventArgs e) => { if (!mIsLoading && !mIsApplyingChanges) { DataCell cell = new DataCell(e.Column, (RecipeRow)e.Row); MultipleCellChange change = new MultipleCellChange(cell, e.Row[e.Column], e.ProposedValue); mUndoStack.Push(change); } }; dataTable.ColumnChanged += (object sender, DataColumnChangeEventArgs e) => { RecipeRow row = (RecipeRow)e.Row; DataColumn column = e.Column; mDataTable.GetColumnBehavior(column).OnDataCellChanged(e); if (!mIsLoading) { unsavedFilesLabel.Visible = true; mModifiedCells.Add(new DataCell(column, row)); } }; }
private void ApplyCellChanges(Stack <MultipleCellChange> fromStack, Stack <MultipleCellChange> toStack, Action <MultipleCellChange> doChange) { if (fromStack.Any()) { MultipleCellChange changes = fromStack.Pop(); mIsApplyingChanges = true; doChange(changes); mIsApplyingChanges = false; toStack.Push(changes); // Hide unsaved indicator if we have undone/redone to the current state of the files if (currentStateUndoIndex == mUndoStack.Count()) { unsavedFilesLabel.Visible = false; mModifiedCells.Clear(); } } }
private bool SetGridValue(int colIndex, int rowIndex, string value, MultipleCellChange changes) { try { DataGridViewColumn column = recipesGridView.Columns[colIndex]; if (column is DataGridViewComboBoxColumn) { List <string> autoCompleteStrings = (column as DataGridViewComboBoxColumn).DataSource as List <string>; if (!autoCompleteStrings.Contains(value)) { MessageBox.Show(string.Format("Value \"{0}\" not found in combobox for column \"{1}\"", value, column.Name)); return(false); } } else if (column.ReadOnly) { MessageBox.Show(string.Format("Trying to write to read-only column {0}", column.Name)); return(false); } object oldValue = mDataTable.GetRow(rowIndex)[colIndex]; if (string.IsNullOrEmpty(value)) { mDataTable.GetRow(rowIndex)[colIndex] = DBNull.Value; } else { mDataTable.GetRow(rowIndex)[colIndex] = value; } DataCell cell = new DataCell(mDataTable.Columns[colIndex], mDataTable.GetRow(rowIndex)); changes.Add(new CellChange(cell, oldValue, value)); } catch (Exception exception) { MessageBox.Show(string.Format("Unable to set grid value for ({0}, {1}). Error: {2}", colIndex, rowIndex, exception.Message)); return(false); } return(true); }
private void recipesGridView_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { if (!recipesGridView.IsCurrentCellInEditMode) { recipesGridView.BeginEdit(true); e.Handled = true; } } else if (e.Control && e.KeyCode == Keys.S) { // Save on ctrl+s SaveModifiedFiles(); } else if ((e.Control && e.Shift && e.KeyCode == Keys.Z) || (e.Control && e.KeyCode == Keys.Y)) { // Redo on ctrl+shift+z or ctrl+y ApplyCellChanges(mRedoStack, mUndoStack, changes => changes.Redo()); } else if (e.Control && e.KeyCode == Keys.Z) { // Undo on ctrl+z ApplyCellChanges(mUndoStack, mRedoStack, changes => changes.Undo()); } else if (e.KeyCode == Keys.Delete) { if (recipesGridView.SelectedCells.Count == 0) { return; } else if (recipesGridView.SelectedCells.Count == 1) { // Delete current cell on del if only one selected DeleteCurrentCell(); } else { // Delete multiple cells // Add cell changes to one transaction so we can roll back if needed mIsApplyingChanges = true; MultipleCellChange changes = new MultipleCellChange(); foreach (DataGridViewCell cell in recipesGridView.SelectedCells) { DataColumn dataColumn = mDataTable.GetColumn(cell.ColumnIndex); RecipeRow recipeRow = mDataTable.GetRow(cell.RowIndex); object oldValue = recipeRow[dataColumn]; object newValue = DBNull.Value; bool success = mDataTable.GetColumnBehavior(dataColumn).TryDeleteCell(recipeRow); if (!success) { changes.Undo(); return; } DataCell dataCell = new DataCell(dataColumn, recipeRow); changes.Add(new CellChange(dataCell, oldValue, newValue)); } // Save cell changes made in this delete operation mUndoStack.Push(changes); mIsApplyingChanges = false; } } else if (e.Control && e.KeyCode == Keys.V) { // Paste multiple cells on ctrl+v if (recipesGridView.SelectedCells.Count == 0) { return; } // Add cell changes to one transaction so we can roll back if needed mIsApplyingChanges = true; MultipleCellChange changes = new MultipleCellChange(); Tuple <DataGridViewCell, DataGridViewCell> boundaryCells = GetSelectedCellsBoundaries(); DataGridViewCell startCell = boundaryCells.Item1; DataGridViewCell endCell = boundaryCells.Item2; int startRow = startCell.RowIndex; int startCol = startCell.ColumnIndex; int rowIndex = startRow; string s = Clipboard.GetText(); string[] lines = s.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.None); int lineIndex = 0; while (lineIndex < lines.Count()) { string line = lines[lineIndex]; if (rowIndex < recipesGridView.Rows.Count) { string[] cells = line.Split('\t'); int colIndex = startCol; for (int i = 0; i < cells.Length && colIndex < recipesGridView.Columns.Count; i++) { bool success = SetGridValue(colIndex, rowIndex, cells[i], changes); if (!success) { changes.Undo(); return; } colIndex++; } rowIndex++; } lineIndex++; // Repeat last line in clipboard if we've copied one line and the selected rows exceeds one line if (lineIndex == lines.Count() && lines.Count() == 1) { int selectedRowCount = Math.Abs(startCell.RowIndex - endCell.RowIndex) + 1; int clipboardRowCount = Math.Abs((rowIndex - 1) - startRow) + 1; if (selectedRowCount > clipboardRowCount) { lineIndex--; } } } // Save cell changes made in this paste operation mUndoStack.Push(changes); mIsApplyingChanges = false; } }