DataGrid Row selection in a VB Form

G

Guest

I am using code from Help with two exceptions. (1) I increased the number of sample rows from 3 to 20, and (2) I anchored the datagrid to bottom of form so that I can change the size of the grid by changing the size of the form

The code is at the following location in the January, 2004 help

ms-help://MS.VSCC.2003/MS.MSDNQTR.2004JAN.1033/cpref/html/frlrfSystemWindowsFormsDataGridClassTopic.ht

You can also find it by doing a search for "DataGrid Class", titles search only. It should show up as Rank #1

The problem occurs when I select a row at the bottom of the grid that is only 80% or so exposed height wise. If I select, Row1, the Debug window indicates that I selected Row #0 as I would expect. The same is true with I select any other row as long as it is fully displayed vertically in the grid.

If I select Row #10 that is only 50% exposed, instead of seeing Row = 9 in the debug window as I would expect, I see Row = 10. Needless to say this behavior is a problem when processing the selected row. Is there a workaround? One solution would be to only display complete rows in the grid rather than partial rows but I can't find a way to do it

For convenience, I am listing my entire code below, you can either paste it into a new form or start with code from help and make the two changes. Thank you very much for any assistance that you can provide

=============================

Option Explicit On
Option Strict O

Imports Syste
Imports System.ComponentMode
Imports System.Dat
Imports System.Drawin
Imports System.Windows.Form

Public Class Form
Inherits System.Windows.Forms.For
Private components As System.ComponentModel.Containe
Private WithEvents button1 As Butto
Private WithEvents button2 As Butto
Private WithEvents myDataGrid As DataGri
Private myDataSet As DataSe
Private TablesAlreadyAdded As Boolea

