הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Saturday, March 3, 2018 10:51 AM
Hi
I have a Datagridview and I add a buttom to a column header
I would like to anchor this buttom to the right of the column as the column is resized
This is my code
Public Sub Addbuttom(ByRef DGV As DataGridView)
Dim btn As New Button
btn.BackColor = Color.Red
btn.Text = "F"
btn.Height = 20
btn.Width = 20
Dim r As Rectangle = DGV.GetCellDisplayRectangle(3, -1, False)
Dim btnx As Integer = r.X + r.Width - 30
Dim btny As Integer = (r.Y / 2) + 8
Dim btnloc As New Point(btnx, btny)
btn.Location = btnloc
DGV.Controls.Add(btn)
End Sub
How to do that ?
Thanks
Claudio
All replies (23)
Saturday, March 3, 2018 11:58 AM | 1 vote
Hi
Using the same code as previous thread, but altered to anchor button1 to right of column header.
Dim started As Boolean = False
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
If Not started Then Exit Sub
Dim r As Rectangle = DataGridView1.GetCellDisplayRectangle(3, -1, False)
Button1.Location = New Point(r.Right - Button1.Width, r.Top)
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
started = True
End Sub
Regards Les, Livingston, Scotland
Saturday, March 3, 2018 12:16 PM
ah ok,
one more think
What to do to delete the button for each column header ?
I have a Button (filter) on the form
First time i click the Filter button , I show several buttons for each column header
If I click again the Filter button I want to delete the buttons from each column header
Saturday, March 3, 2018 12:28 PM
Hi Leshay
The anchor does not work if the user resize form or Column
The button stay in the same position and do not follow the column header right margin
Saturday, March 3, 2018 12:31 PM
Hi
You say you want to delete the buttons, maybe, rather than delete you could set the Button.Visible to False instead.
You could have a Boolean Flag which you toggle in the Filter and in the Form.Resize (or where ever you are setting the Button Locations), set the Button.Visible = Flag (show or not show).
Regards Les, Livingston, Scotland
Saturday, March 3, 2018 12:46 PM
What are the buttons for?
Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator
Saturday, March 3, 2018 1:35 PM
Thanks Leshay, buttom Visible problem solved !
Saturday, March 3, 2018 1:48 PM
Hi Karen
I will use each button on column header to filer trows, as the image below
Now I still have the proble how to anchor the button to the right of each column header
Saturday, March 3, 2018 2:21 PM
Hi
EDIT: ignore my posts, I misunderstood your aims.
Here is a different approach. Try this as a stand alone new test project and see if it works as you need. It uses 3 buttons for Header cell display (1.2 and3) and Button22 to toggle Button2 on/off. Each of the buttons for header display need their .Tag property set to "hc".
Designer
Code
Option Strict On
Option Explicit On
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
With DataGridView1
.Location = New Point(10, 10)
.Size = New Size(ClientSize.Width - 60, ClientSize.Height - 50)
.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
End With
End Sub
Private Sub DataGridView1_CellPainting(ByVal sender As System.Object, ByVal e As DataGridViewCellPaintingEventArgs) Handles DataGridView1.CellPainting
If e.RowIndex = -1 AndAlso e.ColumnIndex = 3 Then
Dim x As Integer = 0
For Each c As Control In Controls
If c.Visible AndAlso c.Tag Is "hc" Then
c.Location = New Point(DataGridView1.Left + e.CellBounds.Right - x - c.Width, DataGridView1.Top + e.CellBounds.Top + 2)
x += c.Width
End If
Next
End If
End Sub
Private Sub Button22_Click(sender As Object, e As EventArgs) Handles Button22.Click
' here, I toggle Button2 only - you can
'toggle any/all as needed here.
Button2.Visible = Not Button2.Visible
DataGridView1.Invalidate()
End Sub
End Class
Regards Les, Livingston, Scotland
Saturday, March 3, 2018 3:02 PM
An alternate (which I have used in a app I created in 2003 and still in use) is the following which requires two (or is it three) lines of code.
Here is vb.net my demo back from 2013. The demo does some basic and advance filtering.
Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator
Saturday, March 3, 2018 3:49 PM
Karen I know this solution and i will use it later.
The difference is that it use a Mouse right click to open the filter Panels
I would like to use a button on the column header instead of If I use the the Mouse right click
So now I dont know which event to use to re-locate the buttons
If I use the ColumnWidthChanged i cannot get the header width and hight that I need to re-calculate the button position
Saturday, March 3, 2018 4:13 PM
HI Les
The problem is that the CellPainting event is raised for each cell of dgv.
So with 10.000 rows and 20 columns I get 200.000 calls to the event
mmmmmm not too good ! ;.(
Saturday, March 3, 2018 4:35 PM
HI Les
The problem is that the CellPainting event is raised for each cell of dgv.
So with 10.000 rows and 20 columns I get 200.000 calls to the event
mmmmmm not too good ! ;.(
Hi
Well, the cell paint event is called anyway as the system paints the cells (visible cells),and, the code I posted only intercepts the column header row, and only on selected column indexes.
So, not so bad after all.
Regards Les, Livingston, Scotland
Saturday, March 3, 2018 5:50 PM
Okay. In the mean time I tinkered with a custom DataGridView as shown below, the buttons are added in the custom DataGridView. Press the filter button (at this time) displays a text box to enter a filter.
Not worth sharing especially since this is in C#. If you don't get a solution I will look at this in a week as I'm heading to Microsoft all next week and will not have much time to play with this.
Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator
Saturday, March 3, 2018 7:11 PM
You can create a custom header cell which contains a button. This will allow you to maintain the sort glyph and will handle things like horizontal scrolling when the columns exceed the display area. Here is an example of how you can go about doing this.
Public Class DataGridViewButtonHeaderCell
Inherits DataGridViewColumnHeaderCell
Public Event HeaderButtonClick As EventHandler
' button size will be column height minus this amount, square
Public Property ButtonOffset As Integer = 2
Private buttonBounds As Rectangle 'store button bounds
Private isMouseDown As Boolean 'track mouse down over button for drawing button state
Private lastSize As Size 'track column size to ignore size changes
Private sortDirection As ComponentModel.ListSortDirection 'track sort direction for displaying sort gylph
' helper method to determine if button is clicked
Private Function IsPointInButtonBounds(value As Point, columnIndex As Integer) As Boolean
Return buttonBounds.Contains(value + Me.DataGridView.GetColumnDisplayRectangle(columnIndex, True).Location - New Point(Me.DataGridView.HorizontalScrollingOffset, 0))
End Function
Protected Overrides Sub OnDataGridViewChanged()
MyBase.OnDataGridViewChanged()
' need to programmaticaly control sorting so that clicking the button doesn't cause a sort
If Me.DataGridView IsNot Nothing Then
Me.DataGridView.Columns.Item(Me.ColumnIndex).SortMode = DataGridViewColumnSortMode.Programmatic
AddHandler Me.DataGridView.Sorted, Sub(sender As Object, e As EventArgs)
If sender Is Me.DataGridView Then
If Me.DataGridView.SortedColumn IsNot Me.DataGridView.Columns.Item(Me.ColumnIndex) Then
Me.SortGlyphDirection = SortOrder.None
End If
End If
End Sub
lastSize = Me.Size
End If
End Sub
' provide an event to handle for the custom button click
Protected Overridable Sub OnHeaderButtonClick(e As EventArgs)
RaiseEvent HeaderButtonClick(Me, e)
End Sub
' determine if button is being clicked and redraw cell
Protected Overrides Sub OnMouseDown(e As DataGridViewCellMouseEventArgs)
MyBase.OnMouseDown(e)
isMouseDown = IsPointInButtonBounds(e.Location, e.ColumnIndex)
Me.DataGridView.InvalidateCell(Me)
End Sub
Protected Overrides Sub OnMouseUp(e As DataGridViewCellMouseEventArgs)
MyBase.OnMouseUp(e)
If Size = lastSize Then 'ignore column size changes
' if button is being clicked, raise the click event
If IsPointInButtonBounds(e.Location, e.ColumnIndex) Then
OnHeaderButtonClick(EventArgs.Empty)
Else
' otherwise sort the column
Dim column = Me.DataGridView.Columns.Item(e.ColumnIndex)
Dim direction As ComponentModel.ListSortDirection = System.ComponentModel.ListSortDirection.Ascending
If Me.DataGridView.SortedColumn Is column Then direction = If(sortDirection = System.ComponentModel.ListSortDirection.Ascending, ComponentModel.ListSortDirection.Descending, ComponentModel.ListSortDirection.Ascending)
Me.DataGridView.Sort(column, direction)
Me.SortGlyphDirection = If(direction = System.ComponentModel.ListSortDirection.Ascending, SortOrder.Ascending, SortOrder.Descending)
sortDirection = direction
End If
End If
isMouseDown = False
Me.DataGridView.InvalidateCell(Me)
End Sub
Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, elementState As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
' store the current button size
lastSize = Size
' calculate the button bounds
buttonBounds = New Rectangle(cellBounds.Right - cellBounds.Height, cellBounds.Top + ButtonOffset, cellBounds.Height - ButtonOffset * 2, cellBounds.Height - ButtonOffset * 2)
' paint background and border to erase previous contents
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background Or DataGridViewPaintParts.Border)
' paint custom button
ControlPaint.DrawButton(graphics, buttonBounds, If(isMouseDown, ButtonState.Pushed, ButtonState.Normal))
'TODO: draw something in the button if desired
'resize cell to exclude button area
cellBounds.Width -= buttonBounds.Width + ButtonOffset
'perform default painting of the header cell within the modified bounds
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
End Sub
End Class
When the form loads you can assign an instance of this custom header cell to whatever columns you choose:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' choose a column
Dim column = DataGridView1.Columns.Item(0)
' create a new custom button header cell
Dim headerCell As New DataGridViewButtonHeaderCell
' handle the custom button's click event
AddHandler headerCell.HeaderButtonClick, Sub(_sender As Object, _e As EventArgs)
' do something when the button is clicked
MessageBox.Show("button clicked")
End Sub
' set the custom header cell as the column header
column.HeaderCell = headerCell
End Sub
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Saturday, March 3, 2018 7:16 PM
Hi Les
you are right.
I changed a little bit the code as follows. It is supposed that every button has a numeric Tag = column index (that can be set in the DGV1.Controls.Add(btn) )
Private Sub DGV1_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DGV1.CellPainting
If e.RowIndex = -1 And e.ColumnIndex = 0 Then
For Each c As Control In DGV1.Controls
If c.GetType = GetType(Button) Then
Dim index As Integer = c.Tag
Dim r As Rectangle = DGV1.GetCellDisplayRectangle(index, -1, False)
Dim btnx As Integer = r.Right - c.Width
Dim btny As Integer = (r.Y / 2) + 8
Dim btnloc As New Point(btnx, btny)
c.Location = btnloc
End If
Next
End If
End Sub
One more thing. Do you know which event is raised when two columns are splitted ?
Thanks for your help anyway !
Saturday, March 3, 2018 7:39 PM
Hi Karen
I will be glad if you will send me the sample of Custom Datagridview with the buttoms when you will have time to do it
Thanks a Lot
Claudio
Saturday, March 3, 2018 7:53 PM
One more thing. Do you know which event is raised when two columns are splitted ?
Thanks for your help anyway !
Hi
Do you mean when column(s) are Frozen or not?
If that is what you mean, then you must have (say) a button, or perhaps a ContextMenu item that you use to Toggle the Column.Frozen state - in which case, the state can be examined and code called for either Froze/UnFrozen state.
Can't help thinking you mean something else though.
Regards Les, Livingston, Scotland
Saturday, March 3, 2018 8:08 PM
I mean when I move a column before another (of after)
if the AllowsUerToOrderColumns = true
What event is raised when this appens ?
Saturday, March 3, 2018 8:32 PM
I mean when I move a column before another (of after)
if the AllowsUerToOrderColumns = true
What event is raised when this appens ?
Hi
I was correct - you did mean something different :)
Private Sub DataGridView1_ColumnDisplayIndexChanged(sender As Object, e As DataGridViewColumnEventArgs) Handles DataGridView1.ColumnDisplayIndexChanged
Stop
End Sub
Regards Les, Livingston, Scotland
Saturday, March 3, 2018 10:01 PM
The column index does not change if the user exchange the position do two columns
ColumnDisplayIndexChanged
is not the right event to check :-(((
thank you Les
Saturday, March 3, 2018 11:15 PM
The column index does not change if the user exchange the position do two columns
ColumnDisplayIndexChanged
is not the right event to check :-(((
thank you Les
Hi
Pardon me! You said nothing about what you wanted other than an event that is raised 'when I move a column before another (of after)'
Do you really think that we are mind readers in this forum?
Using that event, even though the Column Index remains the same, you get the new DisplayIndex.
For example:
Column(1) Text = "Column1" DisplayIndex=1
after move one column to right,
Column(1) Text = "Column1" DisplayIndex=2
Isn't that what you need?
Furthermore, just think of the consequences of changing the ColumnIndex based on users shifting columns all over the place - how do you propose that the cell addresses of the data is tracked?
Regards Les, Livingston, Scotland
Sunday, March 4, 2018 4:24 PM
Hi Reed
It seems a good solution
I have to study it and test it
Thank you so much
Claudio
Sunday, March 4, 2018 6:06 PM
Hi Reed
one more thing
I set the DataGridViewButtonHeaderCell for each column by a cliking a Button in the Form (Let us call it Btn1) and then loop through all columns in the dgv
I use your code in this way and everything is ok.
For Each col As DataGridViewColumn In DGV.Columns
Dim HeaderCell = New DataGridViewButtonHeaderCell
AddHandler HeaderCell.HeaderButtonClick,
Sub(_sender As Object, _e As EventArgs)
MessageBox.Show("button clicked" & _e.ToString & " " & _sender.ToString)
End Sub
col.HeaderCell = HeaderCell
Next
Now clicking BTN1 again I would like to go back to standard
DataGridViewColumnHeaderCell ( The headercell without the buttons) and I use this code
For Each col As DataGridViewColumn In DGV.Columns
col.HeaderCell = New DataGridViewColumnHeaderCell
Next
I get just one problem
When I pass from ColumnHeaderCell to ButtonHeaderCell the Column.HeaderTexts I set by designer in the DGV, change to DesignName and this of course is a problem
How to keep the Column.HeaderText ?
Thank you for help
Claudio