Selecting cells in Datagridview using vb.net - vb.net

I have a datagridview named datagridview1 inculude a table from ms sql. I want to select a cell and then select another without unselecting the first cell that I have selected before. How can I do that?
I tried this code which is not selecting anything:
Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
If DataGridView1.CurrentCell.Selected = True Then
DataGridView1.CurrentCell.Selected = False
Else
DataGridView1.CurrentCell.Selected = True
End If
End Sub
Any suggestions?

I guess then that you could roll your own datagridview and override the OnCellMouseDown and OnCellMouseUp events to give you this effect without the mouseup cancelling out the currently selected items.
Create a new class in your solution and inherit the datagridview
Public Class MyDataGridView
Inherits DataGridView
Protected Overrides Sub OnCellMouseDown(e As DataGridViewCellMouseEventArgs)
Me.Rows(e.RowIndex).Cells(e.ColumnIndex).Selected = Not Me.Rows(e.RowIndex).Cells(e.ColumnIndex).Selected
End Sub
Protected Overrides Sub OnCellMouseUp(e As DataGridViewCellMouseEventArgs)
End Sub
End Class
This should cancel out the what happens when the mouseclick event process fully which in a standard cell, will deselect the previous selection (unless the CTRL key is used).
Add this code, compile it and you should see at the top of your toolbox a MyDataGridView control. Drag it onto your form, populate it and give it a go.

Related

parse value from datagrid to button name

I'm building a form that has many buttons, all buttons do the same thing: add 1 every time they are clicked. Every pressed button is sent to a datagridview along with the time they are pressed. Datagrid values look like this:
a_1_serv (button name), 18:05:00(time).
Sometimes I want to delete the last row. Everything works fine so far.
When I delete the last row, I want to change the text of the button (a_1_serv).
I can parse the dgv value (a_1_serv) to a variable but I can't bind it to the appropriate button name so I can control it.
Is there a way to do it?
Don't store your program state in your UI
Create a data structure to hold the information, and let the DataGridView be a "view", not treating it as a variable. You will save yourself headaches vs using the UI as a variable.
That said, create a class to represent your information
Public Class Data
Public Sub New(button As Button, time As DateTime)
Me.Button = button
Me.Time = time
End Sub
<System.ComponentModel.Browsable(False)>
Public Property Button As Button
Public ReadOnly Property Text As String
Get
Return Button.Name
End Get
End Property
Public Property Time As DateTime
End Class
And your code can manipulate the data in a variable off the UI. Bind the data to the DataGridView for display.
Private datas As New List(Of Data)()
Private Sub Button_Click(sender As Object, e As EventArgs) Handles Button1.Click, Button2.Click, Button3.Click, Button4.Click
addButton(DirectCast(sender, Button))
End Sub
Private Sub RemoveLastButton_Click(sender As Object, e As EventArgs) Handles RemoveLastButton.Click
removeLast()
End Sub
Private Sub addButton(b As Button)
datas.Add(New Data(b, DateTime.Now))
bindData()
End Sub
Private Sub removeLast()
Dim b = datas.Last.Button
b.Text = "new text" ' change to whatever
datas.RemoveAt(datas.Count - 1)
bindData()
End Sub
Private Sub bindData()
DataGridView1.DataSource = Nothing
DataGridView1.DataSource = datas
End Sub
This does exactly what you stated but there may be inconsistency in these two bits of information you provided: a_1_serv (button name) and I want to change the text of the button .... This changes the button text but not the name. The name is displayed in the grid. You can change the data class to display the text or whatever. But the point is this approach will keep your data off the UI and you won't need to look up the control by name anymore.

Combobox custom control with a lid

