DataGridView - ReadOnly Cell KeyDown Event - vb.net

i have a datagridview with a readonly cell, i would like to show a formdialog window when the user press the space key. but is not possible since the cell is readonly=true.
i'v been using the following code with the EditingControlShowing event. and when the cell is readonly=false it works sometimes.
Private Sub sub_fecha_keydown(ByVal sender As Object, ByVal e As KeyEventArgs)
If e.KeyCode = Keys.Space Then
Dim frm As New frmFecha
frm.fecha_inicial = Me.m_dtp_id_fecha.Fecha
Dim res As DialogResult = frm.ShowDialog()
If res = Windows.Forms.DialogResult.OK Then
Me.m_dgv_detalle.Rows(Me.m_dgv_detalle.CurrentRow.Index).Cells("m_dgv_dtm_documento").Value = frm.fecha_format
Else
Me.m_dgv_detalle.Rows(Me.m_dgv_detalle.CurrentRow.Index).Cells("m_dgv_dtm_documento").Value = ""
End If
End If
End Sub
i would like to keep the cell readonly=true.
is there any other way to do it?
thanks very much for your time and help.

Rather than trying to intercept a keystroke for a readonly cell, which may not be possible, why not add a button column next to the field and when it is pressed, perform your actions.
This way you don't have to worry about whether the cell is readonly or not and it will be easier for your users to understand how the form is to be accessed.
Here is a link to the MSDN documentation on the DataGridViewButtonColumn.

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.

Check to see if selection/text was changed in form

I have a form with about 20 controls on it (ComboBox, TextBox, etc) that I have pre-loaded with data. This is being displayed to the user and gives them the capability to change any of the fields.
I do not know the best way of recognizing that changes have taken place. After some research, I found TextBox.TextChanged and setting the flag IsDirty = True or something along those lines.
I don't think this will be 100% bulletproof since the user might change the value and then go back and change it to how it was when initially loaded. I've been thinking about saving the current data to .Tag and then comparing it with the .Text that was entered when the user clicks "Cancel" to simply ask them if they'd like to save the changes.
This is my code:
Private Sub Form1_Load(ByVal sender as Object, byVal e as System.EventArgs)Handles MyBase.Load
For Each ctr as Control in me.Controls
if typeof ctr is TextBox then
ctr.tag=ctr.text
end if
Next
End Sub
This is the code for when the user clicks "Cancel":
Private Sub CmdCancel_Click (ByVal sender as Object, ByVal e As System.EventArgs) Handles CmdCancel.Click
For each ctr As Control in Me.Controls
If Typeof ctr is Textbox then
if ctr.tag.tostring <> ctr.text then
MsgBox ("Do you want to save the items", YesNo)
end if
End if
Next
End sub
Is this an effective way to do this? Can it be relied on? If anyone has any better idea, I'd love to hear it.
Have a look at this:
For Each txtBox In Me.Controls.OfType(Of TextBox)()
If txtBox.Modified Then
'Show message
End If
Next
EDIT
Have a look at this. This may be of interest to you if you wanted an alternative way to the .Tag property:
'Declare a dictionary to store your original values
Private _textboxDictionary As New Dictionary(Of TextBox, String)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'You would place this bit of code after you had set the values of the textboxes
For Each txtBox In Me.Controls.OfType(Of TextBox)()
_textboxDictionary.Add(txtBox, txtBox.Text)
Next
End Sub
Then use this to find out the original value and compare to the new value:
For Each txtBox In Me.Controls.OfType(Of TextBox)()
If txtBox.Modified Then
Dim oldValue = (From kp As KeyValuePair(Of TextBox, String) In _textboxDictionary
Where kp.Key Is txtBox
Select kp.Value).First()
If oldValue.ToString() <> txtBox.Text Then
'Show message
End If
End If
Next
I know this already has an accepted answer, but I thought the part about checking if the actual text value has changed should be addressed. Checking modified will reveal if any changes were made to the text, but it will fail if the user, for example, adds a character and then deletes it. I think a good way to do this would be with a custom control, so here's an example of a simple control that stores the textbox's original text whenever it is changed programmatically, and has a textaltered property that can be checked to show whether or not the user's modifications actually resulted in the text being different from its original state. This way, each time you fill the textbox with data yourself, the value you set is saved. Then when you are ready, you just check the TextAltered property:
Public Class myTextBox
Inherits System.Windows.Forms.TextBox
Private Property OriginalText As String
Public ReadOnly Property TextAltered As Boolean
Get
If OriginalText.Equals(MyBase.Text) Then
Return False
Else
Return True
End If
End Get
End Property
Public Overrides Property Text As String
Get
Return MyBase.Text
End Get
Set(value As String)
Me.OriginalText = value
MyBase.Text = value
End Set
End Property
End Class

VB DataGridView CellMouseClick event Prevents CellMouseDoubleClick

