Freeze Column in DataGrid

  • Thread starter Thread starter Agnes
  • Start date Start date
A

Agnes

I understand it is impossible, but still curious to know "Can I freeze
several column in the datagrid, the user can only scroll the first 3 columns
(not verical), for the rest of the coulumn, it is freeze.
 
Hi,

Here is a column style that locks a column on the datagrid. It is
still under development. basically if you set the locked property to true
it places a panel over the datagrid that has the locked column drawn on it.
Currently it only will lock the first column.

Imports System.Drawing.Drawing2D

Public Class ColoredGridColumn

Inherits DataGridTextBoxColumn

Dim mForeColor As Color = Color.Black

Dim mBackColor As Color = Color.White

Dim WithEvents mctrl As DblBufferPanel

Dim WithEvents dg As DataGrid

Dim pt As New Point

Dim bPanelOnly As Boolean = False

Dim cm As CurrencyManager

Dim ar As Boolean

Private Class DblBufferPanel

Inherits Panel

Public Sub New()

Me.SetStyle(ControlStyles.DoubleBuffer, True)

End Sub

End Class

Public Property ForeColor() As Color

Get

Return mForeColor

End Get

Set(ByVal Value As Color)

mForeColor = Value

End Set

End Property

Public Property BackColor() As Color

Get

Return mBackColor

End Get

Set(ByVal Value As Color)

mBackColor = Value

End Set

End Property

Public Property Locked() As Boolean

Get

Return Not mctrl Is Nothing

End Get

Set(ByVal Value As Boolean)

If Value = False Then

mctrl = Nothing

Else

mctrl = New DblBufferPanel

End If

End Set

End Property

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)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Static bPainted As Boolean = False

If Not bPainted And Not (mctrl Is Nothing) Then

dg = Me.DataGridTableStyle.DataGrid

dg.Parent.Controls.Add(mctrl)

MovePanel()

mctrl.BringToFront()

pt = dg.GetCellBounds(0, 0).Location

If TypeOf dg.DataSource Is DataTable Then

AddHandler DirectCast(dg.DataSource, DataTable).DefaultView.ListChanged,
AddressOf dv_ListChanged

ElseIf TypeOf dg.DataSource Is DataView Then

AddHandler DirectCast(dg.DataSource, DataView).ListChanged, AddressOf
dv_ListChanged

End If

End If

cm = source

ar = alignToRight

bPainted = True

If Me.DataGridTableStyle.DataGrid.IsSelected(rowNum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If Not bPanelOnly Then

MyBase.Paint(g, bounds, source, rowNum, brBack, brFore, alignToRight)

End If

If Not (mctrl Is Nothing) Then

' if there is another control to draw on move the bounds to the right edge
if htere is not then it will ignore that directive right? yesgot oitf the
control

'mctrl.BackgroundImage = bm

PaintRow(mctrl.CreateGraphics, bounds, rowNum)

End If

If Me.GetColumnValueAtRow(source, rowNum).ToString = "Davolio" Then

Me.DataGridTableStyle.DataGrid.Select(rowNum)

End If

End Sub

Public Shadows Sub BeginUpdate()

MyBase.BeginUpdate()

End Sub

Public Shadows Sub EndUpdate()

MyBase.EndUpdate()

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)

MyBase.TextBox.ForeColor = ForeColor()

MyBase.TextBox.BackColor = BackColor

End Sub

Public Sub New()

End Sub

