Monitoring Datagridview for rows that are being unhidden - vb.net

I've got a a bit of code that is allowing a Results box to pop up, populating a DataGridView with information. The DataGridView uses the same BindingSource that another DataGridView uses, so when one is clicked, the other automatically moves to the same selected cell.
The issue I am having is the Result_DataGridView doesn't always contain all of the same rows as the master DGV, as it hides rows that don't match a criteria. If the user clicks on a cell on the Master DGV that isn't present in the Result DGV, the Result DGV un-hides that row (as you can't hide a selected row).
I'm currently trying to use this method to hide the row that appears again, but because of how VB treats "Entering a cell" it fires before the cell actually appears (as it fires on input focus, but before the cell actually appears in the DGV, so that row never gets checked)
Private Sub Result_Datagridview_CellEnter(sender As Object, e As DataGridViewCellEventArgs) Handles Result_Datagridview.CellEnter
Dim Result As Integer
Dim i
For row As Integer = 0 To Result_Datagridview.RowCount - 1
i = row
Result = Array.Find(ResultArray, Function(x) x = Result_Datagridview.Rows(i).Cells(0).Value)
If Result = 0 Then
Result_Datagridview.Rows(i).Visible = False
End If
Next
End Sub
If there was a ".RowsUnhidden" event, this would work fine.
Note - the ResultArray contains all of the index numbers that need to remain visible, the check is performed to see if any rows exist with an index number that does not appear in the array, if so, hide it again.
Does anyone have a work around or better approach to this?

Handling the RowEnter event, you can suspend the binding and reset row.Visible to False.
So, if ResultArray is an Integer array of visible row indices, you simply do the following:
Private Sub Result_Datagridview_RowEnter(sender As Object, e As DataGridViewCellEventArgs)
If Not ResultArray.Contains(e.RowIndex) Then
Dim currencyManager1 As CurrencyManager = DirectCast(BindingContext(Result_Datagridview.DataSource), CurrencyManager)
currencyManager1.SuspendBinding()
Result_Datagridview.Rows(e.RowIndex).Visible = False
currencyManager1.ResumeBinding()
End If
End Sub

You can look at the DataGridView.CellStateChanged event. It occurs when a cell get the focus, lose it, is selected, ...

Related

Vb.net TableLayoutPanel Rows overlapping while every second alternate row control visible true/false

Small overview:-
(Assuming the row index starts with 1 for better clarity)
I have every odd row (1,3,5...) Drug information.
Every alternate row (2,4,6...) has a special description field which is optional
which i have kept by default visible = false.
So I had kept a button in every first row (1,3,5...) when clicked the appropriate control TextBox (in next row) visible property is assigned true/false (toggle button).
The second row has only one TextBox control.
Hence when TextBox control is false it is expected that the second row height is automatically zero and when its true the appropriate second row should be visible.
I have set all the rows height autosize
Issue:-
When the button is clicked the TextBox comes overlapped on third row (3,5,7....) instead of displaying on its appropriate second row(2,4,6...)
When i set the TextBox default visible = true then it takes every second row correctly. But its unnecessary taking a lot of space. As the TextBox entry is optional as said and not required everytime.
Following are some sreenshots for better more clarity for my issue:-
Fig.1: TableLayout Design
Fig.2: Overlapped on third row instead of taking visible second row
Fig.3: When second row TextBox visible is set true by default
My Code behind the button click:-
Private Sub Button_Drug_Dosage_General_Instructions_Click(
sender As Object, e As EventArgs
) Handles Button_Drug_Dosage_General_Instructions_20.Click,
Button_Drug_Dosage_General_Instructions_19.Click,
Button_Drug_Dosage_General_Instructions_18.Click,
Button_Drug_Dosage_General_Instructions_17.Click,
Button_Drug_Dosage_General_Instructions_16.Click,
Button_Drug_Dosage_General_Instructions_15.Click,
Button_Drug_Dosage_General_Instructions_14.Click,
Button_Drug_Dosage_General_Instructions_13.Click,
Button_Drug_Dosage_General_Instructions_12.Click,
Button_Drug_Dosage_General_Instructions_11.Click,
Button_Drug_Dosage_General_Instructions_10.Click,
Button_Drug_Dosage_General_Instructions_09.Click,
Button_Drug_Dosage_General_Instructions_08.Click,
Button_Drug_Dosage_General_Instructions_07.Click,
Button_Drug_Dosage_General_Instructions_06.Click,
Button_Drug_Dosage_General_Instructions_05.Click,
Button_Drug_Dosage_General_Instructions_04.Click,
Button_Drug_Dosage_General_Instructions_03.Click,
Button_Drug_Dosage_General_Instructions_02.Click,
Button_Drug_Dosage_General_Instructions_01.Click
If Initialization_In_Progress = True Then Exit Sub
'------------------------------------------------------------------------------------------------
'Button_Drug_Dosage_General_Instructions_obj
'------------------------------------------------------------------------------------------------
Dim btn_Button_Drug_Dosage_General_Instructions_obj As Button = CType(sender, Button)
'------------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------------
Dim object_name As String = btn_Button_Drug_Dosage_General_Instructions_obj.Name
Dim xCustomer_Selected_srno As Double = object_name.Substring(object_name.Length - 2)
'------------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------------
Dim txtbox_TextBox_General_Instructions_obj As TextBox = CType(Me.Controls.Find("TextBox_Drug_Dosage_General_Instructions_" + (xCustomer_Selected_srno).ToString("00"), True)(0), TextBox)
'------------------------------------------------------------------------------------------------
If txtbox_TextBox_General_Instructions_obj.Visible = False Then
txtbox_TextBox_General_Instructions_obj.Visible = True
txtbox_TextBox_General_Instructions_obj.SelectionLength = 0
Else
txtbox_TextBox_General_Instructions_obj.Visible = False
End If
End Sub
Hope I have made my best to put the exact issue. If still any further more information is needed I would definately post.
My other workouts:-
Tried TextBox Dock Fill, None, Anchor Top,Left, also all, RowHeight Absolute, but nothing worked.