Public Sub New(
' Required for Windows Form Designer support
InitializeComponent(
' Call SetUp to bind the controls
SetUp(
End Su

Private Sub InitializeComponent(
Me.button1 = New System.Windows.Forms.Butto
Me.button2 = New System.Windows.Forms.Butto
Me.myDataGrid = New System.Windows.Forms.DataGri
CType(Me.myDataGrid, System.ComponentModel.ISupportInitialize).BeginInit(
Me.SuspendLayout(

'button

Me.button1.Location = New System.Drawing.Point(24, 16
Me.button1.Name = "button1
Me.button1.Size = New System.Drawing.Size(120, 24
Me.button1.TabIndex =
Me.button1.Text = "Change Appearance

'button

Me.button2.Location = New System.Drawing.Point(150, 16
Me.button2.Name = "button2
Me.button2.Size = New System.Drawing.Size(120, 24
Me.button2.TabIndex =
Me.button2.Text = "Get Binding Manager

'myDataGri

Me.myDataGrid.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom)
Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles
Me.myDataGrid.CaptionText = "Microsoft DataGrid Control
Me.myDataGrid.DataMember = "
Me.myDataGrid.HeaderForeColor = System.Drawing.SystemColors.ControlTex
Me.myDataGrid.Location = New System.Drawing.Point(24, 50
Me.myDataGrid.Name = "myDataGrid
Me.myDataGrid.Size = New System.Drawing.Size(300, 200
Me.myDataGrid.TabIndex =

'Form

Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13
Me.ClientSize = New System.Drawing.Size(450, 330
Me.Controls.Add(Me.button1
Me.Controls.Add(Me.button2
Me.Controls.Add(Me.myDataGrid
Me.Name = "Form1
Me.Text = "DataGrid Control Sample
CType(Me.myDataGrid, System.ComponentModel.ISupportInitialize).EndInit(
Me.ResumeLayout(False

End Su

Public Shared Sub Main(
Application.Run(New Form1
End Su

Private Sub SetUp(
' Create a DataSet with two tables and one relation
MakeDataSet(
' Bind the DataGrid to the DataSet. The dataMembe
' specifies that the Customers table should be displayed
myDataGrid.SetDataBinding(myDataSet, "Customers"
End Su

Protected Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Clic
If TablesAlreadyAdded = True Then Exit Sub
AddCustomDataTableStyle()
End Sub

Private Sub AddCustomDataTableStyle()
Dim ts1 As New DataGridTableStyle
ts1.MappingName = "Customers"
' Set other properties.
ts1.AlternatingBackColor = Color.LightGray
' Add a GridColumnStyle and set its MappingName
' to the name of a DataColumn in the DataTable.
' Set the HeaderText and Width properties.

Dim boolCol As New DataGridBoolColumn
boolCol.MappingName = "Current"
boolCol.HeaderText = "IsCurrent Customer"
boolCol.Width = 150
ts1.GridColumnStyles.Add(boolCol)

' Add a second column style.
Dim TextCol As New DataGridTextBoxColumn
TextCol.MappingName = "custName"
TextCol.HeaderText = "Customer Name"
TextCol.Width = 250
ts1.GridColumnStyles.Add(TextCol)

' Create the second table style with columns.
Dim ts2 As New DataGridTableStyle
ts2.MappingName = "Orders"

' Set other properties.
ts2.AlternatingBackColor = Color.LightBlue

' Create new ColumnStyle objects
Dim cOrderDate As New DataGridTextBoxColumn
cOrderDate.MappingName = "OrderDate"
cOrderDate.HeaderText = "Order Date"
cOrderDate.Width = 100
ts2.GridColumnStyles.Add(cOrderDate)

' Use a PropertyDescriptor to create a formatted
' column. First get the PropertyDescriptorCollection
' for the data source and data member.
Dim pcol As PropertyDescriptorCollection = _
Me.BindingContext(myDataSet, "Customers.custToOrders"). _
GetItemProperties()

' Create a formatted column using a PropertyDescriptor.
' The formatting character "c" specifies a currency format. */

Dim csOrderAmount As _
New DataGridTextBoxColumn(pcol("OrderAmount"), "c", True)
csOrderAmount.MappingName = "OrderAmount"
csOrderAmount.HeaderText = "Total"
csOrderAmount.Width = 100
ts2.GridColumnStyles.Add(csOrderAmount)

' Add the DataGridTableStyle instances to
' the GridTableStylesCollection.
myDataGrid.TableStyles.Add(ts1)
myDataGrid.TableStyles.Add(ts2)

' Sets the TablesAlreadyAdded to true so this doesn't happen again.
TablesAlreadyAdded = True
End Sub

Protected Sub button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button2.Click
Dim bmGrid As BindingManagerBase
bmGrid = BindingContext(myDataSet, "Customers")
MessageBox.Show(("Current BindingManager Position: " & bmGrid.Position))
End Sub

Private Sub Grid_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles myDataGrid.MouseUp
' Create a HitTestInfo object using the HitTest method.
' Get the DataGrid by casting sender.
Dim myGrid As DataGrid = CType(sender, DataGrid)
Dim myHitInfo As DataGrid.HitTestInfo = myGrid.HitTest(e.X, e.Y)
Console.WriteLine(myHitInfo)
Console.WriteLine(myHitInfo.Type)
Console.WriteLine(myHitInfo.Row)
Console.WriteLine(myHitInfo.Column)
End Sub

' Create a DataSet with two tables and populate it.
Private Sub MakeDataSet()
' Create a DataSet.
myDataSet = New DataSet("myDataSet")

' Create two DataTables.
Dim tCust As New DataTable("Customers")
Dim tOrders As New DataTable("Orders")

' Create two columns, and add them to the first table.
Dim cCustID As New DataColumn("CustID", GetType(Integer))
Dim cCustName As New DataColumn("CustName")
Dim cCurrent As New DataColumn("Current", GetType(Boolean))
tCust.Columns.Add(cCustID)
tCust.Columns.Add(cCustName)
tCust.Columns.Add(cCurrent)

' Create three columns, and add them to the second table.
Dim cID As New DataColumn("CustID", GetType(Integer))
Dim cOrderDate As New DataColumn("orderDate", GetType(DateTime))
Dim cOrderAmount As New DataColumn("OrderAmount", GetType(Decimal))
tOrders.Columns.Add(cOrderAmount)
tOrders.Columns.Add(cID)
tOrders.Columns.Add(cOrderDate)

' Add the tables to the DataSet.
myDataSet.Tables.Add(tCust)
myDataSet.Tables.Add(tOrders)

' Create a DataRelation, and add it to the DataSet.
Dim dr As New DataRelation("custToOrders", cCustID, cID)
myDataSet.Relations.Add(dr)

' Populates the tables. For each customer and order,
' creates two DataRow variables.
Dim newRow1 As DataRow
Dim newRow2 As DataRow

' Create three customers in the Customers Table.
Dim i As Integer
For i = 1 To 30
newRow1 = tCust.NewRow()
newRow1("custID") = i
' Add the row to the Customers table.
tCust.Rows.Add(newRow1)
Next i
' Give each customer a distinct name.
tCust.Rows(0)("custName") = "Customer1"
tCust.Rows(1)("custName") = "Customer2"
tCust.Rows(2)("custName") = "Customer3"

' Give the Current column a value.
tCust.Rows(0)("Current") = True
tCust.Rows(1)("Current") = True
tCust.Rows(2)("Current") = False

' For each customer, create five rows in the Orders table.
For i = 1 To 3
Dim j As Integer
For j = 1 To 5
newRow2 = tOrders.NewRow()
newRow2("CustID") = i
newRow2("orderDate") = New DateTime(2001, i, j * 2)
newRow2("OrderAmount") = i * 10 + j * 0.1
' Add the row to the Orders table.
tOrders.Rows.Add(newRow2)
Next j
Next i
End Sub
End Class
 
C

Cor

Hi Genojoe,

I get the answers when I push on the button, that I think there should be,
can you explain again what should be the error?



Cor
 
G

Guest

When I execute this application in Debug, I will initially see about 9.25 rows. To make the debug listing shorter, I remarked out 3 of the 4 Console.WriteLine's. If I then click the header records sequentially without scrolling the grid, I get the following listing in Debug

{ RowHeader,0,-1
{ RowHeader,1,-1
{ RowHeader,2,-1
{ RowHeader,3,-1
{ RowHeader,4,-1
{ RowHeader,5,-1
{ RowHeader,6,-1
{ RowHeader,7,-1
{ RowHeader,8,-1
{ RowHeader,10,-1} (record is only partially visible at bottom of page.

The problem occurs at Row #10 because only 25% of it is visible vertically. The last Debug line should be:
{RowHeader,9,-1}. If I scroll the grid with the Vertical scroll bar so that a row is 100% visible before clicking it, there is not a problem. The problem occurs only when a part of the row is hidden at the bottom of the page. The problem occurs if the row is 95% visible

Hope this is clearer. It is a 100% repeatable problem.
 
C

Cor

Hi GenoJoe,

This code

Console.WriteLine(DirectCast(sender, DataGrid).CurrentRowIndex)
Console.WriteLine(myHitInfo.Row)
Console.WriteLine(myHitInfo.Column)

gives with me when row 30 is hardly visible and I click on it in the front
header

29
30
-1

While if is is full visible

29
29
-1

Was that what you did mean?

Cor
 
G

Guest

You are on the money. I assume you know that you solved my problem. Is it fair to say that Microsoft has a slight quirk in the way it handles the clicking of a partial row? When I look at the Object Browser what I see suggests that Info.Row and Grid.CurrentRowIndex should result in the same value. Lines below are from Object browser. The lesson is to use CurrentRowIndex and realize that Info.Row is not accurate in all cases.

Thank you.

Row() As Integer
Summary:
Gets the number of the row the user has clicked.

CurrentRowIndex() As Integer
Summary:
Gets or sets index of the selected row.
 
G

Guest

I have now learned more about this problem. First, my goal was to perform some operations based upon the row header being clicked. My problem was with the sample code. It uses a mouse up event. By changing to a mouse down event, my problem disappeared. If this sample code used the mouse-down event, this series of messages would never have occurred

Regarding using CurrentRowIndex, at first it looked like a good solution. Later I realized that it is not a good solution. If a person clicks the + or - in the row header, the row does not change and reflects the previously selected row and not the clicked row. Not the behavior that I want
 

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