コード例 #1
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
 ///<summary>Check static CacheLock fields and verify that they are still valid given the new filter criteria.
 ///Returns true if cache needs to be refreshed. Otherwise returns false.</summary>
 private bool IsInvalid(DashboardFilter filterIn, out DateTime dateFromOut, out DateTime dateToOut)
 {
     dateFromOut = DashboardCacheLock <T> .FilterOptions.DateFrom; dateToOut = DashboardCacheLock <T> .FilterOptions.DateTo;
     lock (DashboardCacheLock <T> .Lock) {
         if (_cacheS == null)                //Hasn't run yet so it is invalid.
         {
             dateFromOut = filterIn.DateFrom;
             dateToOut   = filterIn.DateTo;
             return(true);
         }
         if (!DashboardCacheLock <T> .FilterOptions.UseDateFilter)
         {
             //Date filter has previously been turned off, which means we have already gotten the untiltered cache at least once.
             //There will be nothing else to get so cache is valid.
             return(false);
         }
         bool ret = false;
         if (filterIn.DateFrom < DashboardCacheLock <T> .FilterOptions.DateFrom)              //New 'from' is before old 'from', invalidate.
         {
             dateFromOut = filterIn.DateFrom;
             ret         = true;
         }
         if (filterIn.DateTo > DashboardCacheLock <T> .FilterOptions.DateTo)              //New 'to' is after old 'to', invalidate.
         {
             dateToOut = filterIn.DateTo;
             ret       = true;
         }
         return(ret);
     }
 }
コード例 #2
0
        protected override string GetCommand(DashboardFilter filter)
        {
            string where = "";
            List <string> listWhereClauses = new List <string>();

            if (filter.UseDateFilter)
            {
                listWhereClauses.Add("AdjDate BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ");
            }
            if (filter.UseProvFilter)
            {
                listWhereClauses.Add("ProvNum=" + POut.Long(filter.ProvNum) + " ");
            }
            if (listWhereClauses.Count > 0)
            {
                where = "WHERE " + string.Join("AND ", listWhereClauses);
            }
            return
                ("SELECT AdjDate,ProvNum,SUM(AdjAmt) AdjTotal, ClinicNum "
                 + "FROM adjustment "
                 + where
                 + "GROUP BY AdjDate,ProvNum,ClinicNum "
                 + "HAVING AdjTotal<>0 "
                 + "ORDER BY AdjDate,ProvNum ");
        }
コード例 #3
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
 protected override List <T> GetCache(DashboardFilter filter)
 {
     return(DashboardQueries.GetTable(GetCommand(filter))
            .AsEnumerable()
            .Select(x => GetInstanceFromDataRow(x))
            .ToList());
 }
コード例 #4
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
 ///<summary>Fills the instance cache and the static cache (when necessary) using the given criteria. This IS thread-safe.
 ///If invalidateFirst==true then cache will be invalidated and forcefully refreshed. Use this sparingly.</summary>
 public void Run(DashboardFilter filter, bool invalidateFirst)
 {
     lock (DashboardCacheLock <T> .Lock) {
         if (invalidateFirst)                  //This will cause a force refresh.
         {
             _cacheS = null;
         }
         if (!AllowQueryDateFilter())
         {
             DashboardCacheLock <T> .FilterOptions.UseDateFilter = false;
         }
         DateTime dateFromOut; DateTime dateToOut;
         if (IsInvalid(filter, out dateFromOut, out dateToOut))                //The cache is invalid and should be filled using the new filter options.
         {
             DashboardCacheLock <T> .FilterOptions.DateFrom = dateFromOut;
             DashboardCacheLock <T> .FilterOptions.DateTo   = dateToOut;
             if (!filter.UseDateFilter && DashboardCacheLock <T> .FilterOptions.UseDateFilter)
             {
                 //Previously we used a data filter but now we are not. Set the flag indicating that we have retrieved the unfiltered cache.
                 DashboardCacheLock <T> .FilterOptions.UseDateFilter = false;
             }
             //This is potentially a slow query so set the static cache here.
             _cacheS = GetCache(DashboardCacheLock <T> .FilterOptions);
             RemoveBadData(_cacheS);
             //This is a simple shallow copy so it is safe enough to set _cache inside of this lock. It makes _cache available even when _cacheS is unavailable due to slow query.
             _cache = new List <T>(_cacheS);
         }
     }
 }