Private Sub dg_Scroll(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Scroll

Trace.WriteLine("Scroll")

RedrawPanel()

End Sub

Private Sub MovePanel()

mctrl.Location = New Point(dg.Left + dg.RowHeaderWidth + 2, dg.Top + 21)

Dim intFactor As Integer = SystemInformation.HorizontalScrollBarHeight

For Each ctrl As Control In Me.DataGridTableStyle.DataGrid.Controls

If TypeOf ctrl Is HScrollBar Then

If Not DirectCast(ctrl, HScrollBar).Visible Then intFactor = 0

End If

Next

mctrl.Height = dg.Height - 21 - intFactor - 2

End Sub

Private Sub dg_Move(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Move

MovePanel()

End Sub

Private Sub PreparePanel()

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = mctrl.CreateGraphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Catch

End Try

End Sub

Private Sub dv_ListChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.ListChangedEventArgs)

'PreparePanel()

RedrawPanel()

End Sub

Private Sub dg_VisibleChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.VisibleChanged

Try

mctrl.Visible = dg.Visible

Catch ex As Exception

End Try

End Sub

Private Sub dg_SizeChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.SizeChanged

MovePanel()

RedrawPanel()

End Sub

Private Sub RedrawPanel()

Static oldTop As Integer = 0

If Not mctrl Is Nothing And dg.VisibleRowCount > 0 Then

Application.DoEvents()

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

bPanelOnly = False

End If

End Sub

Private Sub dg_Resize(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Resize

MovePanel()

End Sub

Private Sub mctrl_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles mctrl.Paint

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = e.Graphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Debug.WriteLine("Panel Paint")

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Dim oldTop As Integer

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

Catch

End Try

End Sub

Private Sub PaintRow(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal
rownum As Integer)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Dim bounds2 As New Rectangle(0, bounds.Y - 21, bounds.Width, bounds.Height)

If Me.DataGridTableStyle.DataGrid.IsSelected(rownum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If mctrl.Width <> Me.Width Then mctrl.Width = Me.Width

MyBase.Paint(g, bounds2, cm, rownum, _

brBack, brFore, ar)

If rownum = cm.Count - 1 Then

Dim br As New SolidBrush(Me.DataGridTableStyle.DataGrid.BackgroundColor)

g.FillRectangle(br, 0, bounds2.Bottom + 1, mctrl.Width, _

mctrl.Height - bounds2.Bottom - 1)

End If

End Sub

End Class



Ken
 
This is nothing short of amazing work Ken.



Ken Tucker said:
Hi,

Here is a column style that locks a column on the datagrid. It is

still under development. basically if you set the locked property to true

it places a panel over the datagrid that has the locked column drawn on
it.
Currently it only will lock the first column.

Imports System.Drawing.Drawing2D

Public Class ColoredGridColumn

Inherits DataGridTextBoxColumn

Dim mForeColor As Color = Color.Black

Dim mBackColor As Color = Color.White

Dim WithEvents mctrl As DblBufferPanel

Dim WithEvents dg As DataGrid

Dim pt As New Point

Dim bPanelOnly As Boolean = False

Dim cm As CurrencyManager

Dim ar As Boolean

Private Class DblBufferPanel

Inherits Panel

Public Sub New()

Me.SetStyle(ControlStyles.DoubleBuffer, True)

End Sub

End Class

Public Property ForeColor() As Color

Get

Return mForeColor

End Get

Set(ByVal Value As Color)

mForeColor = Value

End Set

End Property

Public Property BackColor() As Color

Get

Return mBackColor

End Get

Set(ByVal Value As Color)

mBackColor = Value

End Set

End Property

Public Property Locked() As Boolean

Get

Return Not mctrl Is Nothing

End Get

Set(ByVal Value As Boolean)

If Value = False Then

mctrl = Nothing

Else

mctrl = New DblBufferPanel

End If

End Set

End Property

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)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Static bPainted As Boolean = False

If Not bPainted And Not (mctrl Is Nothing) Then

dg = Me.DataGridTableStyle.DataGrid

dg.Parent.Controls.Add(mctrl)

MovePanel()

mctrl.BringToFront()

pt = dg.GetCellBounds(0, 0).Location

If TypeOf dg.DataSource Is DataTable Then

AddHandler DirectCast(dg.DataSource, DataTable).DefaultView.ListChanged,

AddressOf dv_ListChanged

ElseIf TypeOf dg.DataSource Is DataView Then

AddHandler DirectCast(dg.DataSource, DataView).ListChanged, AddressOf
dv_ListChanged

End If

End If

cm = source

ar = alignToRight

bPainted = True

If Me.DataGridTableStyle.DataGrid.IsSelected(rowNum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,

0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,

1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If Not bPanelOnly Then

MyBase.Paint(g, bounds, source, rowNum, brBack, brFore, alignToRight)

End If

If Not (mctrl Is Nothing) Then

' if there is another control to draw on move the bounds to the right edge

if htere is not then it will ignore that directive right? yesgot oitf the

control

'mctrl.BackgroundImage = bm

PaintRow(mctrl.CreateGraphics, bounds, rowNum)

End If

If Me.GetColumnValueAtRow(source, rowNum).ToString = "Davolio" Then

Me.DataGridTableStyle.DataGrid.Select(rowNum)

End If

End Sub

Public Shadows Sub BeginUpdate()

MyBase.BeginUpdate()

End Sub

Public Shadows Sub EndUpdate()

MyBase.EndUpdate()

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)

MyBase.TextBox.ForeColor = ForeColor()

MyBase.TextBox.BackColor = BackColor

End Sub

Public Sub New()

End Sub

Private Sub dg_Scroll(ByVal sender As Object, ByVal e As System.EventArgs)

Handles dg.Scroll

Trace.WriteLine("Scroll")

RedrawPanel()

End Sub

Private Sub MovePanel()

mctrl.Location = New Point(dg.Left + dg.RowHeaderWidth + 2, dg.Top + 21)

Dim intFactor As Integer = SystemInformation.HorizontalScrollBarHeight

For Each ctrl As Control In Me.DataGridTableStyle.DataGrid.Controls

If TypeOf ctrl Is HScrollBar Then

If Not DirectCast(ctrl, HScrollBar).Visible Then intFactor = 0

End If

Next

mctrl.Height = dg.Height - 21 - intFactor - 2

End Sub

Private Sub dg_Move(ByVal sender As Object, ByVal e As System.EventArgs)

Handles dg.Move

MovePanel()

End Sub

Private Sub PreparePanel()

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = mctrl.CreateGraphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Catch

End Try

End Sub

Private Sub dv_ListChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.ListChangedEventArgs)

'PreparePanel()

RedrawPanel()

End Sub

Private Sub dg_VisibleChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.VisibleChanged

Try

mctrl.Visible = dg.Visible

Catch ex As Exception

End Try

End Sub

Private Sub dg_SizeChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.SizeChanged

MovePanel()

RedrawPanel()

End Sub

Private Sub RedrawPanel()

Static oldTop As Integer = 0

If Not mctrl Is Nothing And dg.VisibleRowCount > 0 Then

Application.DoEvents()

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,

dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x,
dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

bPanelOnly = False

End If

End Sub

Private Sub dg_Resize(ByVal sender As Object, ByVal e As System.EventArgs)

Handles dg.Resize

MovePanel()

End Sub

Private Sub mctrl_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles mctrl.Paint

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = e.Graphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Debug.WriteLine("Panel Paint")

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Dim oldTop As Integer

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,

dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x,
dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

Catch

End Try

End Sub

Private Sub PaintRow(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal

rownum As Integer)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Dim bounds2 As New Rectangle(0, bounds.Y - 21, bounds.Width,
bounds.Height)

If Me.DataGridTableStyle.DataGrid.IsSelected(rownum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,

0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,

1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If mctrl.Width <> Me.Width Then mctrl.Width = Me.Width

MyBase.Paint(g, bounds2, cm, rownum, _

brBack, brFore, ar)

If rownum = cm.Count - 1 Then

Dim br As New SolidBrush(Me.DataGridTableStyle.DataGrid.BackgroundColor)

g.FillRectangle(br, 0, bounds2.Bottom + 1, mctrl.Width, _

mctrl.Height - bounds2.Bottom - 1)

End If

End Sub

End Class



Ken

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

I understand it is impossible, but still curious to know "Can I freeze
several column in the datagrid, the user can only scroll the first 3
columns
(not verical), for the rest of the coulumn, it is freeze.
 
I am looking for the same function in a web application (using a web form
data grid). The application uses C# and heaps of data grids that have the
first one or two columns populated with data that would be nice to have
remain visable as the user scrolls horizontally. Of course, it would also be
nice to have the headings remain visable as the user scrolls down the grid as
well.

I had a quick look at Ken's code (although I am not a VB person), but it
seems the DataGridTextBoxColumn is only part of the Windows Form data grid.
So was wondering if anyone can give me any help with this.

Cheers,

Ken Tucker said:
Hi,

Here is a column style that locks a column on the datagrid. It is
still under development. basically if you set the locked property to true
it places a panel over the datagrid that has the locked column drawn on it.
Currently it only will lock the first column.

Imports System.Drawing.Drawing2D

Public Class ColoredGridColumn

Inherits DataGridTextBoxColumn

Dim mForeColor As Color = Color.Black

Dim mBackColor As Color = Color.White

Dim WithEvents mctrl As DblBufferPanel

Dim WithEvents dg As DataGrid

Dim pt As New Point

Dim bPanelOnly As Boolean = False

Dim cm As CurrencyManager

Dim ar As Boolean

Private Class DblBufferPanel

Inherits Panel

Public Sub New()

Me.SetStyle(ControlStyles.DoubleBuffer, True)

End Sub

End Class

Public Property ForeColor() As Color

Get

Return mForeColor

End Get

Set(ByVal Value As Color)

mForeColor = Value

End Set

End Property

Public Property BackColor() As Color

Get

Return mBackColor

End Get

Set(ByVal Value As Color)

mBackColor = Value

End Set

End Property

Public Property Locked() As Boolean

Get

Return Not mctrl Is Nothing

End Get

Set(ByVal Value As Boolean)

If Value = False Then

mctrl = Nothing

Else

mctrl = New DblBufferPanel

End If

End Set

End Property

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)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Static bPainted As Boolean = False

If Not bPainted And Not (mctrl Is Nothing) Then

dg = Me.DataGridTableStyle.DataGrid

dg.Parent.Controls.Add(mctrl)

MovePanel()

mctrl.BringToFront()

pt = dg.GetCellBounds(0, 0).Location

If TypeOf dg.DataSource Is DataTable Then

AddHandler DirectCast(dg.DataSource, DataTable).DefaultView.ListChanged,
AddressOf dv_ListChanged

ElseIf TypeOf dg.DataSource Is DataView Then

AddHandler DirectCast(dg.DataSource, DataView).ListChanged, AddressOf
dv_ListChanged

End If

End If

cm = source

ar = alignToRight

bPainted = True

If Me.DataGridTableStyle.DataGrid.IsSelected(rowNum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If Not bPanelOnly Then

MyBase.Paint(g, bounds, source, rowNum, brBack, brFore, alignToRight)

End If

If Not (mctrl Is Nothing) Then

' if there is another control to draw on move the bounds to the right edge
if htere is not then it will ignore that directive right? yesgot oitf the
control

'mctrl.BackgroundImage = bm

PaintRow(mctrl.CreateGraphics, bounds, rowNum)

End If

If Me.GetColumnValueAtRow(source, rowNum).ToString = "Davolio" Then

Me.DataGridTableStyle.DataGrid.Select(rowNum)

End If

End Sub

Public Shadows Sub BeginUpdate()

MyBase.BeginUpdate()

End Sub

Public Shadows Sub EndUpdate()

MyBase.EndUpdate()

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)

MyBase.TextBox.ForeColor = ForeColor()

MyBase.TextBox.BackColor = BackColor

End Sub

Public Sub New()

End Sub

Private Sub dg_Scroll(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Scroll

Trace.WriteLine("Scroll")

RedrawPanel()

End Sub

Private Sub MovePanel()

mctrl.Location = New Point(dg.Left + dg.RowHeaderWidth + 2, dg.Top + 21)

Dim intFactor As Integer = SystemInformation.HorizontalScrollBarHeight

For Each ctrl As Control In Me.DataGridTableStyle.DataGrid.Controls

If TypeOf ctrl Is HScrollBar Then

If Not DirectCast(ctrl, HScrollBar).Visible Then intFactor = 0

End If

Next

mctrl.Height = dg.Height - 21 - intFactor - 2

End Sub

Private Sub dg_Move(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Move

MovePanel()

End Sub

Private Sub PreparePanel()

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = mctrl.CreateGraphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Catch

End Try

End Sub

Private Sub dv_ListChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.ListChangedEventArgs)

'PreparePanel()

RedrawPanel()

End Sub

Private Sub dg_VisibleChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.VisibleChanged

Try

mctrl.Visible = dg.Visible

Catch ex As Exception

End Try

End Sub

Private Sub dg_SizeChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.SizeChanged

MovePanel()

RedrawPanel()

End Sub

Private Sub RedrawPanel()

Static oldTop As Integer = 0

If Not mctrl Is Nothing And dg.VisibleRowCount > 0 Then

Application.DoEvents()

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

bPanelOnly = False

End If

End Sub

Private Sub dg_Resize(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Resize

MovePanel()

End Sub

Private Sub mctrl_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles mctrl.Paint

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = e.Graphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Debug.WriteLine("Panel Paint")

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Dim oldTop As Integer

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

Catch

End Try

End Sub

Private Sub PaintRow(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal
rownum As Integer)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Dim bounds2 As New Rectangle(0, bounds.Y - 21, bounds.Width, bounds.Height)

If Me.DataGridTableStyle.DataGrid.IsSelected(rownum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If mctrl.Width <> Me.Width Then mctrl.Width = Me.Width

MyBase.Paint(g, bounds2, cm, rownum, _

brBack, brFore, ar)

If rownum = cm.Count - 1 Then

Dim br As New SolidBrush(Me.DataGridTableStyle.DataGrid.BackgroundColor)

g.FillRectangle(br, 0, bounds2.Bottom + 1, mctrl.Width, _

mctrl.Height - bounds2.Bottom - 1)

End If

End Sub

End Class



Ken

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

I understand it is impossible, but still curious to know "Can I freeze
several column in the datagrid, the user can only scroll the first 3 columns
(not verical), for the rest of the coulumn, it is freeze.
 
Hi James,
For a web application you'd do this with client script:
http://www.codeproject.com/aspnet/FreezePaneDatagrid.asp

Marcie

I am looking for the same function in a web application (using a web form
data grid). The application uses C# and heaps of data grids that have the
first one or two columns populated with data that would be nice to have
remain visable as the user scrolls horizontally. Of course, it would also be
nice to have the headings remain visable as the user scrolls down the grid as
well.

I had a quick look at Ken's code (although I am not a VB person), but it
seems the DataGridTextBoxColumn is only part of the Windows Form data grid.
So was wondering if anyone can give me any help with this.

Cheers,

Ken Tucker said:
Hi,

Here is a column style that locks a column on the datagrid. It is
still under development. basically if you set the locked property to true
it places a panel over the datagrid that has the locked column drawn on it.
Currently it only will lock the first column.

Imports System.Drawing.Drawing2D

Public Class ColoredGridColumn

Inherits DataGridTextBoxColumn

Dim mForeColor As Color = Color.Black

Dim mBackColor As Color = Color.White

Dim WithEvents mctrl As DblBufferPanel

Dim WithEvents dg As DataGrid

Dim pt As New Point

Dim bPanelOnly As Boolean = False

Dim cm As CurrencyManager

Dim ar As Boolean

Private Class DblBufferPanel

Inherits Panel

Public Sub New()

Me.SetStyle(ControlStyles.DoubleBuffer, True)

End Sub

End Class

Public Property ForeColor() As Color

Get

Return mForeColor

End Get

Set(ByVal Value As Color)

mForeColor = Value

End Set

End Property

Public Property BackColor() As Color

Get

Return mBackColor

End Get

Set(ByVal Value As Color)

mBackColor = Value

End Set

End Property

Public Property Locked() As Boolean

Get

Return Not mctrl Is Nothing

End Get

Set(ByVal Value As Boolean)

If Value = False Then

mctrl = Nothing

Else

mctrl = New DblBufferPanel

End If

End Set

End Property

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)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Static bPainted As Boolean = False

If Not bPainted And Not (mctrl Is Nothing) Then

dg = Me.DataGridTableStyle.DataGrid

dg.Parent.Controls.Add(mctrl)

MovePanel()

mctrl.BringToFront()

pt = dg.GetCellBounds(0, 0).Location

If TypeOf dg.DataSource Is DataTable Then

AddHandler DirectCast(dg.DataSource, DataTable).DefaultView.ListChanged,
AddressOf dv_ListChanged

ElseIf TypeOf dg.DataSource Is DataView Then

AddHandler DirectCast(dg.DataSource, DataView).ListChanged, AddressOf
dv_ListChanged

End If

End If

cm = source

ar = alignToRight

bPainted = True

If Me.DataGridTableStyle.DataGrid.IsSelected(rowNum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If Not bPanelOnly Then

MyBase.Paint(g, bounds, source, rowNum, brBack, brFore, alignToRight)

End If

If Not (mctrl Is Nothing) Then

' if there is another control to draw on move the bounds to the right edge
if htere is not then it will ignore that directive right? yesgot oitf the
control

'mctrl.BackgroundImage = bm

PaintRow(mctrl.CreateGraphics, bounds, rowNum)

End If

If Me.GetColumnValueAtRow(source, rowNum).ToString = "Davolio" Then

Me.DataGridTableStyle.DataGrid.Select(rowNum)

End If

End Sub

Public Shadows Sub BeginUpdate()

MyBase.BeginUpdate()

End Sub

Public Shadows Sub EndUpdate()

MyBase.EndUpdate()

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)

MyBase.TextBox.ForeColor = ForeColor()

MyBase.TextBox.BackColor = BackColor

End Sub

Public Sub New()

End Sub

Private Sub dg_Scroll(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Scroll

Trace.WriteLine("Scroll")

RedrawPanel()

End Sub

Private Sub MovePanel()

mctrl.Location = New Point(dg.Left + dg.RowHeaderWidth + 2, dg.Top + 21)

Dim intFactor As Integer = SystemInformation.HorizontalScrollBarHeight

For Each ctrl As Control In Me.DataGridTableStyle.DataGrid.Controls

If TypeOf ctrl Is HScrollBar Then

If Not DirectCast(ctrl, HScrollBar).Visible Then intFactor = 0

End If

Next

mctrl.Height = dg.Height - 21 - intFactor - 2

End Sub

Private Sub dg_Move(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Move

MovePanel()

End Sub

Private Sub PreparePanel()

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = mctrl.CreateGraphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Catch

End Try

End Sub

Private Sub dv_ListChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.ListChangedEventArgs)

'PreparePanel()

RedrawPanel()

End Sub

Private Sub dg_VisibleChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.VisibleChanged

Try

mctrl.Visible = dg.Visible

Catch ex As Exception

End Try

End Sub

Private Sub dg_SizeChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.SizeChanged

MovePanel()

RedrawPanel()

End Sub

Private Sub RedrawPanel()

Static oldTop As Integer = 0

If Not mctrl Is Nothing And dg.VisibleRowCount > 0 Then

Application.DoEvents()

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

bPanelOnly = False

End If

End Sub

Private Sub dg_Resize(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Resize

MovePanel()

End Sub

Private Sub mctrl_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles mctrl.Paint

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = e.Graphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Debug.WriteLine("Panel Paint")

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Dim oldTop As Integer

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

Catch

End Try

End Sub

Private Sub PaintRow(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal
rownum As Integer)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Dim bounds2 As New Rectangle(0, bounds.Y - 21, bounds.Width, bounds.Height)

If Me.DataGridTableStyle.DataGrid.IsSelected(rownum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If mctrl.Width <> Me.Width Then mctrl.Width = Me.Width

MyBase.Paint(g, bounds2, cm, rownum, _

brBack, brFore, ar)

If rownum = cm.Count - 1 Then

Dim br As New SolidBrush(Me.DataGridTableStyle.DataGrid.BackgroundColor)

g.FillRectangle(br, 0, bounds2.Bottom + 1, mctrl.Width, _

mctrl.Height - bounds2.Bottom - 1)

End If

End Sub

End Class



Ken

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

I understand it is impossible, but still curious to know "Can I freeze
several column in the datagrid, the user can only scroll the first 3 columns
(not verical), for the rest of the coulumn, it is freeze.
 
Thanks Marcie, I have had a look at the link and will try what it suggests
today. Thank you for the kindness to take the time to reply and help.

Cheers,
Jamie (James)

Marcie Jones said:
Hi James,
For a web application you'd do this with client script:
http://www.codeproject.com/aspnet/FreezePaneDatagrid.asp

Marcie

I am looking for the same function in a web application (using a web form
data grid). The application uses C# and heaps of data grids that have the
first one or two columns populated with data that would be nice to have
remain visable as the user scrolls horizontally. Of course, it would also be
nice to have the headings remain visable as the user scrolls down the grid as
well.

I had a quick look at Ken's code (although I am not a VB person), but it
seems the DataGridTextBoxColumn is only part of the Windows Form data grid.
So was wondering if anyone can give me any help with this.

Cheers,

Ken Tucker said:
Hi,

Here is a column style that locks a column on the datagrid. It is
still under development. basically if you set the locked property to true
it places a panel over the datagrid that has the locked column drawn on it.
Currently it only will lock the first column.

Imports System.Drawing.Drawing2D

Public Class ColoredGridColumn

Inherits DataGridTextBoxColumn

Dim mForeColor As Color = Color.Black

Dim mBackColor As Color = Color.White

Dim WithEvents mctrl As DblBufferPanel

Dim WithEvents dg As DataGrid

Dim pt As New Point

Dim bPanelOnly As Boolean = False

Dim cm As CurrencyManager

Dim ar As Boolean

Private Class DblBufferPanel

Inherits Panel

Public Sub New()

Me.SetStyle(ControlStyles.DoubleBuffer, True)

End Sub

End Class

Public Property ForeColor() As Color

Get

Return mForeColor

End Get

Set(ByVal Value As Color)

mForeColor = Value

End Set

End Property

Public Property BackColor() As Color

Get

Return mBackColor

End Get

Set(ByVal Value As Color)

mBackColor = Value

End Set

End Property

Public Property Locked() As Boolean

Get

Return Not mctrl Is Nothing

End Get

Set(ByVal Value As Boolean)

If Value = False Then

mctrl = Nothing

Else

mctrl = New DblBufferPanel

End If

End Set

End Property

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)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Static bPainted As Boolean = False

If Not bPainted And Not (mctrl Is Nothing) Then

dg = Me.DataGridTableStyle.DataGrid

dg.Parent.Controls.Add(mctrl)

MovePanel()

mctrl.BringToFront()

pt = dg.GetCellBounds(0, 0).Location

If TypeOf dg.DataSource Is DataTable Then

AddHandler DirectCast(dg.DataSource, DataTable).DefaultView.ListChanged,
AddressOf dv_ListChanged

ElseIf TypeOf dg.DataSource Is DataView Then

AddHandler DirectCast(dg.DataSource, DataView).ListChanged, AddressOf
dv_ListChanged

End If

End If

cm = source

ar = alignToRight

bPainted = True

If Me.DataGridTableStyle.DataGrid.IsSelected(rowNum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If Not bPanelOnly Then

MyBase.Paint(g, bounds, source, rowNum, brBack, brFore, alignToRight)

End If

If Not (mctrl Is Nothing) Then

' if there is another control to draw on move the bounds to the right edge
if htere is not then it will ignore that directive right? yesgot oitf the
control

'mctrl.BackgroundImage = bm

PaintRow(mctrl.CreateGraphics, bounds, rowNum)

End If

If Me.GetColumnValueAtRow(source, rowNum).ToString = "Davolio" Then

Me.DataGridTableStyle.DataGrid.Select(rowNum)

End If

End Sub

Public Shadows Sub BeginUpdate()

MyBase.BeginUpdate()

End Sub

Public Shadows Sub EndUpdate()

MyBase.EndUpdate()

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)

MyBase.TextBox.ForeColor = ForeColor()

MyBase.TextBox.BackColor = BackColor

End Sub

Public Sub New()

End Sub

Private Sub dg_Scroll(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Scroll

Trace.WriteLine("Scroll")

RedrawPanel()

End Sub

Private Sub MovePanel()

mctrl.Location = New Point(dg.Left + dg.RowHeaderWidth + 2, dg.Top + 21)

Dim intFactor As Integer = SystemInformation.HorizontalScrollBarHeight

For Each ctrl As Control In Me.DataGridTableStyle.DataGrid.Controls

If TypeOf ctrl Is HScrollBar Then

If Not DirectCast(ctrl, HScrollBar).Visible Then intFactor = 0

End If

Next

mctrl.Height = dg.Height - 21 - intFactor - 2

End Sub

Private Sub dg_Move(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Move

MovePanel()

End Sub

Private Sub PreparePanel()

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = mctrl.CreateGraphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Catch

End Try

End Sub

Private Sub dv_ListChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.ListChangedEventArgs)

'PreparePanel()

RedrawPanel()

End Sub

Private Sub dg_VisibleChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.VisibleChanged

Try

mctrl.Visible = dg.Visible

Catch ex As Exception

End Try

End Sub

Private Sub dg_SizeChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.SizeChanged

MovePanel()

RedrawPanel()

End Sub

Private Sub RedrawPanel()

Static oldTop As Integer = 0

If Not mctrl Is Nothing And dg.VisibleRowCount > 0 Then

Application.DoEvents()

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

bPanelOnly = False

End If

End Sub

Private Sub dg_Resize(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Resize

MovePanel()

End Sub

Private Sub mctrl_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles mctrl.Paint

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = e.Graphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Debug.WriteLine("Panel Paint")

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Dim oldTop As Integer

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

Catch

End Try

End Sub

Private Sub PaintRow(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal
rownum As Integer)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Dim bounds2 As New Rectangle(0, bounds.Y - 21, bounds.Width, bounds.Height)

If Me.DataGridTableStyle.DataGrid.IsSelected(rownum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If mctrl.Width <> Me.Width Then mctrl.Width = Me.Width

MyBase.Paint(g, bounds2, cm, rownum, _

brBack, brFore, ar)

If rownum = cm.Count - 1 Then

Dim br As New SolidBrush(Me.DataGridTableStyle.DataGrid.BackgroundColor)

g.FillRectangle(br, 0, bounds2.Bottom + 1, mctrl.Width, _

mctrl.Height - bounds2.Bottom - 1)

End If

End Sub

End Class



Ken

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

I understand it is impossible, but still curious to know "Can I freeze
several column in the datagrid, the user can only scroll the first 3 columns
(not verical), for the rest of the coulumn, it is freeze.
 
vb.net 2003

hi thankx for the tip i am new to vb.net 2003 and had the same requirement.
but my prob is i am very new to vb.net 2003 and can u pls. guide me how to call for this clase ?? i mean how do i use it......pls. help me out with this....

thankx a lot for ur help...

Ken Tucker [MVP] said:
Hi,

Here is a column style that locks a column on the datagrid. It is
still under development. basically if you set the locked property to true
it places a panel over the datagrid that has the locked column drawn on it.
Currently it only will lock the first column.

Imports System.Drawing.Drawing2D

Public Class ColoredGridColumn

Inherits DataGridTextBoxColumn

Dim mForeColor As Color = Color.Black

Dim mBackColor As Color = Color.White

Dim WithEvents mctrl As DblBufferPanel

Dim WithEvents dg As DataGrid

Dim pt As New Point

Dim bPanelOnly As Boolean = False

Dim cm As CurrencyManager

Dim ar As Boolean

Private Class DblBufferPanel

Inherits Panel

Public Sub New()

Me.SetStyle(ControlStyles.DoubleBuffer, True)

End Sub

End Class

Public Property ForeColor() As Color

Get

Return mForeColor

End Get

Set(ByVal Value As Color)

mForeColor = Value

End Set

End Property

Public Property BackColor() As Color

Get

Return mBackColor

End Get

Set(ByVal Value As Color)

mBackColor = Value

End Set

End Property

Public Property Locked() As Boolean

Get

Return Not mctrl Is Nothing

End Get

Set(ByVal Value As Boolean)

If Value = False Then

mctrl = Nothing

Else

mctrl = New DblBufferPanel

End If

End Set

End Property

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)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Static bPainted As Boolean = False

If Not bPainted And Not (mctrl Is Nothing) Then

dg = Me.DataGridTableStyle.DataGrid

dg.Parent.Controls.Add(mctrl)

MovePanel()

mctrl.BringToFront()

pt = dg.GetCellBounds(0, 0).Location

If TypeOf dg.DataSource Is DataTable Then

AddHandler DirectCast(dg.DataSource, DataTable).DefaultView.ListChanged,
AddressOf dv_ListChanged

ElseIf TypeOf dg.DataSource Is DataView Then

AddHandler DirectCast(dg.DataSource, DataView).ListChanged, AddressOf
dv_ListChanged

End If

End If

cm = source

ar = alignToRight

bPainted = True

If Me.DataGridTableStyle.DataGrid.IsSelected(rowNum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If Not bPanelOnly Then

MyBase.Paint(g, bounds, source, rowNum, brBack, brFore, alignToRight)

End If

If Not (mctrl Is Nothing) Then

' if there is another control to draw on move the bounds to the right edge
if htere is not then it will ignore that directive right? yesgot oitf the
control

'mctrl.BackgroundImage = bm

PaintRow(mctrl.CreateGraphics, bounds, rowNum)

End If

If Me.GetColumnValueAtRow(source, rowNum).ToString = "Davolio" Then

Me.DataGridTableStyle.DataGrid.Select(rowNum)

End If

End Sub

Public Shadows Sub BeginUpdate()

MyBase.BeginUpdate()

End Sub

Public Shadows Sub EndUpdate()

MyBase.EndUpdate()

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)

MyBase.TextBox.ForeColor = ForeColor()

MyBase.TextBox.BackColor = BackColor

End Sub

Public Sub New()

End Sub

Private Sub dg_Scroll(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Scroll

Trace.WriteLine("Scroll")

RedrawPanel()

End Sub

Private Sub MovePanel()

mctrl.Location = New Point(dg.Left + dg.RowHeaderWidth + 2, dg.Top + 21)

Dim intFactor As Integer = SystemInformation.HorizontalScrollBarHeight

For Each ctrl As Control In Me.DataGridTableStyle.DataGrid.Controls

If TypeOf ctrl Is HScrollBar Then

If Not DirectCast(ctrl, HScrollBar).Visible Then intFactor = 0

End If

Next

mctrl.Height = dg.Height - 21 - intFactor - 2

End Sub

Private Sub dg_Move(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Move

MovePanel()

End Sub

Private Sub PreparePanel()

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = mctrl.CreateGraphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Catch

End Try

End Sub

Private Sub dv_ListChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.ListChangedEventArgs)

'PreparePanel()

RedrawPanel()

End Sub

Private Sub dg_VisibleChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.VisibleChanged

Try

mctrl.Visible = dg.Visible

Catch ex As Exception

End Try

End Sub

Private Sub dg_SizeChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles dg.SizeChanged

MovePanel()

RedrawPanel()

End Sub

Private Sub RedrawPanel()

Static oldTop As Integer = 0

If Not mctrl Is Nothing And dg.VisibleRowCount > 0 Then

Application.DoEvents()

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

bPanelOnly = False

End If

End Sub

Private Sub dg_Resize(ByVal sender As Object, ByVal e As System.EventArgs)
Handles dg.Resize

MovePanel()

End Sub

Private Sub mctrl_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles mctrl.Paint

Dim sf As New StringFormat

sf.LineAlignment = StringAlignment.Center

Dim rDraw As New RectangleF(0, 0, Me.Width, 20)

Dim g As Graphics = e.Graphics

g.Clear(mctrl.BackColor)

Try

g.DrawString(Me.HeaderText, dg.Font, Brushes.Black, rDraw, sf)

ControlPaint.DrawBorder3D(g, _

New Rectangle(0, 0, Me.Width, 19), Border3DStyle.RaisedInner)

Debug.WriteLine("Panel Paint")

Dim hti As DataGrid.HitTestInfo = dg.HitTest(pt)

Dim newRow As Integer = hti.Row

Dim oldTop As Integer

Trace.WriteLine(String.Format("First Row {0} Visible rows {1}", hti.Row,
dg.VisibleRowCount))

oldTop = newRow

bPanelOnly = True

For x As Integer = oldTop To oldTop + dg.VisibleRowCount - 1

If x < cm.Count Then

Trace.WriteLine(String.Format("Drawing Row {0} {1}", x, dg.GetCellBounds(x,
dg.FirstVisibleColumn)))

Paint(Nothing, dg.GetCellBounds(x, dg.FirstVisibleColumn), _

cm, x, Nothing, Nothing, ar)

End If

Next

Catch

End Try

End Sub

Private Sub PaintRow(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal
rownum As Integer)

Dim brFore As Brush

Dim brBack As Brush

Dim cFore As Color

Dim cBack As Color

Dim bounds2 As New Rectangle(0, bounds.Y - 21, bounds.Width, bounds.Height)

If Me.DataGridTableStyle.DataGrid.IsSelected(rownum) Then

cFore = Me.DataGridTableStyle.SelectionForeColor

cBack = Me.DataGridTableStyle.SelectionBackColor

Else

cFore = ForeColor

cBack = BackColor

End If

brBack = New LinearGradientBrush(bounds, cBack, Color.White, 90, False)

brFore = New SolidBrush(cFore)



Dim bl As New Blend

bl.Factors = New Single() {0.0F, 0.1F, 0.5F, 0.7F, 0.7F, 0.5F, 0.3F, 0.2F,
0}

bl.Positions = New Single() {0, 0.1F, 0.2F, 0.5F, 0.6F, 0.7F, 0.8F, 0.9F,
1.0F}

DirectCast(brBack, LinearGradientBrush).Blend = bl

If mctrl.Width <> Me.Width Then mctrl.Width = Me.Width

MyBase.Paint(g, bounds2, cm, rownum, _

brBack, brFore, ar)

If rownum = cm.Count - 1 Then

Dim br As New SolidBrush(Me.DataGridTableStyle.DataGrid.BackgroundColor)

g.FillRectangle(br, 0, bounds2.Bottom + 1, mctrl.Width, _

mctrl.Height - bounds2.Bottom - 1)

End If

End Sub

End Class



Ken

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

"Agnes" wrote in message
news:[email protected]...
I understand it is impossible, but still curious to know "Can I freeze
several column in the datagrid, the user can only scroll the first 3 columns
(not verical), for the rest of the coulumn, it is freeze.
 
Back
Top