I have a problem with changing all textboxes in a form with Null to a Value 0.0 after Lost Focus. Specifically, if the textbox is blank after pressing tab it would revert back to 0 since it affects calculations in the other part of the form. Writing the code for every textbox event procedure (57 or so boxes) seems tedious and the names for all the boxes are different.
I was wondering if there was an efficient way to go about changing the textbox value after losing focus easily rather than changing the event procedure for every textbox in the form.
Thanks
Figured I would give an example along with my comments. You could use something along these lines:
Public Function DefaultToZero(frm As Form)
Dim ctrl As Access.Control
For Each ctrl In frm
If ctrl.Tag = "Default" Then
If Nz(ctrl.Value, "") = "" Then
ctrl.Value= "0.0"
End If
End If
Next ctrl
End Function
Then you just select all controls while in design mode and set the tag to 'Default'. Not the best answer but I don't really see any other options besides using each "Lost Focus" event.
Related
We discovered a possible bug involving the DataGridView. The DataGridView has a property, StandardTab, that is set to False by default. This default setting means that the TAB key moves between cells within the grid. When it reaches the final cell in the grid, then the TAB key moves focus to the next control. This is the setting we are using in our project.
The DataGridView is connected to a binding source in our project, which may or may not be relevant.
When the DataGridView is on a form that is being displayed from a COM-based project (VB6, in our case), the grid control loses focus when the user tries to tab within the grid. If you hold down the tab key, focus cycles through other controls on the form until it returns to the grid. When it returns to the grid, the selected cell is the one that the user was tabbing to.
So, it is possible for the user to navigate through all the cells, via a detour through the rest of the controls on the form as they move from cell to cell. This does not make for happy users.
I did find an MSDN forum question that seems to describe this problem, but the only answer to it is not terribly helpful.
I could submit this as a bug on Microsoft Connect, but I doubt they are going to fix it. Is there a way to deal with this issue in code?
Further investigation of the following events/methods revealed a pattern:
Leave (on the control)
ProcessDialogKey (on the form and on the control)
ProcessDataGridViewKey (on the control)
The last two events turned out to be key to the problem.
When we tested in a 100% .NET project, we discovered that tabbing internally would execute the ProcessDataGridViewKey event to fire. When on the last cell, the ProcessDataGridView function was not executed, but the ProcessDialogKey function was executed.
When we tested in the Interop project, the events were exactly the same, but a Leave event on the control occurred before the ProcessDataGridViewKey function was executed. The bad scenario is unique in that the control will not have focus then ProcessDataGridViewKey function is executed.
Perhaps we can test for that and make focus come back to the control? It turns out that we can, and here is a subclassed control that handles it, yet still works fine in a 100% .NET project.
Public Class DataGridViewCustom : Inherits DataGridView
Protected Overrides Function ProcessDataGridViewKey(e As System.Windows.Forms.KeyEventArgs) As Boolean
' When the grid is hosted by a form that is being loaded through the Interop Forms Toolkit,
' the default behavior of using the TAB key to navigate between cells is broken
' (StandardTab = False). The tab key causes the grid control to lose focus before it has a
' chance to process the tab key in this event handler.
'
' This handler is not executed when the TAB key is supposed to make it lose focus (i.e. when
' StandardTab is True or when TABbing off the last cell within the grid). In those
' scenarios, the ProcessDialogKey event handler is executed, and there is no problem.
' Therefore, we can assume that if this event is being processed, and the grid does not have
' focus, we should put focus back on the control.
' The datagridview has different behavior for TAB and CTL-TAB, depending on how the StandardTab
' property is set. We don't have to worry about that becuase this method only executes when the
' focus is supposed to stay within the control. A different method is executed when the focus
' is supposed to leave the control.
If e.KeyCode = Keys.Tab AndAlso Not Me.Focused Then Me.Focus()
Return MyBase.ProcessDataGridViewKey(e)
End Function
End Class
I have a DataGridView bound to a List[of Parts]. The last item in the list is always a 'dummy part', which is there to create an extra row in the grid so the user can start typing into the first cell to add a part to the list.
As soon as the user types more than x characters into that particular cell, a new DataGridView with search results appears under the cell where he is typing (a bit look Google's suggestions), and he can select one of the matches to add the part to the list.
I do this by handling the EditControlShowing event, which assigns the 'editing control' to a TextBox variable which has a handler for TextChanged.
The bug:
I want the focus to change to the second DataGridView (search results) if the user hits the down arrow key.
The EditControlShowing handler works fine first time, moving the focus to the second DataGridView and leaves the first DataGridView in a 'seemingly' functional state, i.e. all other event handlers work. But the second time the EditControlShowing handler fires, the DataGridView throws the NullReferenceException on InitializeEditingControlValue.
Because it is the DataGridView's own call which throw the error, the debugger brings me to "Application.Run" in my code, which isn't helpful.
However, I determined that the call which causes the DataGridView to go into that state, and the point at which exception is thrown, is when I steal focus from the first DataGridView by calling Focus() on the second DataGridView (or any other control for that matter).
If however I let the user change focus to the DataGridView (e.g. by clicking with the mouse), then the DataGridView stays fine.
Does anyone know why stealing focus away from a DataGridView during a handler for EditControlShowing should result in it behaving differently afterwards?
I've tried CancelEdit, Refresh, Enable/Disable etc...
Any suggestions on helping me find out what is going on within the DataGridView? I can't spot anything obvious by inspecting it at breakpoints before and after. I don't even know how to find out what object is null as its the DataGridView's own code...
Many thanks.
OK, I resolved this using BeginInvoke in the TextChanged event handler (code is in Boo but should make sense):
//The event handler
private def CellAsTextBoxTextChanged(sender as object, e as EventArgs):
...
self.BeginInvoke(ShowPartSelectionArea, currentCell, _CellAsTextBox.Text)
//The method which amongst other things, sets the focus to another control
private def ShowPartSelectionArea(currentCell as DataGridViewCell, searchString as string):
...
AnotherDataGridView.Focus()
...
I had previously tried using BeginInvoke directly at the point of calling Focus() on the other control, like so:
private def CellAsTextBoxTextChanged(sender as object, e as EventArgs):
...
ShowPartSelectionArea(currentCell, _CellAsTextBox.Text)
private def ShowPartSelectionArea(currentCell as DataGridViewCell, searchString as string):
...
self.BeginInvoke(AnotherDataGridView.Focus())
...
But the latter didn't work, perhaps because the first way actually allows the DataGridView's cell to finish everything it does whereas the second way doesn't.
So for anyone facing the same problem, I'd advise playing about with where in the call stack you use BeginInvoke.
I have a little problem - in my Windows Forms program I have a lot of text boxes. They only can get numeric values between 1 - 1024. "Protecting" the text box form non numeric inputs is no problem. But how can I assure that the value doesn't get higher than 1024? Is there any function or any event I could try to catch and then Handle it on my own? I thought about catching the "TextChanged" Event and then check for the value. But how can I know then which Button was the last one pressed?
Besides I wouldn't like to exchange my Textboxes with any other Controls since they're all implemented right now and it would be a lot of work to exchange them all.
Best Regards
Quendras
You should use the NumericUpDown control and set the Maximum property.
You could try using OnLostFocus on each text box. Then verify the input was numeric, and it's value is greater/equal to 0, and less/equal to 1024.
You could check when that textbox loses focus, and then check its value:
public sub Textbox1_lostFocus() handles textbox1.onLostFocus
If cint(textbox1.text) > 1024 then
'whatever you need to do here
End if
end sub
First I remove control visibility by doing this:
For Each ctl In Me.MySubform.Controls
ctl.Visible = False
Next ctl
and later, I go back and bind those controls I'm going to use for the current list of fields using an array of the caption and control source name.
For i = 0 To UBound(MyArray) Step 2
Me.MySubform.Controls(i).ControlSource = MyArray(i)
Me.MySubform.Controls(i + 1).Caption = MyArray(i + 1)
Me.MySubform.Controls(i).Visible = True
Me.MySubform.Controls(i + 1).Visible = True
Next i
The issue I run into is, if a user has clicked into one of these fields providing it with focus, I seem to set the control visible property to false or rebind the field to another field during the next refresh event.
I think by removing the controls focus I would be able to accomplish this; however, I have two concerns.
Is this possible in VBA (MS Access 2003)? If so how?
Is there a better more ideal way to accomplish this in this environment? If so, what options are available and what considerations go into picking a solution?
Thanks,
You cannot change the visible property of a control that has focus. Is this the problem? If so, it can be useful to keep a small control to receive focus with SetFocus : http://msdn.microsoft.com/en-us/library/aa205181(office.10).aspx
When editing text the user is able to use the keybord shift button and direction keys to modify the selection - one position stays anchored while the other moves. By pressing left it is possible to get the movable part on the left of the anchored part.
I'm trying to dinamicaly modify the users selection in WPF's TextBox (for the purpose of the discussion, lets say I want to select the characters in pairs, eg. when pressing shift+left, 2 characters would get selected, not just one). However, when using SelectionStart/SelectionIndex/CaretIndex/Select the "movebale end" of the selection is always ends up on the far right end of the selection, rendering the shift+left combination useless.
Any way to preserve the "selection direction"?
This is not quite the answer you are looking for but it'll work. Invoke the command and do it the way WPF does it.
EditingCommands.SelectLeftByCharacter.Execute(null, textBox1);
None of those work. SelectionLength doesn't allowed to be negative, and CaretIndex is always identical to SelectionStart. This is a design bug in TB, as you cannot achieve a valid state of it even in the protected scope.
The command actually works, but you still cannot determine the selection's direction of the currently analyzed textbox. There's only one solution, which is an ugly workaround: You can write your own observer code by overriding the mouse and keyboard event handlers.
The only possibility I can think of is to set the SelectionStart and then make the SelectionLength negative.
Have you tried setting the CaretIndex property before or after setting SelectionStart/SelectionLength?