コード例 #5
0
        protected override List <Clinic> GetCache(DashboardFilter filter)
        {
            List <Clinic> list = Clinics.GetDeepCopy();

            _dictClinicNames = list.ToDictionary(x => x.ClinicNum, x => string.IsNullOrEmpty(x.Description) ? x.ClinicNum.ToString() : x.Description);
            return(list);
        }
コード例 #6
0
        protected override string GetCommand(DashboardFilter filter)
        {
            string where = "";
            List <string> listWhereClauses = new List <string>();

            if (filter.UseDateFilter)
            {
                listWhereClauses.Add("DATE(AdjDate) BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ");
            }
            if (filter.UseProvFilter)
            {
                listWhereClauses.Add("ProvNum=" + POut.Long(filter.ProvNum) + " ");
            }
            if (listWhereClauses.Count > 0)
            {
                where = "WHERE " + string.Join("AND ", listWhereClauses);
            }
            return
                ("SELECT AdjDate,ProvNum,COUNT(AdjNum) AdjCount,ClinicNum,AdjType, SUM(AdjAmt) AdjAmt "
                 + "FROM adjustment "
                 + "INNER JOIN definition ON definition.DefNum=adjustment.AdjType "
                 + "AND definition.ItemValue = '+' "
                 + where
                 + "GROUP BY AdjDate,ProvNum,ClinicNum,AdjType "
                 + "ORDER BY AdjDate,ProvNum,ClinicNum ");
        }
コード例 #7
0
        protected override List <DashboardAR> GetCache(DashboardFilter filter)
        {
            DateTime firstOfMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);

            filter.DateTo   = filter.DateTo < firstOfMonth ? filter.DateTo : firstOfMonth;
            filter.DateFrom = new DateTime(filter.DateFrom.Year, filter.DateFrom.Month, 1);
            return(DashboardQueries.GetAR(filter.DateFrom, filter.DateTo, DashboardARs.Refresh(filter.DateFrom)));
        }
コード例 #8
0
        protected override List <Provider> GetCache(DashboardFilter filter)
        {
            List <Provider> list = Providers.GetDeepCopy();

            _dictProvNames  = list.ToDictionary(x => x.ProvNum, x => string.IsNullOrEmpty(x.Abbr) ? x.ProvNum.ToString() : x.Abbr);
            _dictProvColors = list.GroupBy(x => x.Abbr).ToDictionary(x => string.IsNullOrEmpty(x.Key) ? x.First().ProvNum.ToString() : x.Key, x => x.First().ProvColor);
            return(list);
        }
コード例 #9
0
ファイル: ODGraph.cs プロジェクト: royedwards/DRDNet
        ///<summary>Helper method to convert from json string to ODGraphBaseSettingsAbs. Most importantly, provides filter settings for a given DashboardCell.</summary>
        public static ODGraphSettingsBase Deserialize(string json)
        {
            ODGraphSettingsBase ret = JsonConvert.DeserializeObject <ODGraphSettingsBase>(json);

            Cache.DashboardFilter filter = GetDatesFromQuickRange(ret.QuickRangePref, ret.DateFrom, ret.DateTo);
            ret.DateFrom = filter.DateFrom;
            ret.DateTo   = filter.DateTo;
            return(ret);
        }
コード例 #10
0
 protected override string GetCommand(DashboardFilter filter)
 {
     return
         ("SELECT PatNum, MIN(ProcDate) FirstProc, ClinicNum, ProvNum "
          + "FROM procedurelog USE INDEX(indexPNPSCN) "
          + "INNER JOIN procedurecode ON procedurecode.CodeNum = procedurelog.CodeNum "
          + "AND procedurecode.ProcCode NOT IN ('D9986','D9987')"
          + "WHERE ProcStatus=" + POut.Int((int)ProcStat.C) + " "
          + "GROUP BY PatNum");
 }