I have created a custom combobox with a label to cover the combobox (as it's very ugly) when it's not in use. The label, witch is the lid should show the display member. The covering and uncovering forks fine however the text on the label displayed is the previous value and not the current one. Passing over the label with the mouse, triggers the labels mouse enter event and than the display value is correct.
Here is the code for the custom control.
Public Class ComboBoxWithALid
Inherits ComboBox
Private WithEvents Lid As New Label With {.BackColor = Color.LightCyan, .ForeColor = Color.Black,
.TextAlign = ContentAlignment.MiddleCenter}
Protected Overrides Sub OnDataSourceChanged(ByVal e As EventArgs)
MyBase.OnDataSourceChanged(e)
Lid.Location = Location
Lid.Size = Size
Parent.Controls.Add(Lid)
Lid.BringToFront()
End Sub
Private Sub Lid_MouseEnter(sender As Object, e As EventArgs) Handles Lid.MouseEnter
Lid.SendToBack()
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
MyBase.OnMouseLeave(e)se
Lid.Text = SelectedText
Lid.BringToFront()
End Sub
Protected Overrides Sub OnDropDownClosed(e As EventArgs)
MyBase.OnDropDownClosed(e)
Lid.BringToFront()
Lid.Text = SelectedText
End Sub
End Class
To test the control, drag the control from the tool box to your form and bind the control to any table you have
I tried to use text in place of selected text - same results
I found the solution. Change the move statement to:
Lid.Text = Items(SelectedIndex)(DisplayMember)
and is works.
SelectedText is for the highlighted portion of the text that is currently selected, not the selected item. You probably want something like this:
If SelectedIndex = -1 Then
Lid.Text = String.Empty
Else
Lid.Text = Items(SelectedIndex).ToString()
End If
Yes, you have an annoying control.

Edit Update DatagridView VB.Net (No Database)

Good day everyone.
I need your help in this project I am into (a Visual Basic program with no database.) It just contains a Datagridview, a Textbox, and three buttons (an "Add" Button, a "Edit" and an "Update" Button).
1 . Is there any way (like using "for loop") to automatically assign DataGridView1.Item("item location") to the one edited and be updated?
2 . Or is it possible to just click an item in the Datagridview then it will be edited at that without passing it to a Textbox, and to be updated at that.
The DataGridViewCellEventArgs variable (e in the method stub the designer will generate for you) of the double click event of the cell has RowIndex and ColumnIndex properties which refer to the position of the cell you clicked.
Save those (in a class variable possibly or a local one if that's all you need) and then refer to them when you update the cell in your DataGridView, possibly like this MyDataGridView.Item(e.ColumnIndex, e.RowIndex) or MyDataGridView.Rows(e.RowIndex).Cells(e.ColumnIndex) where e is the variable from the double click event handler.
For you cell double click event you could have something like this:
Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
Using myEditor As New frmCellEditor(Me.DataGridView1.Item(e.ColumnIndex, e.RowIndex).Value)
If myEditor.ShowDialog() = DialogResult.OK Then
Me.DataGridView1.Item(e.ColumnIndex, e.RowIndex).Value = myEditor.NewCellValue
End If
End Using
End Sub
This will call a new instance of your editor and get a value from you. For the purpose of this demo I have made a form like this:
Public Class frmCellEditor
Public NewCellValue As Integer
Public Sub New(ByVal CurrentCellValue As Object)
InitializeComponent()
Me.TextBox1.Text = CStr(CurrentCellValue)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.NewCellValue = CInt(Me.TextBox1.Text)
Me.DialogResult = DialogResult.OK
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Call Me.Close()
End Sub
End Class
Which just has two buttons (Button1 = OK, Button2 = Cancel). When you click OK, it just returns the value 1 which then gets set as the value of the cell.
This is a VERY simplistic example, but it should provide you the basics of what you are trying to do.
UPDATE:
I updated the code for the editor interface so it will include handling for passing the value back and forth from the form with your datagridview.
In your project, make a new form called frmCellEditor. This forms has to have two buttons and a textbox (Make sure that the programmatic names match!). Replace the code with the code listed above. You will have to add Imports System.Windows.Forms above the class as well.
Amend the event handler for the cell double click event of your datagrid to pass the cell value when frmCellEditor is constructed (the line going ... New frmCellEditor(...).
How many columns does your DataGridView has?
Based on how you populate your DataGridView, I'll assume only 1.
Declare this on top of your form
Dim i as Integer
On your btnUpdate_Click Event (Just combine your Edit and Update button into One)
SELECT CASE btnUpdate.Text
Case "Update"
With DataGridView1
'Check if there is a selected row
If .SelectedRows.Count = 0 Then
Msgbox "No Row Selected for Update"
Exit Sub
End If
i = .CurrentRow.Index 'Remember the Row Position
Textbox1.Text = .item(0 ,i).value 'Pass the Value to the textbox
.Enabled = False 'Disable DataGridView to prevent users from clicking other row while updating.
btnUpdate.Text = "Save"
End With
Case Else 'Save
DatagridView1.Item(0,i).Value = Textbox1.Text
btnUpdate.Text = "Update"
END SELECT
Thanks for those who contributed to finding answers for this thread. I have not used your solutions for now (maybe some other time). After some research, I've found an answer for problem 2 (more user friendly at that):
2 . Or is it possible to just click an item in the Datagridview then
it will be edited at that without passing it to a Textbox, and to be
updated at that.
Here's what i did:
in Private Sub Form1_Load, just add:
yourDataGridView.EditMode = DataGridViewEditMode.EditOnEnter
in Private Sub yourDataGridView_(whatever event here: DoubleCellClick, CellContentClick, etc.) add:
DataGridView1(e.ColumnIndex, e.RowIndex).[ReadOnly] = False
DataGridView1.BeginEdit(False)

How to change programmatically cell values of bound DataGridView without receiving exceptions?

I have problems trying to change programmatically the content of a cell of a bound DataGridView.
I implemented a minimal piece of code to show the problem.
Do the following steps to replicate the problem:
Launch example
Write the title content to create a new row
CTRL+C on inserted title
Move to grid's empty row to force the creation of a new row
CTRL+V on title cell
Click on previous row (new row creation is cancelled)
Click again to the empty row to force the creation of a new row
Exception: Operation is not valid due to the current state of the object.
Here it is the code:
Public Class Form1
Private _dgv As New DataGridView
Private _Movies As New System.ComponentModel.BindingList(Of Movie)
Public Sub New()
InitializeComponent()
Me.Controls.Add(_dgv)
_dgv.Dock = DockStyle.Fill
_dgv.DataSource = _Movies
AddHandler _dgv.KeyDown, AddressOf DataGridView_KeyDown
End Sub
Private Sub DataGridView_KeyDown(sender As Object, e As KeyEventArgs)
If e.Control AndAlso e.KeyCode = Keys.V Then
_dgv.CurrentCell.Value = Clipboard.GetText
End If
End Sub
Public Class Movie
Public Property Title As String
End Class
End Class
For sure there is something wrong in my implementation but I spent many hours searching a workaround without success. Thank you in advance for any help you can give me.
When setting up the form in the constructor, make sure the EditMode of the DataGridView is DataGridViewEditMode.EditOnEnter. This makes the cell we are pasting to enter edit mode as soon as it receives focus and makes the new row stick instead of being cancelled if we move away from it.
Public Sub New()
InitializeComponent()
Me.Controls.Add(_dgv)
_dgv.Dock = DockStyle.Fill
_dgv.DataSource = _Movies
AddHandler _dgv.KeyDown, AddressOf DataGridView_KeyDown
_dgv.EditMode = DataGridViewEditMode.EditOnEnter
End Sub
Then, instead of setting the cell value, set the Title property of the underlying Movie:
Private Sub DataGridView_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
If e.Control AndAlso e.KeyCode = Keys.V Then
Dim Mov As Movie = _Movies.Last
Mov.Title = Clipboard.GetText
_dgv.Refresh()
End If
End Sub
When you add a new row in the DataGridView, the BindingList is automagically adding a new Movie object to the list. _Movies.Last should gets you the newly added Movie.
Why not use the DataGridView event UserAddedRow?
system.windows.forms.datagridview.useraddedrow

Select the content of textbox when it receives focus

I have found a similar question to mine in Making a WinForms TextBox behave like your browser's address bar
Now i am trying to modify or make it some more different by making it general. I want to apply same action to all the textboxes in form without write code for each one... how many i dun know. As soon as i add a textbox in my form it should behave with similar action of selecting.
So wondering how to do it?
The following code inherits from TextBox and implements the code you mentioned in Making a WinForms TextBox behave like your browser's address bar.
Once you've added the MyTextBox class to your project you can do a global search for System.Windows.Forms.Text and replace with MyTextBox.
The advantage of using this class is you can't forget to wire all the events for every textbox. Also if you decide on another tweak for all textboxes you have one place to add the feature.
Imports System
Imports System.Windows.Forms
Public Class MyTextBox
Inherits TextBox
Private alreadyFocused As Boolean
Protected Overrides Sub OnLeave(ByVal e As EventArgs)
MyBase.OnLeave(e)
Me.alreadyFocused = False
End Sub
Protected Overrides Sub OnGotFocus(ByVal e As EventArgs)
MyBase.OnGotFocus(e)
' Select all text only if the mouse isn't down.
' This makes tabbing to the textbox give focus.
If MouseButtons = MouseButtons.None Then
Me.SelectAll()
Me.alreadyFocused = True
End If
End Sub
Protected Overrides Sub OnMouseUp(ByVal mevent As MouseEventArgs)
MyBase.OnMouseUp(mevent)
' Web browsers like Google Chrome select the text on mouse up.
' They only do it if the textbox isn't already focused,
' and if the user hasn't selected all text.
If Not Me.alreadyFocused AndAlso Me.SelectionLength = 0 Then
Me.alreadyFocused = True
Me.SelectAll()
End If
End Sub
End Class
Assuming you're going to use the accepted solution from the question you link to, all you'd need to do would be that whenever you create a new textbox, you use AddHandler to add the same 3 eventhandlers to each new textbox.
Then you need to change the event handlers to instead of referencing the textbox as this.textBox1 they'll reference it as CType(sender, TextBox) which means that they'll use the textbox that generated the event.
Edit: I'll add that line of code here as well since it's easier to read then
Private Sub TextBox_GotFocus (ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.GotFocus, TextBox2.GotFocus, TextBox3.GotFocus
We use this custom textbox control:
Public Class TextBoxX
Inherits System.Windows.Forms.TextBox
Private Sub TextBoxX_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
SelectAll()
End Sub
end class
You can see the full project of our TextBox (on steroids) on GitHub https://github.com/logico-dev/TextBoxX