I'm using Visual Basic to write a WinForm Application. In my DataGridView I have the Selection Mode property set to CellSelect. I am trying to set my DataGrid up so that on a single click, a few textboxes are populated with some data, and on a double click, it will open up a new form and display all kinds of other info.
I have tried both the CellClick + CellDoubleClick events as well as the CellMouseClick + CellMouseDoubleClick however, everytime I double click, the single click event fires first and prevents the doubleclick event from ever firing.
Maybe this is just a lack of understanding on my part and I need to do something different, I thought about just adding a button column and firing the buttonclick event but that will require a lot of re-coding since I hard-coded existing data columns properties such as Column(1...15).visible = false and a lot more. Anyone have any thoughts on how to get both events to fire?
Double Click event
Private Sub DataGridView1_CellDoubleClick(sender As Object, e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDoubleClick
CallLookup.ShowDialog()
Dim PatientID As String = SelectGrid.Rows(SelectGrid.CurrentRow.Index).Cells("PatientID").Value.ToString
PatientID = CallLookup.patientID2
End Sub
Single Click
Private Sub DataGridView1_CellMouseClick1(sender As Object, e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseClick
Dim reader As SqlClient.SqlDataReader = mycommand.ExecuteReader
While reader.Read
Dispatchtxt2.Text = (reader("PickupDispatchedTime").ToString)
Enroute2Txt.Text = (reader("PickupEnRouteTime").ToString)
OnScene2Txt.Text = (reader("PickupOnSceneTime").ToString)
Transport2Txt.Text = (reader("PickupTransportTime").ToString)
Arrival2Txt.Text = (reader("PickupArrivalTime").ToString)
clear2txt.Text = (reader("PickupClearTime").ToString)
End While
DataGridView1.Refresh()
DataGridView1.InvalidateRow(DataGridView1.CurrentRow.Index)
Else
End If
End Sub
I left a few lines out that were just a data connection

Using combobox from class

I have some questions on using of combobox.
1) I need to reference combobox from class like this:
If Me.ActiveControl.GetType Is GetType(ComboBox) And combodroppeddown = False) Then
something...
End If
From Here I need right from the AND to check if this combobox is dropped down but I don't know how.
2) My actual type of combobox is of "DropDownList" type.
Problem is that if I drop it down and type with up/down keys the value is changed according to selected row. If I then press ESC then last value stays as choosen what is not wanted.
Is here way to return original value from moment of dropping in case if I press ESC when list is dropped?
How to do that?
Here is closer look to my xCombo subclass to get help in second question...
Public Class xAutoCombo
Inherits ComboBox
Private entertext As String
Protected Overrides Sub OnKeyDown(ByVal e As KeyEventArgs)
If e.Control Then ' this dropped a list with keyboard
If e.KeyCode = Keys.Down Then
Me.DroppedDown = True
End If
End If
'' this should return value back if ESC was pressed
'' but don't work!
If Me.DroppedDown And e.KeyCode = Keys.Escape Then
Me.Text = entertext
End If
MyBase.OnKeyDown(e)
End Sub
Protected Overrides Sub OnDropDown(ByVal e As System.EventArgs)
entertext = Me.Text '' this remember text in moment of droping
MyBase.OnDropDown(e)
End Sub
EDIT:
Here I found one issue in functionality which I like to be solved.
When combo is dropped and I navigate through list by keyboard and then press with mouse to form (or outside of combo) it closes a list and set value which is last been selected.
Instead of that I would like that combo set his new value ONLY on click with mouse to list or with pressing Enter key with keyboard.
Examine the DroppedDown property, but it seemed like you have other things you wanted to do while dropped down.
Dim cbo As ComboBox
If Me.ActiveControl.GetType Is GetType(ComboBox) then
cbo=Ctype(Me.ActiveControl, ComboBox)
' make it easier to refernece
if cbo.DroppedDOwn then
....
End iF
End if
' Note:
Ctype(Me.ActiveControl, ComboBox).DroppedDown
' should work, but the above is easier to read and use since you apparently
' will have other things to do/override with it
Note also that I think one of the three combobox dropdown types does not use/support the DroppedDown property.
For the rest of your question, which I dont entirely follow, you could also store the last selected item and restore it in similar fashion. Overriding windows default behavior though, is rarely a good idea because you are creating something the user has never encountered before.
EDIT
To change Escape functionality from CLOSE DROPDOWN to ABORT CHOICE:
NOTE: I just used a std cbo, refs will need to be changed to MyBase, events to On...
Private selectedindex As Integer = -1
Private bEsc As Boolean = False
Private Sub cbo_Enter(....
' reset tracking vars...might not be needed
selectedindex = -1
bEsc = False
End Sub
Private Sub cbo_DropDown(...
' capture starting state
selectedindex = cbo.SelectedIndex
bEsc = False
End Sub
KeyDown:
If cbo.DroppedDown AndAlso e.KeyCode = Keys.Escape Then
bEsc = True
e.Handled = True
' this MUST be last!
cbo.DroppedDown = False
End If
Private Sub cbo_DropDownClosed(...
' rest cbo.selectedindex if escape was pressed
If bEsc Then
' note: SelectedIndexChanged event will fire and any code there will run
' may need to qualify with If Esc = False...
cbo.SelectedIndex = selectedindex
End If
End Sub

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)