DataGridView czasowa zmiana koloru komórki

0

Witam,

piszę aplikację która asynchronicznie pobiera dane do kontrolki DataGridView i chciałbym uzyskać taki efekt, że gdy zmieniona zostanie wartość danej komórki to kolor tła tej komórki zmieni się na inny na okres np. 2 sekund po czym wróci do domyślnego. Domyslam sie że należy wykorzystać zdarzenie CellValueChanged. Tylko co dalej. Czy wykorzystać kontrolkę Timer działającą w nowym wątku ? Ew. jak to zrobić.

Zaznaczam, że jednocześnie może być zmienionych wiele komórek.

0

Ciekawy problem.
Jeśli w zdarzeniu CellValueChanged zmienisz kolor, następnie dasz Thread.Sleep(2000) i zmienisz kolor ponownie - prawdopodobnie zawiesi sie UI na czas tych dwóch sekund (aczkolwiek nie jestem pewien). Jeśli natomiast w tym zdarzeniu uruchomisz nowy wątek, który by poczekał - powstanie ich zbyt wiele.

Trzeba by chyba w CellValueChanged zmieniać kolor, następnie dodawać informację o dacie zmiany, RowIndex i ColumnIndex do jakiejś kolekcji. Uruchomić jeden wątek odpowiedzialny za sprawdzanie (co np. 100ms) czy któraś komórka wymaga powrotu do pierwotnego koloru, jeśli tak - usuwać ją z kolekcji i zmieniać kolor (pamiętaj, że nie możesz "na chama" zmieniać UI z poziomu wątku, trzeba użyć delegatów/zdarzeń).

0

zdecydowanie koncepcja jednego watku sprawdzajacego jak kolory zmienic danym komorkom jest sluszna
aby timer nie latal bez sensu proponuje dodac tez ze jesli lista komorek, ktorym nalezy zmieniac kolory jest pusta to timer sie zatrzymuje, jesli dodajesz do tej listy element, a jest ona pusta, to timer startujesz (i o ile timer nie chodzi)

0

Dziękuję za udzielone rady, uwzględniając je udało mi się osiągnąć zamierzony efekt w poniższy sposób.

Stan kiedy komórka ma zmieniony kolor trwa 1 sek i działa to świetnie. Zauważyłem jednak że użycie procesora wzrosło do 30% (wczesniej użycie było marginalne). Zapewne ma to związek z odmalowywaniem komórek, a jest ich trochę (kilka zmian na sekunde). Czy da się ten problem też jakoś rozwiązać ?


        mdCollection.ListChanged += new ListChangedEventHandler(mdCollection_ListChanged);
        tc = new TimerCallback(CellColorChange);
        cellTimer = new System.Threading.Timer(tc, cellColors, 10, 10)   // odświeżanie co 10 ms.
        

        private void mdCollection_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (e.ListChangedType == ListChangedType.ItemChanged)
            {
                try
                {
                    int rowIndex = e.NewIndex;
                    string cellName = e.PropertyDescriptor.Name;
                    int colIndex = monitor.Rows[rowIndex].Cells[cellName].ColumnIndex;

                    monitor.Rows[rowIndex].Cells[cellName].Style.BackColor = Color.FromArgb(208, 248, 136);
                    cellColors.Add(new CellColor(Environment.TickCount, rowIndex, colIndex));
                }
                catch (Exception ex) { }
            }
        }

        private void CellColorChange(Object obj)
        {
            if (obj is List<CellColor>)
            {
                try
                {
                    List<CellColor> cellColors = (List<CellColor>)obj;
                    int count = cellColors.Count;
                    int currentTime = Environment.TickCount;

                    foreach (CellColor ck in cellColors)
                    {
                        if (currentTime - ck.Time > 1000)
                        {
                            monitor.Rows[ck.RowIndex].Cells[ck.ColIndex].Style.BackColor = Color.White; // monitor = DataGridView
                            cellColors.Remove(ck);
                        }
                    }
                }
                catch (Exception ex)
                {
                }
            }
        }
0

proponuje zwiekszyc tick do 100ms i nie uzywac foreach tylko zwyklego for lub cellColors.ForEach (nie chce mi sie rozwodzic czemu sa szybsze, ale sa)
oraz dodac lock na dodawaniu do cellColors komorki
oraz lock na tym samym obiekcie na CellColorChange

lub uzyc wpf

jak cos jeszcze wymysle dam znac

0

Mała ciekawostka. Kiedyś napisałem program w którym było odliczanie czasu (co sekundę) we wszystkich komórkach jednej kolumny. Jechał po nich dedykowany wątek, który po aktualizacji wszystkich komórek spał 100ms. Było też kolorowanie tekstu w komórkach w zależności od pokazanego w nich czasu (w zdarzeniu CellFormatting). Wszystko działało dobrze dopóki nie wykonałem sortowania, po nim od razu użycie procesora rosło do 100% i nie wiedziałem dlaczego. Nie udało mi się tego w żaden sposób rozwiązać. Jakiś czas temu przeglądałem ten program, zaktualizowałem go do Framework 4.0 (był napisany z wykorzystaniem chyba 3.5) i problem zniknął - czyli wychodzi na to, że był to błąd wcześniejszej wersji Framework'a.

A jeśli chodzi o Twój problem - możesz spróbować też pauzować Timer na początku i puszczać na końcu (po sprawdzeniu co ma sprawdzić). Możesz też dla DataGridView zastosować .SuspendLayout() przed aktualizacją i .ResumeLayout() po niej - powinno zwiększyć wydajność.

1 użytkowników online, w tym zalogowanych: 0, gości: 1