Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Tuesday, February 10, 2009 10:44 AM
Hi All,
I'm trying to do the following:
I have a datagridview with a fullrowselected selection mode, and I would like to change the full row border when selected, I've tried:
Private
Sub DGCAL_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles DGCAL.CellPainting
If e.RowIndex = DGCAL.CurrentRow.Index Then
e.Paint(e.CellBounds, DataGridViewPaintParts.Border)
Using p = New Pen(Color.Black, 4)
Dim rect As Rectangle = e.CellBounds
rect.Width -= 2
rect.Height -= 2
e.Graphics.DrawRectangle(p, rect)
End Using
e.Handled = True
End If
End Sub
But I get borders in all cells inside the row insted of a single border all over the row, any suggestion would be eternally appreciated.
Thanks in advance
Saturday, February 21, 2009 1:01 PM ✅Answered
Hi George,
you have to handle the RowPrePaint event to prevent the grid from painting the SelectionBackColor over the row's current background.
This is the code from above, which handles this event:
(C#)
private void HandleRowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e) |
{ |
DataGridViewElementStates state; |
state = e.State & DataGridViewElementStates.Selected; |
if (state == DataGridViewElementStates.Selected) |
{ |
e.PaintParts &= // prevent the grid from automatically |
~( // painting the selection background |
DataGridViewPaintParts.Focus | |
DataGridViewPaintParts.SelectionBackground |
); |
} |
} |
(VB)
Private Sub HandleRowPrePaint(ByVal sender As Object, ByVal e As DataGridViewRowPrePaintEventArgs) |
Dim state As DataGridViewElementStates = (e.State And DataGridViewElementStates.Selected) |
If (state = DataGridViewElementStates.Selected) Then |
e.PaintParts = (e.PaintParts And Not (DataGridViewPaintParts.SelectionBackground Or DataGridViewPaintParts.Focus)) |
End If |
End Sub |
I you don't handle this event, the grid will fill a rectangle with the selection background color, which will be painted over the row's current background.
Please tell me, if I'm missing something or if this doesn't solve your problem.
Hope this helps,
franking
Tuesday, February 10, 2009 12:44 PM | 1 vote
Hi,
How about handling the RowPostPaint event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.rowpostpaint.aspx
The argument for this event give you the row bounds, this should allow you to draw a border around the entire row.
http://www.scottlogic.co.uk/blog/wpf/ - my WPF blog
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx - WPF DataGrid Practical Examples
Tuesday, February 10, 2009 1:26 PM | 1 vote
RowPostPaint is the right way. But you still have to prevent the grid from drawing the default selection rectangle.
Use RowPrePaint to prevent the grid from drawing the selection border/background. This can be done by setting the DataGridViewRowPrePaintEventArgs.PaintParts property.
Use RowPostPaint to draw a rectangle around the selected row.
Have a look here http://msdn.microsoft.com/en-us/library/85kxk29c.aspx
Here's a simple example based on the link from above:
using System; |
using System.Windows.Forms; |
using System.Drawing.Drawing2D; |
using System.Data; |
using System.Drawing; |
namespace Tester |
{ |
class CustomRowSelectionPainting:Form |
{ |
DataGridView gridView; // a gridview |
DataTable tbl; // a table with some data |
BindingSource bsData; // a source.. |
const float BORDER_WIDTH=2f; // specify the width of selection border |
int oldCellY = -1; // to invalidate the old row... |
// don't really need this... |
public CustomRowSelectionPainting() |
{ |
gridView = new DataGridView(); // set up the grid and the source |
bsData = new BindingSource(); |
tbl = new DataTable(); |
tbl.Columns.Add("FirstColumn", typeof(String)); // add some columns |
tbl.Columns.Add("SecondColumn", typeof(String)); |
bsData.DataSource = tbl; // connect the table |
gridView.Dock = DockStyle.Fill; // set up the source |
gridView.DataSource = bsData; |
gridView.DefaultCellStyle.SelectionForeColor = SystemColors.WindowText; |
gridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect; |
gridView.CurrentCellChanged += new EventHandler(HandleCurrentCellChanged); |
gridView.RowPostPaint += new DataGridViewRowPostPaintEventHandler(HandleRowPostPaint); |
gridView.RowPrePaint += new DataGridViewRowPrePaintEventHandler(HandleRowPrePaint); |
Controls.Add(gridView); |
} |
private void HandleCurrentCellChanged(object sender, EventArgs e) |
{ |
if (oldCellY != -1) |
{ |
gridView.InvalidateRow(oldCellY); |
} |
oldCellY = gridView.CurrentCellAddress.Y; |
} |
private void HandleRowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e) |
{ |
DataGridViewElementStates state; |
state = e.State & DataGridViewElementStates.Selected; |
if (state == DataGridViewElementStates.Selected) |
{ |
e.PaintParts &= // prevent the grid from automatically |
~( // painting the selection background |
DataGridViewPaintParts.Focus | |
DataGridViewPaintParts.SelectionBackground |
); |
} |
} |
private void HandleRowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) |
{ |
Rectangle rowRect; // a selection rectangle |
DataGridViewElementStates state; |
state = e.State & DataGridViewElementStates.Selected; // only paint on selected row |
if (state == DataGridViewElementStates.Selected) |
{ |
int iBorder = Convert.ToInt32(BORDER_WIDTH); // calculate columns width |
int columnsWidth = gridView.Columns.GetColumnsWidth(DataGridViewElementStates.Visible); |
int xStart = gridView.RowHeadersWidth; |
// need do calculate the clipping rectangle, because you can't use e.RowBounds |
rowRect = |
new Rectangle |
( |
xStart, // start after the row header |
e.RowBounds.Top + iBorder - 1, // at the top of the row |
columnsWidth - gridView.HorizontalScrollingOffset + 1, // get the visible part of the row |
e.RowBounds.Height - iBorder // get the row's height |
); |
// draw the border |
using (Pen pen = new Pen(gridView.DefaultCellStyle.SelectionBackColor, BORDER_WIDTH)) |
{ |
e.Graphics.DrawRectangle(pen, rowRect); // you can't use e.RowBounds here! |
} |
} |
} |
[STAThread] |
public static void Main() |
{ |
Application.EnableVisualStyles(); |
Application.SetCompatibleTextRenderingDefault(false); |
Application.Run(new CustomRowSelectionPainting()); |
} |
} |
} |
Hope this helps,
franking
Saturday, February 14, 2009 12:25 AM
Colin,
Thanks for your reply, I've seen the rowpostpaint event and it works, but it has some rendering problems, if I minimize the program and then maximize it shows inside the square what it was before maximizing it. Also when populating the grid the first row appears in white, I have to click another row to see the firsts' content, any ideas how to solve it ?
Thanks in advance
Saturday, February 14, 2009 12:27 AM
Franking,
Thanks for your reply, I've used your code and it works, but it has some rendering problems, if I minimize the program and then maximize it shows inside the square what it was before maximizing it. Also when populating the grid the first row appears in white, I have to click another row to see the firsts' content, any ideas how to solve it ?
Thanks in advance
Wednesday, February 18, 2009 10:20 PM
C'mon guys, can anybody help me ?
Friday, February 20, 2009 3:45 PM
Hi George,
did you change the DefaultCellStyle.SelectionForeColor ? If you don't change this, the text insinde will be colored white while the background is white as well...So you will end up having white letters on white background.
I tried minimizing and maximizing the window and it's working without rendering problems.
Can you reproduce this with a short example?
regards,
franking
Friday, February 20, 2009 10:41 PM
Thanks Franking, here's what I'm doing:
Private
Sub DGCAL_RowPostPaint(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowPostPaintEventArgs) Handles DGCAL.RowPostPaint
If DGCAL.RowCount > 0 And rowIndexFromMouseDown > -1 Then
If e.RowIndex = DGCAL.CurrentRow.Index Then
Using p = New Pen(Color.Black, 4)
Dim rect As Rectangle = DGCAL.GetRowDisplayRectangle(rowIndexFromMouseDown, True)
rect.Width -= 3
rect.Height -= 3
rect.X += 2
rect.Y += 1
e.Graphics.DrawRectangle(p, rect)
e.Graphics.FillRectangle(Brushes.Transparent, rect)
End Using
End If
End If
End Sub
I'm using on DGCAL:
DefaultCellStyle > ForeColor=Black
DefaultCellStyle > SelectionBackColor=Transparent
DefaultCellStyle > SelectionForeColor=Black
Now, the thing is that if I minimize the program (let's suppose I have in my desktop the Vista classic desktop image) when the program is maximized, I still can see the desktop image in the selectedrow area, I have to select another row to get rid of the desktop image area. Same happens when I pass a program over the selectedrow, let's say I have the program maximized and I pass the messenger or the winamp program over the selected row, the object image remains inside the row.
Another issue, I'm using datagridview to show two lines of production, the DGV starts showing line1, if I select the line 2 (which populates DGV with new values), I still see the first value of the Line 1, I have to select another row to see the first's line 2 value.
In the begginig I thought it was my computer, but I have tested it in 4 pc's already and I stll get the same behavior, that's I call "the rendering problem".
Any suggestion ?
Thanks
Saturday, February 21, 2009 12:38 AM
Hi George,
using Brushes.Transparent will have unexpectable results. The same applies for DefaultCellStyle.SelectionBackColor being set to Color.Transparent. This means, the background will show through and you can't be sure what the background will be. The background can also be the Windows Desktop. I'm sure, this causes parts of the rendering problems. Just drop those commands.
Do you handle the RowPrePaint event? You have to exclude DataGridViewPaintPart.SelectionBackground and DataGridViewPaintPart.Focus from PaintParts, otherwise the background will be painted anyway.
regards,
franking
Saturday, February 21, 2009 10:11 AM
Franking,
I really appreciate your support and time, I have dropped DefaultCellStyle.SelectionBackColor and Brushes.Transparent, it works perfectly but I have a problem, the reason why I was playing with Brushes.Transparent and DefaultCellStyle.SelectionBackColor= Transparent is because my DataGridView has rows with different back colors, these colors are set according to the value of some cell, it could be yellow, red or none and I'm also using AlternatingRowsDefaultCellstyle, if leave the datagridview like you suggested me when you select a row you can't say which color has the selected row because now every selected row's back color will be grey and that's a real problem for me.
I don't handle the RowPrePaint event, is it necessary ?
I was thinking if it's possible to catch the color of the selected row, then use some kind of a brush with alpha, or could you suggest me how to work this out ?
Thanks again for your time.
Monday, February 23, 2009 8:50 AM
Franking,
I just don't know how to thank you, you just solved it !!!!, If you were near I'd buy you some beers !!!!
I leave your solution for someone with the same problem, it works perfectly now:
Private Sub DGCAL_RowPostPaint(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowPostPaintEventArgs) Handles DGCAL.RowPostPaint |
If DGCAL.RowCount > 0 And rowIndexFromMouseDown > -1 Then |
If e.RowIndex = DGCAL.CurrentRow.Index Then |
Using p = New Pen(Color.Black, 4) |
Dim rect As Rectangle = DGCAL.GetRowDisplayRectangle(rowIndexFromMouseDown, True) |
rect.Width -= 3 |
rect.Height -= 3 |
rect.X += 2 |
rect.Y += 1 |
e.Graphics.DrawRectangle(p, rect) |
End Using |
End If |
End If |
End Sub |
Private Sub DGCAL_RowPrePaint(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowPrePaintEventArgs) Handles DGCAL.RowPrePaint |
Dim state As DataGridViewElementStates = (e.State And DataGridViewElementStates.Selected) |
If (state = DataGridViewElementStates.Selected) Then |
e.PaintParts = (e.PaintParts And Not (DataGridViewPaintParts.SelectionBackground Or DataGridViewPaintParts.Focus)) |
End If |
End Sub |
Thanks again !!!!!!!
Thursday, April 14, 2011 1:28 PM
This is another sample in VC++ (same as above, but look better)
System::Void Form1::dg_RowPrePaint(System::Object^ sender, System::Windows::Forms::DataGridViewRowPrePaintEventArgs^ e)
{
bool focus = false;
if ((e->State & DataGridViewElementStates::Selected) == DataGridViewElementStates::Selected)
{
e->PaintParts &= ~(::DataGridViewPaintParts::Focus | ::DataGridViewPaintParts::SelectionBackground);
}
}
System::Void Form1::dg_RowPostPaint(System::Object^ sender, System::Windows::Forms::DataGridViewRowPostPaintEventArgs^ e)
{
if ( dg->RowCount == 0
|| e->RowIndex != dg->CurrentRow->Index
)
{
return;
}
Pen ^ pen = gcnew Pen(Color::Blue, 1.5);
Rectangle rect = dg->GetRowDisplayRectangle(e->RowIndex, true);
rect.Width = Main->Columns->GetColumnsWidth(DataGridViewElementStates::Visible)
- dg->HorizontalScrollingOffset - 2
;
rect.Height -= 2;
rect.X += 0.5;
rect.Y += 0.5;
e->Graphics->DrawRectangle(pen, rect);
}
Tuesday, July 19, 2016 10:37 AM
Hello,
How can change Border Size of Selected Row in datagrid?
Thanks!