I wanted to post it because this would have been such a huge help to us long ago, and I'm hoping it can help someone else.
The Problem:
Our test designs center around being able to update our test iterations during runtime. We store our test iterations in Excel rather than SQL (SQL may make things easier programmtically, but Excel is a much nicer interface to work with from a human perspective, especially for when we need to have manual QAs update test data).
Our test iterations for a particular test can span multiple worksheets in an excel book. For us, a test is its own project and may contain many code modules (we do not use recording at all).
During the course of the test, one or more sheets may need to be updated, and that updated data may need to be referenced in a future iteration using a formulaic reference in Excel.
Here's an example of how it may work (I'm sorry it looks so terrible extra spacing seems to be eliminated and I cannot get table codes to work!):
Columns A B Etc.
Action OrderID Everything else
Row 1 BookOrder OrderID#1 ...
Row2 VerifyOrder =B1 ...
Above is the simplest form of referencing we use. There are other more complex requirements as well, but aren't really necessary for the purpose of this illustration.
There were a few big challenges we ran into, most notably:
1. Had to save the excel sheet to get Ranorex to recognize the data
2. Updating the test data was easy, but the ACTUAL values got recorded and the cell references were lost (so in the example above Column B / Row2 would not be equal to Column B Row 1) - this was the greatest challenge to overcome.
3. Eventually we got Ranorex to recognize the changes to future iterations, but never the current iteration.
4. Updating sheets OTHER than the current bound data sheet would not properly update references.
5. Had to re-write EVERY cell in excel, so updates took a long time (30-60 seconds for large sheets).
Thankfully, we managed to overcome all of these obstacles. Now, updates are instant, you do not have to save the sheet (and we don't want to), Ranorex recognizes the new data immediately, all formulas are preserved no matter what sheet is updated.
To be honest, not having this functionality in Ranorex was a huge hindrance to our workflow and we were in danger of not being able to continue using the product (unfortunate considering how much money we spent

Now that we have our own solution... everything is great (we <3 Ranorex).
I wanted to share the solution with everyone else because I know how painful it was for us to get it working properly and this might be useful to others.
The Solution:
One important requirement is that the machine that is running the test MUST have Excel installed on it. We tried using various references and other interfaces to avoid this requirement, but in ALL cases it simply updated the raw data and formulas were NEVER preserved so that solution was not workable for us.
Something to be aware of:
In your program.cs, you want a finally clause that will kill the excel processes (after properly closing the workbooks), this is important in case ranorex crashes, there are some exceptions or things otherwise terminate abnormally. We use CCNET for our integration and have since updated it to kill excel processes prior to starting tests. If this does not happen, then an errant excel process could continue running and lock the sheet. Once this is set up (which is not hard to do at all), you'll never have a problem.
Additionally, you must have databindings set up properly for your test AND your databinding name must match the excel worksheet to be updated. This is good practice anyway because it keeps things clear.
finally { ExcelInterface.CloseExcelWorkbooks(); OSUtilities.KillProcess("EXCEL"); }For the code itself, I'll just attach the CS file we're using. You will have to make some minor adjustments for it work since we are calling certain classes you won't have (like special exceptions we throw, our own implementation of Reporting) but this is pretty simple. You will probably want to change the namespace as well.
We don't actually call this class directly, we call static methods in another classes. For simplicity I suggest you do the same, but you can use it however you see fit. Below are the methods we call to update the datasheet:
In the below example, all you have to do is call the method and pass the name of the column (defined in the first row of the column) and the new value. We use ignorColumnNotFound for special circumstances, likely you can always leave that false (you can see the parameter is optional).
You can see it calls another method, which I will list after this one...
/// <summary> /// Updates the test data as if it had been updated in Excel directly WITHOUT saving the Excel sheet. Note that all value references/formulas etc. will /// correctly update as well. It will always update the value for the specified column in the current data row. /// </summary> /// <param name="columnToUpdate">The name of the column to update (an exact match is required).</param> /// <param name="updatedValue">The new value.</param> /// <param name="ignoreColumnNotFound">If true, no error will be thrown if the column is not present, otherwise an exception will be thrown</param> /// <remarks>In order for this method to work correctly, your data binding MUST have the same name as the worksheet tab to be updated.</remarks> public static void UpdateActiveTestCaseData(string columnToUpdate, string updatedValue, bool ignoreColumnNotFound = false) { Dictionary<string, string> updateData = new Dictionary<string, string>(); updateData.Add(columnToUpdate, updatedValue); UpdateActiveTestCaseData(updateData, ignoreColumnNotFound); }This one takes a dictionary where the column name is the key, and the value to update is the value. This way you can do one or more updates all at once. You can see it calls another method called getExcelConnectorAndRows which will follow below...
public static void UpdateActiveTestCaseData(Dictionary<string, string> updateColumnsAndValues, bool ignoreColumnNotFound = false) { Ranorex.Core.Data.RowCollection testCollection; Ranorex.Core.Data.ExcelDataConnector connector; getExcelConnectorAndRows(TestCase.Current.DataContext.Source.Connector.Name, out connector, out testCollection); ExcelInterface.PerformExcelUpdate(updateColumnsAndValues, testCollection, connector, TestCase.Current.DataContext.CurrentRowIndex, ignoreColumnNotFound); TestCase.Current.DataContext.ReloadData(); }This method actually gets the excel data from the Ranorex DataCache.
private static void getExcelConnectorAndRows(string connectorName, out Ranorex.Core.Data.ExcelDataConnector connector, out Ranorex.Core.Data.RowCollection testCollection) { DataCache dataSheet = DataSources.Get(connectorName); connector = (Ranorex.Core.Data.ExcelDataConnector)dataSheet.Connector; testCollection = dataSheet.Rows; }Finally, if you want to update a specific sheet - that is, a sheet that does not belong to a test that's currently executing, you can all the following method. Note that the sheet STILL must have a databinding set up AND the sheet name must be the same as the databinding name:
public static void UpdateSpecifiedExcelSheet(string connectorName, Dictionary<string, string> updateColumnsAndValues, int excelRowIndex, bool ignoreColumnNotFound = false) { Ranorex.Core.Data.RowCollection testCollection; Ranorex.Core.Data.ExcelDataConnector connector; const int ROW_OFFSET_FOR_PERFORMEXCELUPDATE = 1; getExcelConnectorAndRows(connectorName, out connector, out testCollection); ExcelInterface.PerformExcelUpdate(updateColumnsAndValues, testCollection, connector, (excelRowIndex - ROW_OFFSET_FOR_PERFORMEXCELUPDATE), ignoreColumnNotFound); TestCase.Current.DataContext.ReloadData(); }So calling these fuctions looks like this if you want to update many cells using a dictionary:
Dictionary<string, string> columnsAndValuesToUpdate = new Dictionary<string, string>(); columnsAndValuesToUpdate.Add(colNameCurrentAvailableBalance, holdingBalances.CurrentAvailableBalance.ToString()); columnsAndValuesToUpdate.Add(colNameCurrentBookBalance, holdingBalances.CurrentBookBalance.ToString()); columnsAndValuesToUpdate.Add(colNameEndingBookBalanceAsof, holdingBalances.EndingBookBalanceAsof.ToString()); TestData.UpdateActiveTestCaseData(columnsAndValuesToUpdate);Or if you just have one cell to update and you don't need a dictionary (this is our most common use):
string confirmationNumber = OrderConfirmation.GetConfirmationNumber(); if (!string.IsNullOrEmpty(confirmationNumber)) { Reporting.ReportSuccess("Order was committed successfully. Confirmation Number is '" + confirmationNumber + "'."); } TestData.UpdateActiveTestCaseData("ConfirmationNumber", confirmationNumber);If you give it a try and find you still cannot get it work, feel free to post back and I'll do my best to help you. This has been tested THOROUGHLY and we use it constantly, so I'm very confident it's working correctly. Thanks so much!
Carson.