/// <summary>
        /// Handles the DoWorker event for the worker
        /// </summary>
        /// <param name="sender">Object that fired the event</param>
        /// <param name="e">.NET supplied event parameters</param>
        protected override void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            lock (syncLock)
            {
                Dictionary<string, string> inputVariableList = ((GadgetParameters)e.Argument).InputVariableList;

                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToProcessingState));
                this.Dispatcher.BeginInvoke(new SimpleCallback(ClearResults));

                AddOutputGridDelegate addGrid = new AddOutputGridDelegate(AddLineListGrid);
                SetGridTextDelegate setText = new SetGridTextDelegate(SetGridText);
                SetGridImageDelegate setImage = new SetGridImageDelegate(SetGridImage);
                AddGridRowDelegate addRow = new AddGridRowDelegate(AddGridRow);
                RenderFrequencyHeaderDelegate renderHeader = new RenderFrequencyHeaderDelegate(RenderFrequencyHeader);
                DrawFrequencyBordersDelegate drawBorders = new DrawFrequencyBordersDelegate(DrawFrequencyBorders);

                Configuration config = DashboardHelper.Config;
                string yesValue = config.Settings.RepresentationOfYes;
                string noValue = config.Settings.RepresentationOfNo;

                string groupVar = string.Empty;
                int maxRows = 50;
                bool exceededMaxRows = false;
                bool exceededMaxColumns = false;
                bool showLineColumn = true;
                bool showColumnHeadings = true;
                bool showNullLabels = true;

                if (GadgetOptions.StrataVariableNames.Count > 0)
                {
                    groupVar = GadgetOptions.StrataVariableNames[0];
                }

                if (inputVariableList.ContainsKey("maxcolumns"))
                {
                    maxColumns = int.Parse(inputVariableList["maxcolumns"]);
                }

                if (inputVariableList.ContainsKey("maxrows"))
                {
                    maxRows = int.Parse(inputVariableList["maxrows"]);
                }

                if (inputVariableList.ContainsKey("showcolumnheadings"))
                {
                    showColumnHeadings = bool.Parse(inputVariableList["showcolumnheadings"]);
                }

                if (inputVariableList.ContainsKey("showlinecolumn"))
                {
                    showLineColumn = bool.Parse(inputVariableList["showlinecolumn"]);
                }

                if (inputVariableList.ContainsKey("shownulllabels"))
                {
                    showNullLabels = bool.Parse(inputVariableList["shownulllabels"]);
                }

                //System.Threading.Thread.Sleep(4000); // Artifically inflating process time to see how the 'loading' screen looks. TODO: REMOVE LATER

                if (IsHostedByEnter)
                {
                    if (System.Windows.SystemParameters.IsSlowMachine == true)
                    {
                        maxColumns = 512;
                    }
                    else
                    {
                        maxColumns = 1024;
                    }
                }
                else
                {
                    int renderingTier = (RenderCapability.Tier >> 16);
                    if (renderingTier >= 2)
                    {
                        maxColumns = 128;
                    }
                    else if (renderingTier >= 1)
                    {
                        maxColumns = 64;
                    }
                    else
                    {
                        maxColumns = 24;
                    }

                    if (System.Windows.SystemParameters.IsSlowMachine == true)
                    {
                        maxColumns = 24;
                    }
                }

                List<string> stratas = new List<string>();
                if (!string.IsNullOrEmpty(groupVar))
                {
                    stratas.Add(groupVar);
                }

                try
                {
                    GadgetOptions.GadgetStatusUpdate += new GadgetStatusUpdateHandler(requestUpdateStatus);
                    GadgetOptions.GadgetCheckForCancellation += new GadgetCheckForCancellationHandler(checkForCancellation);
                    if (this.DataFilters != null)
                    {
                        GadgetOptions.CustomFilter = this.DataFilters.GenerateDataFilterString(false);
                    }
                    else
                    {
                        GadgetOptions.CustomFilter = string.Empty;
                    }

                    List<DataTable> lineListTables = DashboardHelper.GenerateLineList(GadgetOptions);

                    if (lineListTables == null || lineListTables.Count == 0)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithErrorDelegate(RenderFinishWithError), SharedStrings.NO_RECORDS_SELECTED);
                        this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                        Debug.Print("Line list thread cancelled");
                        return;
                    }
                    else if (lineListTables.Count == 1 && lineListTables[0].Rows.Count == 0)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithErrorDelegate(RenderFinishWithError), SharedStrings.NO_RECORDS_SELECTED);
                        this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                        Debug.Print("Line list thread cancelled");
                        return;
                    }
                    else if (worker.CancellationPending)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithErrorDelegate(RenderFinishWithError), SharedStrings.DASHBOARD_GADGET_STATUS_OPERATION_CANCELLED);
                        this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                        Debug.Print("Line list thread cancelled");
                        return;
                    }
                    else
                    {
                        string formatString = string.Empty;

                        foreach (DataTable listTable in lineListTables)
                        {
                            string strataValue = listTable.TableName;
                            if (listTable.Rows.Count == 0)
                            {
                                continue;
                            }
                            this.Dispatcher.BeginInvoke(addGrid, groupVar, listTable.TableName, listTable.Columns.Count);
                        }

                        SetGadgetStatusMessage(SharedStrings.DASHBOARD_GADGET_STATUS_DISPLAYING_OUTPUT);

                        foreach (DataTable listTable in lineListTables)
                        {
                            string strataValue = listTable.TableName;
                            if (listTable.Rows.Count == 0)
                            {
                                continue;
                            }
                            string tableHeading = listTable.TableName;

                            if (lineListTables.Count > 1)
                            {
                                //tableHeading = freqVar; ???
                            }

                            SetCustomColumnSort(listTable);

                            this.Dispatcher.BeginInvoke(renderHeader, strataValue, tableHeading, listTable.Columns);

                            rowCount = 1;

                            if (listTable.Columns.Count == 0)
                            {
                                throw new ApplicationException("There are no columns to display in this list. If specifying a group variable, ensure the group variable contains data fields.");
                            }

                            int[] totals = new int[listTable.Columns.Count - 1];
                            columnCount = 1;

                            foreach (System.Data.DataRow row in listTable.Rows)
                            {
                                this.Dispatcher.Invoke(addRow, strataValue, -1);
                                this.Dispatcher.BeginInvoke(setText, strataValue, new TextBlockConfig(rowCount.ToString(), new Thickness(4, 0, 4, 0), VerticalAlignment.Center, HorizontalAlignment.Stretch, TextAlignment.Center, rowCount, 0, Visibility.Visible), FontWeights.Normal);
                                columnCount = 1;

                                foreach (DataColumn column in listTable.Columns)
                                {
                                    if (columnCount > maxColumns + 1)
                                    {
                                        exceededMaxColumns = true;
                                        break;
                                    }

                                    string displayValue = row[column.ColumnName].ToString();

                                    if (DashboardHelper.IsUserDefinedColumn(column.ColumnName))
                                    {
                                        displayValue = DashboardHelper.GetFormattedOutput(column.ColumnName, row[column.ColumnName]);
                                    }
                                    else
                                    {
                                        Field field = null;
                                        string columnType = string.Empty;

                                        foreach (DataRow fieldRow in DashboardHelper.FieldTable.Rows)
                                        {
                                            if (fieldRow["columnname"].Equals(column.ColumnName))
                                            {
                                                columnType = fieldRow["datatype"].ToString();
                                                if (fieldRow["epifieldtype"] is Field)
                                                {
                                                    field = fieldRow["epifieldtype"] as Field;
                                                }
                                                break;
                                            }
                                        }

                                        if ((field != null && (field is YesNoField || field is CheckBoxField)) || column.DataType.ToString().Equals("System.Boolean"))
                                        {
                                            if (row[column.ColumnName].ToString().Equals("1") || row[column.ColumnName].ToString().ToLower().Equals("true"))
                                                displayValue = yesValue;
                                            else if (row[column.ColumnName].ToString().Equals("0") || row[column.ColumnName].ToString().ToLower().Equals("false"))
                                                displayValue = noValue;
                                        }
                                        else if ((field != null && field is DateField) || (!DashboardHelper.DateColumnRequiresTime(listTable, listTable.Columns[column.ColumnName].ColumnName)))
                                        {
                                            displayValue = string.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:d}", row[column.ColumnName]);
                                        }
                                        else if (field != null && field is TimeField)
                                        {
                                            displayValue = string.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:T}", row[column.ColumnName]);
                                        }
                                        else
                                        {
                                            displayValue = DashboardHelper.GetFormattedOutput(column.ColumnName, row[column.ColumnName]);
                                        }
                                    }

                                    if (string.IsNullOrEmpty(displayValue))
                                    {
                                        if (showNullLabels)
                                        {
                                            displayValue = config.Settings.RepresentationOfMissing;
                                        }
                                        else
                                        {
                                            displayValue = string.Empty;
                                        }
                                    }

                                    if (column.DataType.ToString().Equals("System.DateTime") || column.DataType.ToString().Equals("System.Int32") || column.DataType.ToString().Equals("System.Double") || column.DataType.ToString().Equals("System.Single"))
                                    {
                                        if (column.ColumnName.Equals("UniqueKey"))
                                        {
                                            this.Dispatcher.BeginInvoke(setText, strataValue, new TextBlockConfig(displayValue, new Thickness(8, 6, 8, 6), VerticalAlignment.Stretch, HorizontalAlignment.Stretch, TextAlignment.Right, rowCount, columnCount, Visibility.Collapsed), FontWeights.Normal);
                                        }
                                        else
                                        {
                                            this.Dispatcher.BeginInvoke(setText, strataValue, new TextBlockConfig(displayValue, new Thickness(8, 6, 8, 6), VerticalAlignment.Stretch, HorizontalAlignment.Stretch, TextAlignment.Right, rowCount, columnCount, Visibility.Visible), FontWeights.Normal);
                                        }
                                    }
                                    else if (column.DataType == typeof(byte[]) && displayValue != config.Settings.RepresentationOfMissing && IsHostedByEnter)
                                    {
                                        this.Dispatcher.BeginInvoke(setImage, strataValue, (byte[])row[column.ColumnName], new TextBlockConfig(displayValue, new Thickness(8, 6, 8, 6), VerticalAlignment.Stretch, HorizontalAlignment.Stretch, TextAlignment.Left, rowCount, columnCount, Visibility.Visible), FontWeights.Normal);
                                    }
                                    else
                                    {
                                        this.Dispatcher.BeginInvoke(setText, strataValue, new TextBlockConfig(displayValue, new Thickness(8, 6, 8, 6), VerticalAlignment.Stretch, HorizontalAlignment.Stretch, TextAlignment.Left, rowCount, columnCount, Visibility.Visible), FontWeights.Normal);
                                    }
                                    columnCount++;
                                }

                                rowCount++;

                                if (rowCount > maxRows)
                                {
                                    break;
                                }
                            }

                            this.Dispatcher.BeginInvoke(drawBorders, strataValue);

                            if (rowCount > maxRows)
                            {
                                exceededMaxRows = true;
                            }
                        }

                        for(int i = 0; i < lineListTables.Count; i++)
                        {
                            lineListTables[i].Dispose();
                        }
                        lineListTables.Clear();
                    }

                    if (exceededMaxRows && exceededMaxColumns)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithWarningDelegate(RenderFinishWithWarning), "Warning: Some rows and columns were not displayed due to gadget settings. Showing top " + maxRows.ToString() + " rows and top " + maxColumns.ToString() + " columns only.");
                    }
                    else if (exceededMaxColumns)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithWarningDelegate(RenderFinishWithWarning), "Warning: Some columns were not displayed due to gadget settings. Showing top " + maxColumns.ToString() + " columns only.");
                    }
                    else if (exceededMaxRows)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithWarningDelegate(RenderFinishWithWarning), string.Format(SharedStrings.DASHBOARD_GADGET_STATUS_ROW_LIMIT, maxRows.ToString()));
                    }
                    else
                    {
                        this.Dispatcher.BeginInvoke(new SimpleCallback(RenderFinish));
                    }
                    // Now called after drawing all the borders.
                    // this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                }
                catch (Exception ex)
                {
                    this.Dispatcher.BeginInvoke(new RenderFinishWithErrorDelegate(RenderFinishWithError), ex.Message);
                    this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                }
                finally
                {
                    stopwatch.Stop();
                    Debug.Print("Line list gadget took " + stopwatch.Elapsed.ToString() + " seconds to complete with " + DashboardHelper.RecordCount.ToString() + " records and the following filters:");
                    Debug.Print(DashboardHelper.DataFilters.GenerateDataFilterString());
                }
            }
        }
        /// <summary>
        /// Handles the DoWorker event for the worker
        /// </summary>
        /// <param name="sender">Object that fired the event</param>
        /// <param name="e">.NET supplied event parameters</param>
        private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            lock (syncLock)
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToProcessingState));
                this.Dispatcher.BeginInvoke(new SimpleCallback(ClearResults));

                AddLineListGridDelegate addGrid = new AddLineListGridDelegate(AddLineListGrid);
                SetGridTextDelegate setText = new SetGridTextDelegate(SetGridText);
                SetGridImageDelegate setImage = new SetGridImageDelegate(SetGridImage);
                AddGridRowDelegate addRow = new AddGridRowDelegate(AddGridRow);
                RenderFrequencyHeaderDelegate renderHeader = new RenderFrequencyHeaderDelegate(RenderFrequencyHeader);
                DrawFrequencyBordersDelegate drawBorders = new DrawFrequencyBordersDelegate(DrawFrequencyBorders);

                Configuration config = dashboardHelper.Config;
                string yesValue = config.Settings.RepresentationOfYes;
                string noValue = config.Settings.RepresentationOfNo;

                try
                {
                    DataTable dictionaryTable = dashboardHelper.FieldTable.Copy();

                    foreach (KeyValuePair<string, string> kvp in dashboardHelper.TableColumnNames)
                    {
                        DataRow row = dictionaryTable.Rows.Find(kvp.Key);
                        if(row == null)
                        {
                            dictionaryTable.Rows.Add(kvp.Key, kvp.Value);
                        }
                    }

                    if (dashboardHelper.IsUsingEpiProject)
                    {
                        dictionaryTable.Columns.Add("Page", typeof(int));
                        dictionaryTable.Columns.Add("Tab", typeof(int));
                        dictionaryTable.Columns.Add("Prompt", typeof(string));
                        dictionaryTable.Columns.Add("Items", typeof(string));

                        foreach (DataRow fieldRow in dictionaryTable.Rows)
                        {
                            if (fieldRow["epifieldtype"] is RenderableField)
                            {
                                RenderableField renderableField = fieldRow["epifieldtype"] as RenderableField;
                                fieldRow["Page"] = renderableField.Page.Position + 1;
                                fieldRow["Tab"] = renderableField.TabIndex;
                                fieldRow["Prompt"] = renderableField.PromptText;
                                if (renderableField is GroupField)
                                {
                                    GroupField groupField = renderableField as GroupField;
                                    fieldRow["Items"] = groupField.ChildFieldNames;
                                }
                                else if (renderableField is OptionField)
                                {
                                    OptionField optionField = renderableField as OptionField;
                                    fieldRow["Items"] = optionField.GetOptionsString();
                                }
                            }
                        }

                        dictionaryTable.Columns["columnname"].SetOrdinal(0);
                        dictionaryTable.Columns["Prompt"].SetOrdinal(1);
                        dictionaryTable.Columns["formname"].SetOrdinal(2);
                        dictionaryTable.Columns["Page"].SetOrdinal(3);
                        dictionaryTable.Columns["Tab"].SetOrdinal(4);
                        dictionaryTable.Columns["datatype"].SetOrdinal(5);
                        dictionaryTable.Columns["epifieldtype"].SetOrdinal(6);
                        dictionaryTable.Columns["tablename"].SetOrdinal(7);
                        dictionaryTable.Columns["Items"].SetOrdinal(8);
                    }

                    if (dictionaryTable == null || dictionaryTable.Rows.Count == 0)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithErrorDelegate(RenderFinishWithError), "There are no valid fields to display.");
                    }
                    else if (worker.CancellationPending)
                    {
                        this.Dispatcher.BeginInvoke(new RenderFinishWithErrorDelegate(RenderFinishWithError), SharedStrings.DASHBOARD_GADGET_STATUS_OPERATION_CANCELLED);
                        this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                        Debug.Print("Data dictionary thread cancelled");
                        return;
                    }
                    else
                    {
                        this.Dispatcher.BeginInvoke(addGrid, "", "", dictionaryTable.Columns.Count);
                        string formatString = string.Empty;
                        this.Dispatcher.BeginInvoke(renderHeader, "", "", dictionaryTable.Columns);

                        int rowCount = 1;
                        int columnCount = 1;

                        foreach (System.Data.DataRow row in dictionaryTable.Rows)
                        {
                            bool isGroup = false;

                            this.Dispatcher.Invoke(addRow, "", 30);
                            this.Dispatcher.BeginInvoke(setText, "", new TextBlockConfig(StringLiterals.SPACE + rowCount.ToString() + StringLiterals.SPACE, new Thickness(2, 0, 2, 0), VerticalAlignment.Center, HorizontalAlignment.Center, rowCount, 0, Visibility.Visible), FontWeights.Normal);

                            columnCount = 1;
                            foreach (DataColumn column in dictionaryTable.Columns)
                            {
                                string displayValue = row[column.ColumnName].ToString();
                                if (column.ColumnName.Equals("epifieldtype"))
                                {
                                    displayValue = displayValue.Replace("Epi.Fields.", "");
                                    if (isGroup)
                                    {
                                        displayValue = "GroupField";
                                    }
                                }
                                else if (column.ColumnName.Equals("columnname"))
                                {
                                    isGroup = dashboardHelper.GetGroupFieldsAsList().Contains(displayValue);
                                }
                                this.Dispatcher.BeginInvoke(setText, "", new TextBlockConfig(displayValue, new Thickness(8, 8, 8, 8), VerticalAlignment.Center, HorizontalAlignment.Left, rowCount, columnCount, Visibility.Visible), FontWeights.Normal);
                                columnCount++;
                            }

                            rowCount++;
                        }

                        this.Dispatcher.BeginInvoke(drawBorders, "");
                    }

                    this.Dispatcher.BeginInvoke(new SimpleCallback(RenderFinish));
                    this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                }
                catch (Exception ex)
                {
                    this.Dispatcher.BeginInvoke(new RenderFinishWithErrorDelegate(RenderFinishWithError), ex.Message);
                    this.Dispatcher.BeginInvoke(new SimpleCallback(SetGadgetToFinishedState));
                }
                finally
                {
                    stopwatch.Stop();
                    Debug.Print("Data dictionary gadget took " + stopwatch.Elapsed.ToString() + " seconds to complete with " + dashboardHelper.RecordCount.ToString() + " records and the following filters:");
                    Debug.Print(dashboardHelper.DataFilters.GenerateDataFilterString());
                }
            }
        }