コード例 #11
0
 protected override List <T> GetCache(DashboardFilter filter)
 {
     if (filter.UseProvFilter && filter.ProvNum == 0)
     {
         return(new List <T>());
     }
     return(DashboardQueries.GetTable(GetCommand(filter), UseReportServer)
            .AsEnumerable()
            .Select(x => GetInstanceFromDataRow(x))
            .ToList());
 }
コード例 #12
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "";
     if (filter.UseDateFilter)
     {
         where = "DateCP BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " AND ";
     }
     return
         ("SELECT ProvNum,DateCP,SUM(InsPayAmt) AS GrossIncome,ClinicNum "
          + "FROM claimproc "
          + "WHERE " + where + "ClaimPaymentNum<>0 AND InsPayAmt<>0 "
          + "GROUP BY ProvNum,DateCP,ClinicNum ");
 }
コード例 #13
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
        ///<summary>Start a thread dedicated to filling the given cache.</summary>
        private static void FillCacheThreaded <T>(DashboardCacheBase <T> cache, DashboardFilter filter, string groupName, bool invalidateFirst)
        {
            ODThread thread = new ODThread(new ODThread.WorkerDelegate((ODThread th) => {
                if (OnSetDb != null)
                {
                    OnSetDb(cache, new EventArgs());
                }
                cache.Run(filter, invalidateFirst);
            }));

            thread.GroupName = groupName;
            thread.Start(false);
        }
コード例 #14
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "WHERE AptStatus=" + (int)ApptStatus.Broken + " ";
     if (filter.UseDateFilter)
     {
         where += "AND DATE(AptDateTime) BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ";
     }
     return
         ("SELECT DATE(AptDateTime) ApptDate,ProvNum,ClinicNum,COUNT(AptNum) ApptCount "
          + "FROM appointment "
          + where
          + "GROUP BY ApptDate,ProvNum,ClinicNum ");
 }
コード例 #15
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "";
     if (filter.UseDateFilter)
     {
         where = "DatePay BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " AND ";
     }
     return
         ("SELECT ProvNum,DatePay,SUM(SplitAmt) AS GrossSplit,ClinicNum "
          + "FROM paysplit "
          + "WHERE " + where + "IsDiscount=0 "
          + "GROUP BY ProvNum,DatePay,ClinicNum ");
 }
コード例 #16
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "";
     if (filter.UseDateFilter)
     {
         where = "WHERE AdjDate BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ";
     }
     return
         ("SELECT AdjDate,ProvNum,SUM(AdjAmt) AdjTotal, ClinicNum "
          + "FROM adjustment "
          + where
          + "GROUP BY AdjDate,ProvNum,ClinicNum "
          + "HAVING AdjTotal<>0 "
          + "ORDER BY AdjDate,ProvNum ");
 }
コード例 #17
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "WHERE procedurelog.ProcStatus=" + POut.Int((int)ProcStat.C) + " ";
     if (filter.UseDateFilter)
     {
         where += "AND procedurelog.ProcDate BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ";
     }
     return
         ("SELECT procedurelog.ProcDate,procedurelog.ProvNum,procedurelog.ClinicNum, "
          + "SUM(procedurelog.ProcFee*(procedurelog.UnitQty+procedurelog.BaseUnits)) AS GrossProd, "
          + "COUNT(procedurelog.ProcNum) AS ProcCount  "
          + "FROM procedurelog "
          + where
          + "GROUP BY procedurelog.ProcDate,procedurelog.ProvNum,procedurelog.ClinicNum ");
 }
コード例 #18
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "WHERE ProcStatus=" + (int)ProcStat.C + " ";
     if (filter.UseDateFilter)
     {
         where = "AND DATE(ProcDate) BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ";
     }
     return
         ("SELECT ProcDate,ProvNum,ClinicNum,COUNT(ProcNum) ProcCount, SUM(ProcFee) ProcFee,ProcCode "
          + "FROM procedurelog "
          + "INNER JOIN procedurecode ON procedurecode.CodeNum=procedurelog.CodeNum "
          + "AND procedurecode.ProcCode IN('D9986','D9987') "
          + where
          + "GROUP BY ProcDate,ProvNum,ClinicNum,ProcCode ");
 }