How to set the CheckBox column in DataGridView value to true

GD All,
I've looking around for a solution to my below challenge.
I have got a form with an unbound datagridview, the dg has one added column that allows user to select a method to be used.
The state of the event is stored in a database and after re-opening the form the code checks if the event is in an 'open' state, if so it compares the previously selected method with the methods in the datagrid and should set the previously activated method to be the 'selected' method.
Yet I can't seem to get this to work unfortunately...
The below code loops through the methods in the dg and compares the values, if it meets the methodID it should set the value to 'True' or to the TrueValue anyway.
This is initialized if the database check returns true and after full initialisation of the form, where session.methodID is a field in the returned LINQ query.
For Each r As DataGridViewRow In dgMethods.Rows
If r.Cells(1).Value = session.methodID Then
Dim c As DataGridViewCheckBoxCell = r.Cells(0)
c.Value = c.TrueValue
End If
Next
Unfortunately, this doesn't set the checkbox to 'Checked'.
The loop runs and evaluates the comparison between r.Cells(1).Value and session.methodID correct and triggers correctly.
The interesting thing is if I do a similar loop after the 'CellContentClick' event it does do exactly what is expected. (the example below sets all checkbox values to checked)
Private Sub dgMethods_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgMethods.CellContentClick
'Only single selection allowed, so clear table before submitting new selection
For Each r As DataGridViewRow In dgMethods.Rows
Dim c As DataGridViewCheckBoxCell = r.Cells(0)
c.Value = c.TrueValue
Next
dgMethods.CommitEdit(DataGridViewDataErrorContexts.Commit)
End Sub
So, apparently there is a difference in the state between just calling the loop on the dgMethods and when the dgMethods.CellContentClick event has triggered, yet I do not know which one ?
There are many many post on trying to set the CheckBox column yet I have not been able to get any of them working.
Anybody have any idea ?
I would appreciate your suggestions ?
I was not sure of being undestand your question... but there's s simple way to check and change the state of a chechbox cell in a datagridview:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each dr As DataGridViewRow In DataGridView1.Rows
If CBool(dr.Cells(0).Value) = True Then dr.Cells(0).Value = False : Continue For
If CBool(dr.Cells(0).Value) = False Then dr.Cells(0).Value = True
Next
End Sub
In this example, when you click this button for each row in the datagridview, checks the checkboxcell and set the value to FALSE or TRUE depending of his value.
Hope this helps you.
And let me one more tip. If you get acces to the cells for his name instead of his index use his name, it should helps you avoiding troubles ;)
GD All,
After searching further I came across the following interesting behaviour.
The method selection process is part of a form called 'frmAddEvent', the frmAddEvent form is called from a main form using below routine.
The new form instance is created and afterwards filled using a public sub in the form class called InitializeForm() which uses a GUID parameter to retrieve corresponding data to set the form fields.
If Not (isOpened(rsTankName.unqID)) Then
Dim newForm As New frmAddEvent() '(rsTankName)
newForm.InitializeForm(rsTankName)
newForm.Show()
Else
End If
The initialization sub queries several datatables and sets the corresponding fields in the new form instance correctly if applicable.
Part of that setting is the method selection in the dgMethods datagridview.
It would appear that the sequence in which you call the form makes all the difference as the below code works perfectly:
If Not (isOpened(rsTankName.unqID)) Then
Dim newForm As New frmAddEvent() '(rsTankName)
newForm.Show()
newForm.InitializeForm(rsTankName)
Else
End If
So calling the newForm.InitializeForm(rsTankName)after the newForm.Show event allows the datagridview to set the CheckBoxColumn correctly.
Likely because the actual CheckBox itself is only actually generated upon the Show command, despite the fact that it is 'available' as a cell with DataGridViewCheckBoxColumn properties in the datagrid, directly after the New frmAddEvent has created the new form instance. The actual CheckBox and its corresponding CheckedState is not created before the newForm.Show event is called. It would appear that the when the CheckBox is created for display (during the newForm.Show event) there is no comparison made to its actual value.
So, in order to set the Checkbox column on initiating a new form you have to call the Show event prior to setting the DataGridViewCheckBoxColumn values otherwise the CheckBox will not show it as 'Checked'.

