2015-08-22 72 views
8

Vorrei disegnare un bordo rosso attorno a una cella DataGridView durante la modifica.Come si disegna un bordo attorno a una cella DataGridView mentre viene modificato?

sono riuscito a disegnare un bordo rosso intorno alla cella selezionata, mentre non è in corso di modifica utilizzando questo codice:

private void Form1_Load(object sender, EventArgs e) 
{ 
    this.Width = 650; 
    this.Height = 250; 
    dataGridView1.Left = 5; 
    dataGridView1.Top = 5; 
    dataGridView1.Width = 600; 
    dataGridView1.Height = 175; 

    DataTable dt = new DataTable("Test Table"); 
    dt.Columns.Add("Column 1"); 
    dt.Columns.Add("Column 2"); 
    dt.Columns.Add("Column 3"); 
    dt.Columns.Add("Column 4"); 
    dt.Columns.Add("Column 5"); 
    dt.Rows.Add(dt.NewRow()); 
    dt.Rows.Add(dt.NewRow()); 
    dt.Rows.Add(dt.NewRow()); 
    dt.Rows.Add(dt.NewRow()); 
    dt.Rows.Add(dt.NewRow()); 
    dataGridView1.DataSource = dt; 

    dataGridView1.AllowUserToAddRows = false; 
    dataGridView1.AllowUserToDeleteRows = false; 
    dataGridView1.MultiSelect = false; 
    dataGridView1.SelectionMode = DataGridViewSelectionMode.CellSelect; 
    dataGridView1.DefaultCellStyle.SelectionBackColor = Color.White; 
    dataGridView1.CellPainting += new System.Windows.Forms.DataGridViewCellPaintingEventHandler(this.dataGridView1_CellPainting); 
    dataGridView1.EditingControlShowing += new System.Windows.Forms.DataGridViewEditingControlShowingEventHandler(this.dataGridView1_EditingControlShowing); 
} 

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) 
{ 
    if (e.ColumnIndex != -1 && e.RowIndex != -1 && dataGridView1[e.ColumnIndex, e.RowIndex].Selected) 
    { 
     using (Brush borderBrush = new SolidBrush(Color.Red)) 
     { 
      using (Pen borderPen = new Pen(borderBrush, 2)) 
      { 
       Rectangle rectDimensions = e.CellBounds; 
       rectDimensions.Width -= 2; 
       rectDimensions.Height -= 2; 
       rectDimensions.X = rectDimensions.Left + 1; 
       rectDimensions.Y = rectDimensions.Top + 1; 

       e.Graphics.DrawRectangle(borderPen, rectDimensions); 

       e.Handled = true; 
      } 
     } 
    } 
} 

che produce questo risultato:

Image1

Tuttavia, quando si modifica una cella succede:

Image2

Sembra che lo EditingControl si disori sopra la maggior parte del mio bordo rosso. Sfortunatamente, non riesco a trovare un modo per sistemarlo, quindi il mio bordo rosso rimarrà sempre visualizzato in ogni momento.

Come posso fare questo ???



Ecco quello che ho provato finora:

1. gestione dell'evento EditingControlShowing() manualmente ri-disegnare il confine in questo modo:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) 
{ 
    Graphics gfx = e.Control.CreateGraphics(); 

    using (Brush borderBrush = new SolidBrush(Color.Red)) 
    { 
     using (Pen borderPen = new Pen(borderBrush, 2)) 
     { 
      Rectangle rectDimensions = e.Control.ClientRectangle; 
      rectDimensions.Width -= 2; 
      rectDimensions.Height -= 2; 
      rectDimensions.X = rectDimensions.Left + 1; 
      rectDimensions.Y = rectDimensions.Top + 1; 

      gfx.DrawRectangle(borderPen, rectDimensions); 
     } 
    } 
} 

Ma questo non ha disegnato nulla. Ho provato alcune varianti di questo, ma tutte non hanno ancora disegnato nulla qui.


2. Ho poi cercato di gestire l'evento Paint() del EditingControl in questo modo:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) 
{ 
    e.Control.Paint -= new PaintEventHandler(dataGridView1_EditingControl_Paint); 
    e.Control.Paint += new PaintEventHandler(dataGridView1_EditingControl_Paint); 
} 

void dataGridView1_EditingControl_Paint(object sender, PaintEventArgs e) 
{ 
    MessageBox.Show("Starting EditingControl Paint() Event..."); 
} 

Ma questo evento non ha nemmeno il fuoco. Successivamente ho letto da qualche parte che lo EditingControl utilizza un normale TextBox, che non genera l'evento Paint() perché è gestito da Windows.


