Datagrid resizing rows on sort - not wanted

S

skOOb33

I successfully autosized the columns and rows on my Datagrid, and am
now facing another issue. Having the sorting ability by clicking the
column headers is key, but when I do that, it resizes all my rows back
to their defaults. I populate the datagrid, resize it accordingly and
it works fine...just when I click the headers is when it messes up. It
would be fine if I could run my autosizing again after the sorting is
done since there won't be more than 50 rows usually, but I haven't been
able to figure that out.

I know when the user clicks on a column header, but when I run the
autosizing on the mouseup of that click, it just doesnt take. I see
the datagrid flicker with the right row heights, but it just always
goes right back to default. Any ideas on how to keep all the rows the
same size when a user clicks the column heading for sorting?
 
K

Ken Tucker [MVP]

Hi,

When you sort the datagrid sets the row height back to the default
row height. They way I get around it is that I set the default row height
for all the rows to the biggest height and manually resize all the rows.

Imports System.Drawing

Imports System.Drawing.Drawing2D

Imports System.Windows.Forms

Imports System.Reflection

Imports System.ComponentModel

<DataSysDescription("This column style displays more than one line of
text")> _

Public Class MultiLineColumn

Inherits HotTrackTextBoxColumn

Private mTxtAlign As HorizontalAlignment

Private mDrawTxt As New StringFormat

Private mbAdjustHeight As Boolean = True

Private m_intPreEditHeight As Integer

Private m_rownum As Integer

Dim WithEvents dg As DataGrid

Private arHeights As ArrayList

Dim WithEvents cm As CurrencyManager

Dim mbTrack As Boolean = True

Public Property HotTrack() As Boolean

Get

Return mbTrack

End Get

Set(ByVal Value As Boolean)

mbTrack = Value

End Set

End Property

Private Sub GetHeightList()

Dim mi As MethodInfo = dg.GetType().GetMethod("get_DataGridRows",
BindingFlags.FlattenHierarchy Or BindingFlags.IgnoreCase Or
BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public Or
BindingFlags.Static)

Dim dgra As Array = CType(mi.Invoke(Me.dg, Nothing), Array)

arHeights = New ArrayList

Dim dgRowHeight As Object

For Each dgRowHeight In dgra

If dgRowHeight.ToString().EndsWith("DataGridRelationshipRow") = True Then

arHeights.Add(dgRowHeight)

End If

Next

End Sub



Public Sub New()

mTxtAlign = HorizontalAlignment.Left

mDrawTxt.Alignment = StringAlignment.Near

End Sub

Protected Overloads Overrides Sub Edit(ByVal source As
System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal bounds
As System.Drawing.Rectangle, ByVal [readOnly] As Boolean, ByVal instantText
As String, ByVal cellIsVisible As Boolean)

MyBase.Edit(source, rowNum, bounds, [readOnly], instantText, cellIsVisible)

Me.TextBox.TextAlign = mTxtAlign

Me.TextBox.Multiline = mbAdjustHeight

Debug.WriteLine(rowNum)

'If rowNum >= iRows Then

For x As Integer = 0 To arHeights.Count - 1

Dim pi As PropertyInfo = arHeights(x).GetType().GetProperty("Height")

Dim curHeight As Integer = CInt(pi.GetValue(arHeights(x), Nothing))

pi.SetValue(arHeights(x), curHeight, Nothing)

Next

Dim sz As Size = dg.Size

dg.Size = New Size(sz.Width - 1, sz.Height - 1)

dg.Size = sz

GetHeightList()

End Sub

Protected Overloads Overrides Sub Paint(ByVal g As System.Drawing.Graphics,
ByVal bounds As System.Drawing.Rectangle, ByVal source As
System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal
backBrush As System.Drawing.Brush, ByVal foreBrush As System.Drawing.Brush,
ByVal alignToRight As Boolean)

Static bPainted As Boolean = False

If Not bPainted Then

MyBase.Paint(g, bounds, source, rowNum, foreBrush, backBrush, alignToRight)

dg = Me.DataGridTableStyle.DataGrid

GetHeightList()

End If

cm = source

'clear the cell

g.FillRectangle(backBrush, bounds)

'draw the value

Dim s As String = Me.GetColumnValueAtRow([source], rowNum).ToString()

Dim r As New RectangleF(bounds.X, bounds.Y, bounds.Width, bounds.Height)

r.Inflate(-2, -2)

' get the height column should be

Dim sDraw As SizeF = g.MeasureString(s, Me.TextBox.Font, Me.Width, mDrawTxt)

Dim h As Integer = CInt(sDraw.Height) + 15

If mbAdjustHeight Then

AdjustHeight(h)

End If

g.DrawString(s, MyBase.TextBox.Font, foreBrush, r, mDrawTxt)

bPainted = True

If mbTrack = True And Me.MouseOverCell(rowNum) Then

g.DrawRectangle(New Pen(SystemColors.HotTrack), r.Left, r.Top, r.Width,
r.Height)

End If

End Sub

<DataSysDescription("Automatically increase height of column")> _

Public Property AutoAdjustHeight() As Boolean

Get

Return mbAdjustHeight

End Get

Set(ByVal Value As Boolean)

mbAdjustHeight = Value

Try

dg.Invalidate()

Catch

End Try

End Set

End Property





Private Sub cm_PositionChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles cm.PositionChanged

Static intOld As Integer = 0



If cm.Count > DirectCast(dg.DataSource, DataTable).Rows.Count Then

For x As Integer = 0 To arHeights.Count - 1

Dim pi As PropertyInfo = arHeights(x).GetType().GetProperty("Height")

Dim curHeight As Integer = CInt(pi.GetValue(arHeights(x), Nothing))

pi.SetValue(arHeights(x), curHeight, Nothing)

Next

Dim sz As Size = dg.Size

dg.Size = New Size(sz.Width - 1, sz.Height - 1)

dg.Size = sz

End If

intOld = cm.Position

End Sub

Private Sub AdjustHeight(ByVal h As Integer)

Dim curHeight As Integer = Me.DataGridTableStyle.PreferredRowHeight

If h > curHeight Then

'

' Manually set all the row heights to the new height

'

Me.DataGridTableStyle.PreferredRowHeight = h

Trace.WriteLine(h)

If arHeights.Count < cm.Count Then

GetHeightList()

End If

For rownum As Integer = 0 To cm.Count - 1

Try

Dim pi As PropertyInfo

pi = arHeights(rownum).GetType().GetProperty("Height")

' adjust height

If h > curHeight Then

pi.SetValue(arHeights(rownum), h, Nothing)

End If

Catch

' something wrong leave default height

Debug.WriteLine("Error")

End Try

Next

'

' Resize datagrid to get scrollbars to work right

'

Dim sz As Size = dg.Size

dg.Size = New Size(New Point(sz.Width - 1, sz.Height - 1))

dg.Size = sz

End If

End Sub

<DataSysDescription("Suspends painting of column until EndUpdate is
called")> _

Public Shadows Sub BeginUpdate()

MyBase.BeginUpdate()

End Sub

<DataSysDescription("Resumes painting of column")> _

Public Shadows Sub EndUpdate()

MyBase.EndUpdate()

End Sub

End Class



Ken

--------------------

I successfully autosized the columns and rows on my Datagrid, and am
now facing another issue. Having the sorting ability by clicking the
column headers is key, but when I do that, it resizes all my rows back
to their defaults. I populate the datagrid, resize it accordingly and
it works fine...just when I click the headers is when it messes up. It
would be fine if I could run my autosizing again after the sorting is
done since there won't be more than 50 rows usually, but I haven't been
able to figure that out.

I know when the user clicks on a column header, but when I run the
autosizing on the mouseup of that click, it just doesnt take. I see
the datagrid flicker with the right row heights, but it just always
goes right back to default. Any ideas on how to keep all the rows the
same size when a user clicks the column heading for sorting?
 
S

skOOb33

A couple questions. Can that class just inherit the
DataGridTextBoxColumn, or just the HotTrackTextBoxColumn? Also, there
seems to be no function named MouseOverCell() given, but is used in the
Paint method. Any clarification is appreciated. Thanks.
 
K

Ken Tucker [MVP]

Hi,

Sorry you can use datagridtextbox column instead of the
hottracktextbox column and get rid of the line with mouseovercell. But here
is Hottracktextboxcolumn in case you want it. It will highlight the cell
the mouse is over.


Imports System.Drawing

Imports System.Drawing.Drawing2D

Imports System.Windows.Forms

Imports System.Reflection

Imports System.ComponentModel

Public Class HotTrackTextBoxColumn

Inherits DataGridTextBoxColumn

Dim c As Integer

Dim rectPaint As New RectangleF

Dim fnt As New Font(MyBase.TextBox.Font.Name, MyBase.TextBox.Font.Size,
FontStyle.Underline)

Dim WithEvents dg As DataGrid

Dim oldCell As New Point(-1, -1)

Dim isInCell As Boolean = False

Public Sub HandleMouseMove(ByVal sender As Object, ByVal e As
MouseEventArgs) Handles dg.MouseMove

Dim g As Graphics = dg.CreateGraphics

Dim bounds As Rectangle

Dim hti As DataGrid.HitTestInfo = dg.HitTest(New Point(e.X, e.Y))

isInCell = (hti.Row > -1 And hti.Column = c)

Static bRedraw As Boolean = False

If isInCell Then

Dim pt As Point

pt = New Point(hti.Row, hti.Column)

If Not pt.Equals(oldCell) Then

'

' Create a region where we want the datagrid to redraw

' So the datagrid doesn't flash.

'

Dim pthToRedraw As New Drawing2D.GraphicsPath

Dim rgnToRedraw As Region

Dim rCell As Rectangle = dg.GetCellBounds(pt.X, pt.Y)

pthToRedraw.AddRectangle(rCell)

If oldCell.X > -1 Then

'

' Have to redraw last cell

'

pthToRedraw.AddRectangle(dg.GetCellBounds(oldCell.X, oldCell.Y))

End If

rgnToRedraw = New Region(pthToRedraw)

dg.Invalidate(rgnToRedraw)

End If

'

' Flag datagrid for redraw

'

bRedraw = True

oldCell = pt

Else

'

' Only redraw when needed

'

If bRedraw Then

dg.Invalidate(dg.GetCellBounds(oldCell.X, oldCell.Y))

End If

bRedraw = False

oldCell = New Point(-1, -1)

End If

End Sub



Protected Overloads Overrides Sub Paint(ByVal g As System.Drawing.Graphics,
ByVal bounds As System.Drawing.Rectangle, ByVal source As
System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal
backBrush As System.Drawing.Brush, ByVal foreBrush As System.Drawing.Brush,
ByVal alignToRight As Boolean)

Static bPainted As Boolean = False

'

' First time we paint get a reference to datagrid

' So we can consume its events

'

If Not bPainted Then

dg = Me.DataGridTableStyle.DataGrid

c = -1

For Each grdCol As DataGridColumnStyle In
Me.DataGridTableStyle.GridColumnStyles

c += 1

If grdCol.MappingName = Me.MappingName Then Exit For

Next

End If

bPainted = True

MyBase.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight)

Dim pnHot As New Pen(SystemColors.HotTrack)

Dim brHot As New SolidBrush(Color.FromArgb(128, SystemColors.HotTrack))

' see through brush

If MouseOverCell(rowNum) Then

bounds.Inflate(-1, -1)

g.FillRectangle(brHot, bounds)

g.DrawRectangle(pnHot, bounds)

End If



Dim r As New RectangleF(bounds.X, bounds.Y, bounds.Width, bounds.Height)

rectPaint = r

End Sub

Public ReadOnly Property MouseOverCell(ByVal rownum As Integer) As Boolean

Get

Dim pt As New Point(rownum, c)

Return pt.Equals(oldCell)

End Get

End Property

End Class



Ken

---------------------


A couple questions. Can that class just inherit the
DataGridTextBoxColumn, or just the HotTrackTextBoxColumn? Also, there
seems to be no function named MouseOverCell() given, but is used in the
Paint method. Any clarification is appreciated. Thanks.
 
S

skOOb33

Thanks. All I did to rectify the issue was set a timer for 1/2 a
second to resize the rows after the sort. It isn't as good as I wanted
because there is a slight flicker after you sort. I wasn't able to
resize at the right time/event without the timer. I put your HotTrack
to use, and it's a pretty cool feature. Probably won't fly with the
"higher-ups" for now, but probably with one of my next projects.
Thanks. If you have any ideas on a seemless autosizing after sorting,
I would be interested.

thx
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top