コード例 #19
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "";
     if (filter.UseDateFilter)
     {
         where = "WHERE DATE(AdjDate) BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ";
     }
     return
         ("SELECT AdjDate,ProvNum,COUNT(AdjNum) AdjCount,ClinicNum,AdjType, SUM(AdjAmt) AdjAmt "
          + "FROM adjustment "
          + "INNER JOIN definition ON definition.DefNum=adjustment.AdjType "
          + "AND definition.ItemValue = '+' "
          + where
          + "GROUP BY AdjDate,ProvNum,ClinicNum,AdjType "
          + "ORDER BY AdjDate,ProvNum,ClinicNum ");
 }
コード例 #20
0
        protected override string GetCommand(DashboardFilter filter)
        {
            string where = "ProcStatus=" + POut.Int((int)ProcStat.C);
            if (filter.UseProvFilter)
            {
                where += " AND ProvNum=" + POut.Long(filter.ProvNum);
            }
            string cmd =
                "SELECT PatNum, MIN(ProcDate) FirstProc, ClinicNum, ProvNum "
                + "FROM procedurelog USE INDEX(indexPNPSCN) "
                + "INNER JOIN procedurecode ON procedurecode.CodeNum = procedurelog.CodeNum "
                + "AND procedurecode.ProcCode NOT IN ('D9986','D9987')"
                + "WHERE " + where + " "
                + "GROUP BY PatNum";

            return(cmd);
        }
コード例 #21
0
 private void comboQuickRange_SelectedIndexChanged(object sender, EventArgs e)
 {
     _allowFilter = false;
     if (QuickRangePref == QuickRange.custom)
     {
         dateTimeTo.Enabled   = true;
         dateTimeFrom.Enabled = true;
     }
     else
     {
         dateTimeTo.Enabled   = false;
         dateTimeFrom.Enabled = false;
         Cache.DashboardFilter filter = Filter;
         DateFrom = filter.DateFrom;
         DateTo   = filter.DateTo;
     }
     _allowFilter = true;
     FilterData(sender, e);
 }
コード例 #22
0
 protected override string GetCommand(DashboardFilter filter)
 {
     string where = "WHERE TRUE ";
     if (filter.UseDateFilter)
     {
         where += "AND ProcDate BETWEEN " + POut.Date(filter.DateFrom) + " AND " + POut.Date(filter.DateTo) + " ";
     }
     return
         ("SELECT ProcDate,ProvNum,SUM(WriteOff) AS WriteOffs, IF(claimproc.Status=" + (int)ClaimProcStatus.CapComplete + ",'1','0') AS IsCap, ClinicNum "
          + "FROM claimproc "
          + where
          + "AND claimproc.Status IN ("
          + POut.Int((int)ClaimProcStatus.Received) + ","
          + POut.Int((int)ClaimProcStatus.Supplemental) + ","
          + POut.Int((int)ClaimProcStatus.NotReceived) + ","
          + POut.Int((int)ClaimProcStatus.CapComplete) + ") "
          + "GROUP BY ProcDate,ProvNum,(claimproc.Status=" + (int)ClaimProcStatus.CapComplete + "),ClinicNum "
          + "HAVING WriteOffs<>0 ");
 }
