void ProcessBlinkQueue()
        {
            int curentTickCount = Environment.TickCount;

            _tickCountAtLastProcessBlinkQueue = curentTickCount;
            bool anyCellInvalidated = false;

            while (_blinkQueue.Count > 0 && curentTickCount - _blinkQueue[0].tickCount > BlinkTime)
            {
                BlinkInfo bi = _blinkQueue[0];
                _blinkQueue.RemoveAt(0);

                if (bi.recordIndex == -1 || bi.fieldIndex == -1) // associated record or column was deleted.
                {
                    continue;
                }

                BlinkInfo bi2 = (BlinkInfo)_blinkTable[bi.GetKey()];
                if (bi2 != null && bi2.tickCount == bi.tickCount)
                {
                    _blinkTable.Clear(bi.GetKey());
                }

                int            record             = bi.recordIndex;
                int            rowIndex           = record + 1;
                int            columnIndex        = bi.fieldIndex + 1;
                RowColumnIndex cellRowColumnIndex = new RowColumnIndex(rowIndex, columnIndex);

                RenderStyles.Clear(cellRowColumnIndex);
                if (IsCellVisible(cellRowColumnIndex))
                {
                    InvalidateCellRenderStyleBackground(cellRowColumnIndex);
                    anyCellInvalidated = true;
                }
            }

            if (anyCellInvalidated)
            {
                InvalidateVisual(false);
            }
        }
        public BlinkState GetBlinkState(int r, int fd)
        {
            RowColumnIndex key = BlinkInfo.GetKey(r, fd);

            BlinkInfo bi;

            if (_blinkTable.TryGetValue(key, out bi))
            {
                return(bi.BlinkState);
            }

            return(BlinkState.None);
        }
        void Blink(ListChangedEventArgs e)
        {
            if (BlinkTime <= 0)
            {
                return;
            }

            ChangedFieldInfoCollection changeFields = GetChangedFields();
            bool anyCellInvalidated = false;

            if (changeFields != null)
            {
                foreach (ChangedFieldInfo ci in changeFields)
                {
                    PropertyDescriptor pd   = _pdc[ci.Name];
                    object             item = SourceList[e.NewIndex];
                    DataRow            row  = item as DataRow;
                    BlinkState         bs   = BlinkState.None;

                    if (e.ListChangedType == ListChangedType.ItemAdded)
                    {
                        bs = BlinkState.NewRecord;
                    }
                    else
                    {
                        object value    = ci.NewValue;
                        object oldValue = ci.OldValue;
                        int    cmp      = CompareColumns.CompareNullableObjects(value, oldValue);
                        if (cmp > 0)
                        {
                            bs = BlinkState.Increased;
                            if (oldValue == null || oldValue is DBNull)
                            {
                                bs = BlinkState.NewValue;
                            }
                        }
                        else if (cmp < 0)
                        {
                            bs = BlinkState.Reduced;
                            if (value == null || value is DBNull)
                            {
                                bs = BlinkState.NullValue;
                            }
                        }
                    }

                    if (bs != BlinkState.None)
                    {
                        RowColumnIndex key = BlinkInfo.GetKey(e.NewIndex, ci.FieldIndex);
                        BlinkInfo      biOld;
                        if (_blinkTable.TryGetValue(key, out biOld))
                        {
                            int n = _blinkQueue.IndexOf(biOld);
                            if (n != -1)
                            {
                                _blinkQueue.RemoveAt(n);
                            }
                        }

                        BlinkInfo bi = new BlinkInfo(bs, e.NewIndex, ci.FieldIndex, Environment.TickCount, ci);
                        _blinkQueue.Add(bi);
                        _blinkTable[key] = bi;

                        int            record             = e.NewIndex;
                        int            rowIndex           = record + 1;
                        int            columnIndex        = bi.fieldIndex + 1;
                        RowColumnIndex cellRowColumnIndex = new RowColumnIndex(rowIndex, columnIndex);

                        RenderStyles.Clear(cellRowColumnIndex);
                        if (IsCellVisible(cellRowColumnIndex))
                        {
                            InvalidateCellRenderStyleBackground(cellRowColumnIndex);
                            anyCellInvalidated = true;
                        }
                    }
                }
            }
            if (anyCellInvalidated)
            {
                InvalidateVisual(false);
            }
        }