Moving Data From Databound Listbox To Unbound Listbox And Back VB.NET

So I have been browsing about and there are a lot of explanations on how to move data from listbox to listbox.
I have a listbox bound to a source from my SQL server and another unbound. My aim is to move the data from the first (LBsearch) to the second (LBselect) and back. I have seen people say use
LBselect.Items.Add(LBsearch.SelectedItem) however it doesn't return data and instead shows System.Data.DataRowView. I've tried many different suffixes and all show this apart from LBsearch.text. Then to remove the data from the first one I've been removing the databindingsource (PersonBindingSource) with
PersonBindingSource.Remove(LBsearch.SelectedItem) but my issue is adding the data back again.
PersonBindingSource.Add(LBselect.SelectedItem) gives an error:
System.InvalidOperationException: Objects added to a BindingSource's list must all be of the same type.
at System.Windows.Forms.BindingSource.Add(Object value)
at Project_Program.Participants.btnremoveselect_Click(Object sender, EventArgs e) in E:\Documents\Visual Studio\Project Program\Project Program\Participants.vb:line 39
PersonBindingSource.Add(PersonBindingSource.Item(LBsearch.SelectedIndex))
gives an error:
System.ArgumentException: Cannot add external objects to this list.
at System.Data.DataView.System.Collections.IList.Add(Object value)
at System.Windows.Forms.BindingSource.Add(Object value)
at Project_Program.Participants.btnremoveselect_Click(Object sender, EventArgs e) in E:\Documents\Visual Studio\Project Program\Project Program\Participants.vb:line 38
Any help would be appreciated. Thanks
Private Sub btnaddselect_Click(sender As Object, e As EventArgs) Handles btnaddselect.Click
If LBsearch.Items.Count > 0 Then
MsgBox(LBsearch.Text)
' PersonBindingSource.Remove(PersonBindingSource.Item(LBsearch.SelectedIndex))
LBselect.Items.Add(LBsearch.Text)
PersonBindingSource.Remove(LBsearch.SelectedItem)
' filter()
End If
End Sub
Private Sub btnremoveselect_Click(sender As Object, e As EventArgs) Handles btnremoveselect.Click
If LBselect.Items.Count > 0 Then
Try
'PersonBindingSource.Add(PersonBindingSource.Item(LBsearch.SelectedIndex))
PersonBindingSource.Add(LBselect.SelectedItem)
MsgBox(LBselect.SelectedItem.ToString())
LBselect.Items.Remove(LBselect.SelectedItem)
Catch ex As Exception
TextBox1.Text = (ex.ToString)
End Try
'filter()
End If
End Sub
A major problem with moving rows is that since they are DataRows, they will not display well in the unbound control. If you pull out something useful like a name, you will have to recreate the DataRow to return it to the original/bound/source control.
This is a problem because, now it is a new row, so a DataAdpter might add it to the database again! One way to avoid that is to clone the table. Also, if/when you move them back, they will appear at the bottom of the list and not in their original position.
There is a better way than duplicating the table data and moving anything anywhere.
Since the act of being selected can be represented with a simple Boolean, it can be coded so that the Selected ones show in one control, the unSelected ones in the other. For this, a new Selected column is needed. If possible, add one using your SQL:
' MS Access syntax
Dim SQL = "SELECT a, b, c,..., False As Selected FROM tblFoo"
This will create the new column in your datatable with all the values initialized to False. You can also add the column manually.
' form level vars
Private dvSource As DataView
Private dvDest As DataView
...
' set up:
' *** Add a column manually if you cant use SQL
dtSample.Columns.Add("Selected", GetType(Boolean))
' we need to loop and set the initial value for an added column
For Each r As DataRow In dtSample.Rows
r("Selected") = False
Next
' *** end of code for adding col manually
' when the column is added from SQL, you will need:
dtSample.Columns("Selected").ReadOnly = False
' create Source DV as Selected = False
dvSource = New DataView(dtSample,"Selected=False", "",
DataViewRowState.CurrentRows)
' create Dest DV as Selected = True
dvDest = New DataView(dtSample, "Selected=True", "",
DataViewRowState.CurrentRows)
' assign DS
lbSource.DataSource = dvSource
lbSource.DisplayMember = "Name"
lbSource.ValueMember = "Id"
lbDest.DataSource = dvDest
lbDest.DisplayMember = "Name"
lbDest.ValueMember = "Id"
Then in the click events:
' select
CType(lbSource.SelectedItem, DataRowView).Row("Selected") = True
' deselect:
CType(lbSource.SelectedItem, DataRowView).Row("Selected") = False
The two DataView objects will filter on Selected inversely. When you change the state of a row, it is instantly removed from one and appears in the other without actually being added/removed from any table (or collection or control). If you move it back to the Source it will appear in the same position as before.
In this case, the RowState of any item moved will be Modified, which of course it is (unlike the move-to-table approach where they would be new rows (Added) which they are not).
It is hard to illustrate without 5 or 6 images, but the idea:
It is actually a pretty simple method and more economical than one invovling actually moving rows. Using DataViews the rows/items look like they move to another table or control, but they do not, nor do they need to.