コード例 #23
0
 public void DeserializeFromJson(string json)
 {
     try {
         QuantityOverTimeGraphSettings settings = ODGraphSettingsBase.Deserialize <QuantityOverTimeGraphSettings>(json);
         this.QtyType       = settings.QtyType;
         this.SeriesType    = settings.SeriesType;
         this.GroupByType   = settings.GroupByType;
         this.LegendDock    = settings.LegendDock;
         this.BreakdownPref = settings.BreakdownPref;
         this.BreakdownVal  = settings.BreakdownVal;
         this.GraphTitle    = settings.Title;
         this.ChartSubTitle = settings.SubTitle;
         //Important that quick range is set last to prevent FilterData from firing multiple times.
         this.QuickRangePref = settings.QuickRangePref;
         //we should always recreate the dates so that they are current.
         Cache.DashboardFilter filter = ODGraphSettingsBase.GetDatesFromQuickRange(settings.QuickRangePref, settings.DateFrom, settings.DateTo);
         this.DateFrom = filter.DateFrom;
         this.DateTo   = filter.DateTo;
     }
     catch (Exception e) {
         MessageBox.Show(e.Message);
     }
 }
コード例 #24
0
ファイル: ODGraph.cs プロジェクト: royedwards/DRDNet
        ///<summary>If quickRange==QuickRange.custom then return a filter containing customDateFrom and customDateTo.
        ///In all other cases, the date range will be calculated given the quickRange.</summary>
        public static Cache.DashboardFilter GetDatesFromQuickRange(Enumerations.QuickRange quickRange, DateTime customDateFrom, DateTime customDateTo)
        {
            Cache.DashboardFilter filter = new Cache.DashboardFilter();
            switch (quickRange)
            {
            case Enumerations.QuickRange.custom:
                filter.DateTo   = customDateTo;
                filter.DateFrom = customDateFrom;
                break;

            case Enumerations.QuickRange.last7Days:
                filter.DateTo   = DateTime.Today;
                filter.DateFrom = filter.DateTo.AddDays(-7);
                break;

            case Enumerations.QuickRange.last30Days:
                filter.DateTo   = DateTime.Today;
                filter.DateFrom = filter.DateTo.AddDays(-30);
                break;

            case Enumerations.QuickRange.last365Days:
                filter.DateTo   = DateTime.Today;
                filter.DateFrom = filter.DateTo.AddDays(-365);
                break;

            case Enumerations.QuickRange.last12Months:
                filter.DateTo   = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddDays(-1);
                filter.DateFrom = filter.DateTo.AddMonths(-12).AddDays(1);
                break;

            case Enumerations.QuickRange.previousWeek:
                filter.DateFrom = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek).AddDays(-7);
                filter.DateTo   = filter.DateFrom.AddDays(7);
                break;

            case Enumerations.QuickRange.previousMonth:
                filter.DateFrom = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(-1);
                filter.DateTo   = filter.DateFrom.AddMonths(1);
                break;

            case Enumerations.QuickRange.previousYear:
                filter.DateFrom = new DateTime(DateTime.Today.Year - 1, 1, 1);
                filter.DateTo   = filter.DateFrom.AddYears(1);
                break;

            case Enumerations.QuickRange.thisWeek:
                filter.DateFrom = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
                filter.DateTo   = filter.DateFrom.AddDays(7);
                break;

            case Enumerations.QuickRange.thisMonth:
                filter.DateFrom = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
                filter.DateTo   = filter.DateFrom.AddMonths(1);
                break;

            case Enumerations.QuickRange.thisYear:
                filter.DateFrom = new DateTime(DateTime.Today.Year, 1, 1);
                filter.DateTo   = filter.DateFrom.AddYears(1);
                break;

            case Enumerations.QuickRange.weekToDate:
                filter.DateFrom = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
                filter.DateTo   = DateTime.Today;
                break;

            case Enumerations.QuickRange.monthToDate:
                filter.DateFrom = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
                filter.DateTo   = DateTime.Today;
                break;

            case Enumerations.QuickRange.yearToDate:
                filter.DateFrom = new DateTime(DateTime.Today.Year, 1, 1);
                filter.DateTo   = DateTime.Today;
                break;

            case Enumerations.QuickRange.allTime:
                filter.DateFrom      = new DateTime(1880, 1, 1);
                filter.DateTo        = filter.DateFrom.AddYears(300);
                filter.UseDateFilter = false;
                break;

            default:
                throw new Exception("Unsupported QuickRange: " + quickRange.ToString());
            }
            return(filter);
        }
コード例 #25
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
 protected abstract string GetCommand(DashboardFilter filter);