3. Infine, piuttosto che cercare di ri-disegnare un altro confine, ho deciso di provare e incidere intorno esso ridimensionando la EditingControl essere più piccolo del mio confine nella speranza confine sarebbe poi mostrare in giro che, in questo modo:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) 
{ 
    e.Control.Resize -= new EventHandler(dataGridView1_EditingControl_Resize); 
    e.Control.Resize += new EventHandler(dataGridView1_EditingControl_Resize); 
} 

void dataGridView1_EditingControl_Resize(object sender, EventArgs e) 
{ 
    dataGridView1.EditingControl.Left = 20; 
} 

Tuttavia, che mi ha dato questo risultato:

Image3

Quindi lo TextBox si è spostato a sinistra, ma sembra che ci sia un altro controllo al di sotto che sta ancora bloccando il mio bordo rosso.Tuttavia, non riesco a trovare comunque l'accesso a questo controllo per ridimensionarlo, quindi questo non ha funzionato neanche per me.


4. Ho anche provato ad utilizzare il codice da sopra 1 # per ri-disegnare il bordo in caso Resize(), ma che ancora non ha fatto nulla. Anche se, usando dataGridView1.EditingControl.BackColor = Color.Red; ha funzionato così posso qui formattare alcune parti del controllo, ma sembra che provare a disegnare un bordo non è uno di loro.

Tutto ciò che voglio fare è mantenere un bordo rosso visibile intorno alla cella mentre è in corso di modifica. Sai come posso fare questo?

+0

Hai provato ad affrontare gli orrori di borderstyles? – TaW

+0

Ho dato un'occhiata a loro ma tutto quello che ho trovato era opzioni per impostare il BorderStyle su none, inset, raised, ecc. Ma non ero sicuro se ci fosse un modo per impostare anche i colori del bordo che li usano? – Calcolat

+0

Hai ragione, i colori non fanno parte di BorderStyles. – TaW

risposta

2

L'approccio più semplice utilizzando il codice esistente è l'impostazione del CellBorderStyle a Sunken come illustrato di seguito:

dataGridView1.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.Sunken; 

enter image description here

Se non ti piace Affondato, allora si può raggiungere questo obiettivo AdjustCellBorderStyle e DataGridViewAdvancedBorderStyle, in modifica evento focus cella/personalizzare lo stile del bordo cella. Dai un'occhiata anche a: How to: Customize Cells and Columns in the Windows Forms DataGridView Control by Extending Their Behavior and Appearance.

Spero che ti possa aiutare.

+0

Questo è un approccio interessante e funziona in qualche modo. Il mio problema principale è che preferisco mantenere lo stile il più piatto possibile e che trasforma ogni cella in un aspetto sommerso. Inoltre, se utilizzo una larghezza della penna più spessa per il bordo mentre le celle non sono in modalità di modifica, il bordo diventa ancora tagliato in modo evidente mentre si è in modalità di modifica. C'è forse un modo per applicare lo stile incassato solo alla cella attualmente selezionata e non il resto? Se c'è, potrei essere in grado di usarlo come soluzione per il momento. – Calcolat

6

Può essere eseguito utilizzando alcune impostazioni e dipingendo parti specifiche della cella. Per così così:

In primo luogo, impostare CellBorderStyle-Raised o Sunken in designer o semplicemente nel codice caricamento form:

this.dataGridView1.CellBorderStyle = DataGridViewCellBorderStyle.Raised; 

quindi disegnare le cellule usando queste specifiche norme ordinato:

  1. Draw solo griglia celle di contenuto non ColumnHeader cells o RowHeader
  2. Quando si disegnano celle selezionate, prima si dipingono tutte le parti tranne i bordi usando e.Paint (...); quindi disegnare i confini stessi
  3. Set e.Handled = true per evitare di default pittura
  4. Quando si disegna le celle non selezionate, prima dipingere tutte le parti tranne i bordi utilizzando e.Paint (...)
  5. Disegna bordo superiore delle cellule della prima riga e del bordo sinistro delle celle della prima colonna utilizzando il colore di sfondo della griglia
  6. Disegna il bordo inferiore delle celle dell'ultima riga e il bordo destro delle celle dell'ultima colonna utilizzando il colore della linea della griglia
  7. Disegna il bordo inferiore delle celle di non ultimo bordo di riga e destra delle celle della non ultima colonna utilizzando il colore di sfondo della griglia
  8. Disegna t celle op di bordo di prima riga e margine sinistro di celle di non ultima colonna utilizzando il colore della linea della griglia 9. Imposta e.Handled = true per evitare che la pittura di default

