public void AjaxRefresh(Control c, int rowIndex, string animationName, string listOperation, bool isTableRecord, object dataItem, StoreViewStateDelegate storeViewStateDelegate, string clientIdOverride)
        {
            // don't do nothing if not in a partial request or if the control is not accessible (e.g.: refreshing widgets inside table records from outside)
            if (!IsAjaxRequest || c == null)
            {
                return;
            }

            // mark that we are refreshing a widget, so that possible queued javascripts happening in the databind are queued
            // to be sent immediately after the control json (for web block preparations or user defined functions execution)
            _isRefreshingWidget = true;

            try {
                LocalState stackBackup = null;
#if JAVA
                HashSet <IAbstractTopLevelComponentWithMandatory> previousVisibleComponentsWithValidation = null,
                                                                  newVisibleComponentsWithValidation      = null;
#endif


                if (c is OSUserControl)
                {
                    OSUserControl blk = (OSUserControl)c;
                    stackBackup = ((IWebScreen)blk.Page).PushStack();
                }
                else
                {
                    stackBackup = ((IWebScreen)c.Page).PushStack();
                }

                if (listOperation == "")
                {
#if JAVA
                    previousVisibleComponentsWithValidation = GetVisibleComponentsWithValidation(c);
#endif

                    // databind the control
                    c.DataBind();

#if JAVA
                    newVisibleComponentsWithValidation = GetVisibleComponentsWithValidation(c);
#endif
                }
                else
                {
                    // some list operation

                    if (!isTableRecord)
                    {
                        // list records require the prerender phase before list append, insert and remove operations, since prerender creates the current child controls hierarchy
                        MethodInfo preRenderRecursiveInternal = typeof(Page).GetMethod("PreRenderRecursiveInternal", BindingFlags.NonPublic | BindingFlags.Instance);
                        preRenderRecursiveInternal.Invoke(c, null);
                    }

                    IListRefresh listWidget = (IListRefresh)c;
                    // execute the list refresh databind to restore LineCount and StartIndex runtime properties in the table / list record
                    listWidget.DoListRefreshDataBind();
                    // execute the operation in the list
                    switch (listOperation)
                    {
                    case "Append":
                        listWidget.AppendItem(dataItem);
                        break;

                    case "Insert":
                        listWidget.InsertItem(rowIndex, dataItem);
                        break;

                    case "Remove":
                        listWidget.RemoveItem(rowIndex);
                        break;

                    case "Refresh":
                        listWidget.RefreshItem(rowIndex);
                        break;

                    default:
                        System.Diagnostics.Debug.Assert(false, "unknown list operation: " + listOperation);
                        break;
                    }
                }

                // call store viewstate in the calling page / block

                storeViewStateDelegate();

                if (stackBackup != null)
                {
                    Debugger.Pop(stackBackup, true);
                }

                // save partial viewstate and get modified buckets

                Hashtable modifiedBuckets = PartialSaveAllState();

                OSJSONResponse resp = CreateJSONResponse();

                // build JSON response with the control rendering and modified buckets

                foreach (string bucketName in modifiedBuckets.Keys)
                {
                    resp.AddToHidden(bucketName, modifiedBuckets[bucketName].ToString());
                }

                string html = "";

                if (listOperation == "")
                {
                    // regular ajax refresh
                    // render control and add it to outers
                    resp.AddToOuter(c.ClientID, RenderControl(c));

#if JAVA
                    ProcessComponentsWithValidationTurnedInvisible(previousVisibleComponentsWithValidation,
                                                                   newVisibleComponentsWithValidation);
#endif
                }
                else
                {
                    // implicit ajax refresh via ListAppend, ListInsert or ListRemove
                    if (listOperation == "Append")
                    {
                        html = RenderAjaxListOperationRow(c);
                    }
                    else if (listOperation == "Insert")
                    {
#if JAVA
                        html = RenderAjaxListOperationRow(c, rowIndex);
#else
                        html = RenderAjaxListOperationRow(c);
#endif
                    }
                    else if (listOperation == "Remove")
                    {
                        // need to render the empty message?
                        if (((IListRefresh)c).IsEmpty)
                        {
                            html = RenderAjaxListOperationRow(c, true);
                        }
                    }
                    else if (listOperation == "Refresh")
                    {
                        // row refresh operation
                        html = RenderAjaxListOperationRow(c, rowIndex);
                    }

                    string oddLineStyle  = "";
                    string evenLineStyle = "";
                    bool   useBullets    = false;

                    if (c is OSDataGrid)
                    {
                        // get table record information to be sent to the client js
                        OSDataGrid dg = (OSDataGrid)c;
                        oddLineStyle  = dg.OddLineStyle ?? oddLineStyle;
                        evenLineStyle = dg.EvenLineStyle ?? evenLineStyle;
                    }
                    else
                    {
                        // get list record information to be sent to the client js
                        Iterator it = (Iterator)c;
                        useBullets = it.UseBullets;
                    }

                    resp.AddToList(clientIdOverride ?? c.ClientID, html, listOperation, rowIndex, isTableRecord, oddLineStyle, evenLineStyle, useBullets);
                }


                // Add call to animation registration
                if (animationName != null && animationName != "None")
                {
                    if (listOperation == "Remove" && animationName == "Highlight")
                    {
                        animationName = "ListRemoveHighlight";
                    }
                    resp.AddToJs("OsRegisterEffect" + animationName.Replace(" ", "") + "();");
                }

                // write and flush the response
                WriteJavascriptResponse(FormatJSONResponseString(resp), /*flush*/ true);

                // send all the queued javascript gathered in this refresh
                if (_javascriptQueueResponse.Js.Count > 0)
                {
                    resp = CreateJSONResponse();
                    resp.AddToJs("outsystems.internal.$(document).ready(function() {" + FormatJSONResponseString(_javascriptQueueResponse) + "});");
                    // clear it for next executions
                    _javascriptQueueResponse.ClearJs();
                    // write the response
                    WriteJavascriptResponse(FormatJSONResponseString(resp), /*flush*/ true);
                }

                // cleanup JavaScript includes so the next refresh will not re-include it
                BlocksJavaScript.CleanupAlreadyIncludedBlocksWithJavaScript();
            } finally {
                // we're no longer refreshing a widget
                _isRefreshingWidget = false;
            }
        }