change color of DataGrid row

I want to color entire rows of a System.Windows.Forms.DataGrid based on the content of one cell of the Row.
I couldn't find any way to do that, since there is no .Rows-Property of the DataGrid or a .Row-Property of the DataGridTextBoxColumn (or any similar).
Searching for solutions in the internet also didn't help me so far.
Switching to DataGridView is unfortunately not an option.
So the question remains: How can I change the color of a DataGrid row?
Thanks to this link (provided by #Monty) I was able to solve the problem.
You have to format every Cell on its own, so you have to hook up on the SetCellFormat-Event of every Column:
AddHandler column.SetCellFormat, AddressOf FormatGridRow
In the EventHandler you can check for example the cell value of another column of the same row and change the color of the current cell accordingly. When every cell of the row gets formatted this way, it seems like the row as a whole is formatted.
Private Sub FormatGridRow(ByVal sender As Object, ByVal e As DataGridFormatCellEventArgs)
Dim Cell As DataGridColumnStyle = sender
Dim ColumnStyles As GridColumnStylesCollection = Cell.DataGridTableStyle.GridColumnStyles
Dim columnIndex As Integer = ColumnStyles.IndexOf(ColumnStyles.Item("ColumnName"))
If Cell.DataGridTableTableStyle.DataGrid(e.Row, columnIndex).ToString() = "SomeValue" Then
e.BackBrush = New SolidBrush(Color.Red) 'this does only change the Cell`s background
End If
End Sub

Select first visible cell of new row in DataGridView

I'm trying to focus input and fire the editing event on each new row that I add to a DataGridView in my form.
This is the code I am trying to user to achieve this.
Private Sub grd_GoldAdders_RowsAdded(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowsAddedEventArgs) Handles grd_GoldAdders.RowsAdded
Dim grid As DataGridView = DirectCast(sender, DataGridView)
grid.ClearSelection()
If grid.Rows(e.RowIndex).Cells("grid_flag").FormattedValue = Constants.[New] Then
For Each cell As DataGridViewCell In grid.Rows(e.RowIndex).Cells
If Not cell.Visible Then Continue For
grid.CurrentCell = cell
grid.BeginEdit(False)
Exit For
Next
End If
End Sub
The "grid_flag" is a hidden cell which is used to store custom states for a row.
Prior to adding a row, this is what we see on the form:
This is what we see when we actually try and add a new row:
Notice that both the column 0,0 and the first visible column of the new row are selected, but the column 0,0 has the focus. I do not wish for 0,0 to either get selected or have the focus. I also see here that the row indicator is pointing at row 0 too...
This is how I would like to see things after clicking my Add button:
Does anyone know where I am going wrong with the code? I've searched SO for the most part of the day trying to solve this one.
Instead of using your DataGridView's RowAdded event to set the CurrentCell, add the following code wherever you're adding a new record to your DGV (in your Add button's Click event I assume):
''# Add the new record to your Data source/DGV.
For Each row As DataGridViewRow In grd_GoldAdders.Rows
If row.Cells("grid_flag").FormattedValue = Constants.[New] Then
grd_GoldAdders.CurrentCell = row.Cells("AssySiteColumn") ''# I'm calling the first column in your DGV 'AssySiteColumn'.
grd_GoldAdders.BeginEdit(False)
Exit For
End If
Next
This code simply loops through all the rows in your DGV and specifies as the CurrentCell the first cell in the first row with your Constants.[New] flag value.