2017-02-06 6 views
-1

У меня есть DataGridView, привязанный к источнику данных. Я хотел бы иметь задний цвет изменения ячейки (красным цветом), в течение 1-2 секунд, когда значение в ячейке изменяется. Я пробовал и могу изменить цвет ячейки обратно, но не смог вернуть его к цвету по умолчанию через несколько секунд. Идея состоит в том, чтобы обратить внимание пользователя на ячейку при изменении ее значения.DataGridView Изменить цвет обратной связи ячейки на изменение значения

Применение C# .NET 4.5

+0

Добро пожаловать в SO. Можете ли вы опубликовать код yoyr в вопросе, чтобы мы могли видеть, что вы пробовали до сих пор? –

+0

Я думаю, вы должны создать свой собственный класс DataGridViewCell, который имеет System.Windows.Form.Timer и обрабатывает изменения на его значение. Когда значение изменяется, сбросьте таймер и измените цвет фона. Таймер должен менять цвет при запуске. У вас нет времени для разработки правильного решения. Надеюсь, это поможет в любом случае. – sbecker

+0

Спасибо, sbecker .... попробует это. – Rajeev

ответ

1

Я создал пример для кнопки, но вы можете применить его на DataGridView клетки.

private Color OriginalColor = Color.WhiteSmoke; 
    private int TimeToColorInMiliSeconds = 2000; 

    private void button1_Click(object sender, EventArgs e) 
    { 
     ColorForTwoSeconds(button1); 
    } 

    private void ColorForTwoSeconds(Button button) 
    { 
     button.BackColor = Color.Red; 
     Task.Run(() => ResetBackColor()); 
    } 

    private void ResetBackColor() 
    { 
     Thread.Sleep(TimeToColorInMiliSeconds); 
     button1.BeginInvoke((MethodInvoker) delegate 
     { 
      button1.BackColor = OriginalColor; 
     }); 
    } 
+0

Спасибо KernelMode, я пробовал что-то подобное этому, но проблема здесь в том, что если данные быстро меняются, основной поток практически блокируется и форма почти замерзает. Любое другое предложение? – Rajeev

+0

Если данные быстро меняются, тогда здесь нужно больше дел. Например, что происходит, если я меняю одну и ту же ячейку каждую секунду. Возможно, вам следует предотвратить запуск цветовой логики, если ячейка уже отмечена.Кроме того, AFIK, Invoke должен подтолкнуть задачу обновления цвета в очередь, и поток пользовательского интерфейса выполнит эту задачу, когда он «освободится», чтобы сделать это. Обратите внимание, что сон находится под другой нитью. Не пользовательский интерфейс. Возможно ли, что основной поток заблокирован на чем-то другом? – KernelMode

0

попробовать это

dataGridView1.Rows[rowIndex].Cells[columnIndex].Style.BackColor = Color.Red; 

, если вы хотите, чтобы цвет все строки попробовать это

dataGridView1.RowsDefaultCellStyle.SelectionBackColor = Color.Red; 
0

Многое, как KernalMode suggested, вы можете использовать нить вызов для установки ячейки BackColor в течение периода времени. Чтобы гарантировать, что дополнительные изменения в ячейке «сбросят» таймер при изменении цвета, вы можете установить тег ячейки с значением DateTime последнего изменения и проверить его на время, прошедшее с момента его окончания.

private int TimeToColorInMiliSeconds = 2000; 

private void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
{ 
    this.dataGridView1[e.ColumnIndex, e.RowIndex].Tag = DateTime.Now; 
    Task.Run(() => this.ChangeCellBackground(e.ColumnIndex, e.RowIndex, Color.White, Color.IndianRed)); 
} 

