Hi.
I need to detect when the content of a spreadsheet cell has changed.
I'm able to find out a cell was changed by a user interaction, by hooking to the EditModeExited event.
But I have been unable to find a way to detect when the cell content is changed programmatically, e.g. by an Undo command.
Is there any features what would allow me to do this?
Thank you.
Best regards,
Raul
Hello Raul,
Thank you for posting in our forums!
You can handle the UltraSpreadSheet's PerformingAction event (or PerformedAction if you need to know after the action has occurred). These events fire when indirect user interactions occur, like with Undo.
For example, you can use this code:
private void Spreadsheet1_PerformingAction(object sender, SpreadsheetPerformingActionEventArgs e) { UltraSpreadsheetAction action = e.Command; if (action == UltraSpreadsheetAction.Undo) MessageBox.Show("Undo", "Action Occurred"); }
There are many actions available to handle if you need them. If you have any further questions or concerns with this, please let me know and I will be glad to help.
Hello Michael,
I try to clarify:
I don't need to be notified that an undo command has been issued per se.
I need to know which cell values have been changed by the undo command.
In general, I need to know when the value of one or more cells have changed, so that I can retrieve the updated values and use them to set another control on screen.
As I said, this can be accomplished when the user changes a cell e.g. by typing a new value, but not when the value of a cell changes because of an undo command.
Thank you
Regards
It appears that we have been discussing this same issue in a private support case with an ID of CAS-199372-F3K3V3, which I have very recently answered. Below is a transcript of the recent answer:
I agree that it is unfortunate that there does not exist an event that signifies that a cell has changed. I have been investigating into this a bit further, and I have a couple of recommendations that may help you to achieve your requirement.
The first recommendation is to use the UltraSpreadsheet.ActiveCell method in the PerformedAction method after a BeginInvoke Action. The Undo action will change the ActiveCell in the UltraSpreadsheet, but at the point that the PerformedAction event fires, it is slightly too early to access it. The BeginInvoke Action will help you to do this. The code for this could look like the following:
private void UltraSpreadsheet1_PerformedAction(object sender, Infragistics.Win.UltraWinSpreadsheet.SpreadsheetPerformedActionEventArgs e){ if (e.Command == UltraSpreadsheetAction.Undo) { BeginInvoke(new Action(() => { SpreadsheetCell cell = (SpreadsheetCell)ultraSpreadsheet1.ActiveCell; })); }}
As for UI “editing” changes, I would recommend continuing with the EditModeExited event, as the event arguments of this event can net you the cell that was edited. Programmatic changes can be retrieved in application code, as you should know which cells you are changing when doing this programmatically.
Another option that I had thought of was to keep track of the cells that were edited by using the UndoManager of the UltraSpreadsheet. Inside, you will find information about what is the next queued Undo action or Redo action with information about which cell will be affected by using the UndoHistory or RedoHistory collections, respectively. You can also create your own editing history from the EditModeExited event, if you would like.
I hope this helps. Please let me know if you have any other questions or concerns on this matter.
Hi Andrew,
and thanks for your kind reply.
I'd like to share some thoughts on you suggestions.
The first method is doable when the undo operations affects just one cell. If you are undoing a multicell paste operatiion (for example), you get only one of the restored cell as the active cell.
The second method covers editing and programmatical changes, and those pose no problem.
As for the third method, I tried to work along the lines you suggested, but the useful fields in the undo classes are marked as internal, so I first devised a workable solution using the info they store by examing them in the debugger, only to find out that it can't be done in code.
So, I'm stuck.
The Spreadsheet control is powerful, and I have been able to build a nice editor around it, but it sorely lacks some vital features, in my opinion.
Best,
Thank you for your update. I hope that this method will help you, and I will continue to monitor this forum thread in case you have further questions or concerns.
Hi, Andrew.
The reflection method you mentioned looka promising, and I'm going to give it a try.
I'll let you know if I succeded in making it work.
I have been looking a bit further into a solution to the first and third requirements that you have mentioned. Regarding the first, if the undo (or redo) is of a multi-cell paste operation, you can instead use the UltraSpreadsheet.ActiveSelection property. This will return a SpreadsheetSelection object that has a CellRanges and CellRangesAddress property that can help you to determine what was selected.
Regarding the third point, I have been investigating into this a bit further, and you are correct, it does appear that a good majority of the types needed to usefully interact with the UndoManager and UndoHistory collection are internal. Still, you could use reflection to interact with this and get the SpreadsheetCellRange to be affected by the next undo operation. You could do this with the following code-snippet:
var x = ultraSpreadsheet1.UndoManager.UndoHistory[0]; //This will get the next undo action to happen. UndoHistoryItem item = x as UndoHistoryItem; var unit = item.Unit; FieldInfo info = unit.GetType().GetField("AffectedRanges", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); Array range = (Array)info.GetValue(unit); for (int i = 0; i < range.Length; i++) { SpreadsheetCellRange cellRange = (SpreadsheetCellRange)range.GetValue(i); }