Si tratta di screenshot del risultato, dopo selezionare

enter image description here

ed ecco screenshot del risultato, durante la modifica delle cellule

enter image description here

e ecco il codice dell'evento vernice cellulare:

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) 
{ 
    //Draw only grid content cells not ColumnHeader cells nor RowHeader cells 
    if (e.ColumnIndex > -1 & e.RowIndex > -1) 
    { 
     //Pen for left and top borders 
     using (var backGroundPen = new Pen(e.CellStyle.BackColor, 1)) 
     //Pen for bottom and right borders 
     using (var gridlinePen = new Pen(dataGridView1.GridColor, 1)) 
     //Pen for selected cell borders 
     using (var selectedPen = new Pen(Color.Red, 1)) 
     { 
      var topLeftPoint = new Point(e.CellBounds.Left, e.CellBounds.Top); 
      var topRightPoint = new Point(e.CellBounds.Right - 1, e.CellBounds.Top); 
      var bottomRightPoint = new Point(e.CellBounds.Right - 1, e.CellBounds.Bottom - 1); 
      var bottomleftPoint = new Point(e.CellBounds.Left, e.CellBounds.Bottom - 1); 

      //Draw selected cells here 
      if (this.dataGridView1[e.ColumnIndex, e.RowIndex].Selected) 
      { 
       //Paint all parts except borders. 
       e.Paint(e.ClipBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border); 

       //Draw selected cells border here 
       e.Graphics.DrawRectangle(selectedPen, new Rectangle(e.CellBounds.Left, e.CellBounds.Top, e.CellBounds.Width - 1, e.CellBounds.Height - 1)); 

       //Handled painting for this cell, Stop default rendering. 
       e.Handled = true; 
      } 
      //Draw non-selected cells here 
      else 
      { 
       //Paint all parts except borders. 
       e.Paint(e.ClipBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border); 

       //Top border of first row cells should be in background color 
       if (e.RowIndex == 0) 
        e.Graphics.DrawLine(backGroundPen, topLeftPoint, topRightPoint); 

       //Left border of first column cells should be in background color 
       if (e.ColumnIndex == 0) 
        e.Graphics.DrawLine(backGroundPen, topLeftPoint, bottomleftPoint); 

       //Bottom border of last row cells should be in gridLine color 
       if (e.RowIndex == dataGridView1.RowCount - 1) 
        e.Graphics.DrawLine(gridlinePen, bottomRightPoint, bottomleftPoint); 
       else //Bottom border of non-last row cells should be in background color 
        e.Graphics.DrawLine(backGroundPen, bottomRightPoint, bottomleftPoint); 

       //Right border of last column cells should be in gridLine color 
       if (e.ColumnIndex == dataGridView1.ColumnCount - 1) 
        e.Graphics.DrawLine(gridlinePen, bottomRightPoint, topRightPoint); 
       else //Right border of non-last column cells should be in background color 
        e.Graphics.DrawLine(backGroundPen, bottomRightPoint, topRightPoint); 

       //Top border of non-first row cells should be in gridLine color, and they should be drawn here after right border 
       if (e.RowIndex > 0) 
        e.Graphics.DrawLine(gridlinePen, topLeftPoint, topRightPoint); 

       //Left border of non-first column cells should be in gridLine color, and they should be drawn here after bottom border 
       if (e.ColumnIndex > 0) 
        e.Graphics.DrawLine(gridlinePen, topLeftPoint, bottomleftPoint); 

       //We handled painting for this cell, Stop default rendering. 
       e.Handled = true; 
      } 
     } 
    } 
} 
0

Sembra che il EditingControl sia ospitato in un genitore Panel e se si imposta lo stile Opaque su true, il bordo verrà dipinto.

E.g.

void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { 
    var c = e.Control; 
    var p = c.Parent; 
    SetStyles(p, ControlStyles.Opaque, true); 
} 

private static void SetStyles(Control c, ControlStyles styles, bool value) { 
    MethodInfo mi = typeof(Control).GetMethod("SetStyle", BindingFlags.NonPublic | BindingFlags.Instance); 
    mi.Invoke(c, new Object[] { styles, value }); 
} 
+0

Grazie per il tuo commento, l'ho provato e perché quando si imposta lo stile opaco per un controllo, il suo sfondo non dipinge quindi ci sono stati alcuni problemi nel rendering. per esempio quando riduci a icona e la finestra di ripristino, vedrai il problema. La soluzione che uso ancora è quella che ho postato in questo [asnwer] (http://stackoverflow.com/a/32170212/3110834), sarò felice se dai un'occhiata e lo trovi utile :) –