コード例 #26
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
 public virtual List <T> GetCacheUnthreaded(DashboardFilter filter)
 {
     return(GetCache(filter));
 }
コード例 #27
0
 protected override List <HQMessage> GetCache(DashboardFilter filter)
 {
     return(ListHqMessages);
 }
コード例 #28
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
 ///<summary>Concrete implementers must override this and provide the cache given the input criteria.</summary>
 protected abstract List <T> GetCache(DashboardFilter filter);
コード例 #29
0
ファイル: DashboardCache.cs プロジェクト: kjb7749/testImport
        ///<summary>Refresh the cache(s) associated with the given cellType. If waitToReturn==true then block until finished.
        ///If waitToReturn==false then runs async and returns immediately. Optionally wait for the method to return or run async.
        ///onExit event will be fired after async version has completed. Will not fire when sync version is run as this is a blocking call so when it returns it is done.
        ///If invalidateFirst==true then cache will be invalidated and forcefully refreshed. Use this sparingly.</summary>
        public static void RefreshCellTypeIfInvalid(DashboardCellType cellType, DashboardFilter filter, bool waitToReturn, bool invalidateFirst, EventHandler onExit = null)
        {
            //Create a random group name so we can arbitrarily group and wait on the threads we are about to start.
            string groupName = cellType.ToString() + _rand.Next();

            try {
                switch (cellType)
                {
                case DashboardCellType.HQPhone:
                case DashboardCellType.HQConfirmation:
                case DashboardCellType.HQMtMessage:
                case DashboardCellType.HQBillingUsageAccess:
                case DashboardCellType.HQMoMessage:
                case DashboardCellType.HQBillingInboundOutbound:
                case DashboardCellType.HQSignups:
                    //Broadcast monitor does not use the ODGraph cache.
                    return;
                }
                //Always fill certain caches first. These will not be threaded as they need to be available to the threads which will run below.
                //It doesn't hurt to block momentarily here as the queries will run very quickly.
                Providers.Run(new DashboardFilter()
                {
                    UseDateFilter = false
                }, invalidateFirst);
                Clinics.Run(new DashboardFilter()
                {
                    UseDateFilter = false
                }, invalidateFirst);
                //Start certain cache threads depending on which cellType we are interested in. Each cache will have its own thread.
                switch (cellType)
                {
                case DashboardCellType.ProductionGraph:
                    FillCacheThreaded(CompletedProcs, filter, groupName, invalidateFirst);
                    FillCacheThreaded(Writeoffs, filter, groupName, invalidateFirst);
                    FillCacheThreaded(Adjustments, filter, groupName, invalidateFirst);
                    break;

                case DashboardCellType.IncomeGraph:
                    FillCacheThreaded(PaySplits, filter, groupName, invalidateFirst);
                    FillCacheThreaded(ClaimPayments, filter, groupName, invalidateFirst);
                    break;

                case DashboardCellType.AccountsReceivableGraph:
                    FillCacheThreaded(AR, filter, groupName, invalidateFirst);
                    break;

                case DashboardCellType.NewPatientsGraph:
                    FillCacheThreaded(Patients, filter, groupName, invalidateFirst);
                    break;

                case DashboardCellType.BrokenApptGraph:
                    FillCacheThreaded(BrokenAppts, filter, groupName, invalidateFirst);
                    FillCacheThreaded(BrokenProcs, filter, groupName, invalidateFirst);
                    FillCacheThreaded(BrokenAdjs, filter, groupName, invalidateFirst);
                    break;

                case DashboardCellType.NotDefined:
                default:
                    throw new Exception("Unsupported DashboardCellType: " + cellType.ToString());
                }
            }
            finally {
                if (waitToReturn)                  //Block until all threads have completed.
                {
                    ODThread.JoinThreadsByGroupName(System.Threading.Timeout.Infinite, groupName, true);
                }
                else if (onExit != null)                //Exit immediately but fire event later once all threads have completed.
                {
                    ODThread.AddGroupNameExitHandler(groupName, onExit);
                }
            }
        }