private void ChangeCellBackground(int col, int row, Color original, Color alert) 
{ 
    this.dataGridView1.BeginInvoke((MethodInvoker)delegate 
    { 
     this.dataGridView1[col, row].Style.BackColor = alert; 
    }); 

    Thread.Sleep(this.TimeToColorInMiliSeconds); 

    this.dataGridView1.BeginInvoke((MethodInvoker)delegate 
    { 
     DateTime lastChanged = (DateTime)(this.dataGridView1[col, row].Tag); 
     DateTime timeNow = DateTime.Now; 
     TimeSpan elapsed = timeNow - lastChanged; 

     if (elapsed.TotalMilliseconds >= this.TimeToColorInMiliSeconds) 
     { 
      this.dataGridView1[col, row].Style.BackColor = original; 
     } 
    }); 
} 

ТЕСТИРОВАНИЯ НАЗНАЧЕНИЯ

Для моделирования быстрых изменений, рассмотрим следующий пример, в котором все ячейки инициализируется 0 и нажатием кнопки начинается рекурсивную функцию, которая увеличивает значение ячейка выбирается случайным образом каждые N миллисекунд.

private int N = 500; 
private Random rand = new Random(); 

private void Button1_Click(object sender, EventArgs e) 
{ 
    Task.Run(() => this.IncrementRandomCell()); 
} 

private void IncrementRandomCell() 
{ 
    int col = this.rand.Next(this.dataGridView1.ColumnCount); 
    int row = this.rand.Next(this.dataGridView1.RowCount); 

    this.dataGridView1.BeginInvoke((MethodInvoker)delegate 
    { 
     int value = int.Parse(this.dataGridView1[col, row].Value.ToString()); 
     this.dataGridView1[col, row].Value = ++value; 
    }); 

    Thread.Sleep(this.N); 
    this.IncrementRandomCell(); 
} 
0

Вот мой подход. Создав собственную ячейку, вы можете проверить, изменилось ли значение и обрабатывать его соответствующим образом. Использование Forms.Timer позволяет избежать использования потоков.

Поскольку DataGridViewCells не имеют событий OnValueChanged, мы переопределяем Paint, чтобы проверить, изменилось ли значение. Если это так, мы меняем BackColor и запускаем таймер, чтобы вернуть BackColor в его предыдущее значение.

Как вы можете видеть, я получил из DataGridViewTextBoxCell. Но переопределение DataGridViewCheckBoxCell или любого другого должно в основном работать одинаково.

using System; 
using System.Drawing; 
using System.Windows.Forms; 

namespace DataGridViewCustomControls 
{ 
    internal class DataGridViewHighlightChangeCell : DataGridViewTextBoxCell  
    { 
     public Color HighlightColor { get; set; } = Color.Red; 
     public int HighlightTime { get; set; } = 1000; 

     private object PreviousValue; 
     private Color PreviousColor; 
     private Timer HighlightTimer = new Timer(); 

     public DataGridViewHighlightChangeCell() 
     { 
      HighlightTimer.Tick += HighlightTimer_Tick; 
     } 

     protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) 
     { 
      HighlightOnChange(); 

      base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); 
     } 

     private void HighlightOnChange() 
     { 
      if (RowIndex == -1 || Value == PreviousValue) 
      { 
       return; 
      } 

      PreviousValue = Value; 

      if (HighlightTimer.Enabled) 
      { 
       HighlightTimer.Stop(); 
       HighlightTimer.Start(); 
       return; 
      } 

      PreviousColor = Style.BackColor; 
      Style.BackColor = HighlightColor; 
      HighlightTimer.Interval = HighlightTime; 
      HighlightTimer.Start(); 
     } 

     private void HighlightTimer_Tick(object sender, EventArgs e) 
     { 
      HighlightTimer.Stop(); 
      Style.BackColor = PreviousColor; 
     } 

     protected override void Dispose(bool disposing) 
     { 
      if (disposing && HighlightTimer != null) 
      { 
       HighlightTimer.Dispose(); 
       HighlightTimer = null; 
      } 

      base.Dispose(disposing); 
     } 
    } 
}