Odd ComboBox behavior on resize - vb.net

I have an issue where a ComboBox control will change it's Text value when it is resized. Here is some sample code that I worked up:
Option Explicit On
Option Strict On
Public Class FMain
Private Sub FMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
uxComboBox.DropDownStyle = ComboBoxStyle.DropDown
uxComboBox.AutoCompleteSource = AutoCompleteSource.ListItems
uxComboBox.AutoCompleteMode = AutoCompleteMode.Suggest
ComboTest()
End Sub
Private Sub ComboTest()
Dim value As String = "6"
uxComboBox.Text = String.Empty
uxComboBox.Items.Clear()
uxComboBox.Items.AddRange(New String() {"4 9/16", "6 9/16", "7 9/16", "8 9/16"})
Dim index As Integer = uxComboBox.FindStringExact(value)
If uxComboBox.SelectedIndex index Then
uxComboBox.SelectedIndex = index
End If
If uxComboBox.SelectedIndex = -1 AndAlso _
Not String.Equals(uxComboBox.Text, value, StringComparison.OrdinalIgnoreCase) Then
uxComboBox.Text = value
End If
' unselect the text in the combobox
'
uxComboBox.Select(0, 0)
End Sub
End Class
Note that this form (FMain) has a single combobox on it (uxComboBox) that is docked to the top. When I run the code I see that the combobox has a value of "6" which is what I would expect. When I then resize the form, the combobox gets a value of "6 9/16" which is what I would NOT expect.
Does anyone know why this happens? Any suggested workarounds?
Thanks!
Stephen

Yes, this is a known bug in the native Windows implementation of ComboBox. There's another aspect to this bug. Put a button on your form and give it TabIndex = 0, change the CB's TabIndex to 1. Run it, the button will have the focus. Resize. Note that the ComboBox's text changes as before but now also gets highlighted, as though it has the focus. Even though it hasn't.
I think this bug has been around since Vista, it didn't get fixed in Win7. There's no known workaround for it.

When the form loads, ComboTest gets executed, and you see a '6', however when you resize it does not show the new data, sounds like you need to refresh the combo box, regardless of the resize or not.
Try uxComboBox.Refresh() immediately after the line uxComboBox.Items.AddRange.
And after the line 'ComboTest', set the selected index to 0 uxComboBox.Index = 0 also.
Hope this helps,
Best regards,
Tom.

I am using windows 10 and Visual Studio 2017. It appears that this bug is still around. With Hans Passant's answer above I worked around the problem in this way.
I had a combo as a control anchored left and right so it stretched when the form expanded. When the screen expanded, the combobox text was highlighted as if it had got focus even though it hadn't.
As a work around I took one of the anchors off and added it to text box that was next to it. Now my combo box doesn't expand with the screen, the text box does instead. I know its not a fix all solution but it may help someone in a similar situation to sort the problem.

Related

How to hide a DataGridViewButtonCell

I have a DataGridViewButtonCell in my DataGridView and I wanted to set the property Visible to True.
I have tried:
DataGridView1.Rows("number of row i want").Cells("number of cell i want").Visible = True
Unfortunately it says that the property visible is read only.
Here is the code:
Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
'does not work
DataGridView1.Rows(e.RowIndex).Cells(6).Visible = True
End Sub
Does anyone knows how I can achieve this?
Thanks.
There is no actual way to hide a DataGridViewButtonCell. Currently I can only see two options:
Use padding to move the button over as shown here. I will provide similar VB.NET code
Set the Cell to a DataGridViewTextBoxCell and set the ReadOnly property to True
Use Padding:
Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
If DataGridView1.Rows(e.RowIndex).Cells(6).GetType() Is GetType(DataGridViewButtonCell) Then
Dim columnWidth As Integer = DataGridView1.Columns(e.ColumnIndex).Width
Dim newDataGridViewCellStyle As New DataGridViewCellStyle With {.Padding = New Padding(columnWidth + 1, 0, 0, 0)}
DataGridView1.Rows(e.RowIndex).Cells(6).Style = newDataGridViewCellStyle
End If
End Sub
Use DataGridViewTextBoxCell:
Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
If DataGridView1.Rows(e.RowIndex).Cells(6).GetType() Is GetType(DataGridViewButtonCell) Then
Dim newDataGridViewCell As New DataGridViewTextBoxCell
DataGridView1.Rows(e.RowIndex).Cells(6) = newDataGridViewCell
newDataGridViewCell.ReadOnly = True
End If
End Sub
Both of these should give you the effect of not showing the button.
This is really a perspective issue. From a programmer’s perspective, simply ignoring the button clicks on the buttons I want to disable is very easy to do and takes just a few lines of code.
From a user perspective, this situation would play out like this… the user clicks what appears to be a valid enabled button, and nothing happens. The user did not write the code for this… so at best the user will think the computer is not responding to the button click or at the worst… would think your coding skills are dubious!
The same situation happens if the button is missing. The user is not going to know why it is missing… but will most likely come to the same conclusion described above with a non-working button.
In another very simple approach, let say that all the buttons are enabled and we have a list of the button indexes we want to disable. The users presses one of the buttons, we check the disabled button list and if the clicked button is one that is disabled, simply display a message box to indicate why this button is disabled. This approach says to the user… “Here are a bunch of buttons, guess which ones are enabled”…
The DataGridViewDisableButtonCell and DataGridViewDisableButtonColumn wrappers solve all of the above issues… the button is visible so the user wont question where the button went if you set it to invisible and it is greyed out. “Greyed out” is something most users understand and will relieve the user of having to “guess” which buttons are enabled.
You can create a wrapper for two classes: the DataGridViewButtonCell and the DataGridViewButtonColumn.
The link How to: Disable Buttons in a Button Column in the Windows Forms DataGridView Control to the MS example is one I have used before using C#, however there is a VB implementation at the link also.
Below is a picture of the result of using the two wrappers described in the MS link. For testing, the picture below uses the check boxes to left of the button to disable the button on the right.
IMHO, using this strategy is user friendly. If you simply make the button invisible or read only, then the user is possibly going to think your code is messed up and not have a clear understanding of WHY the button is missing or doesn’t work. A disabled button indicates to the user that the button is not available for that item. An option would be to have a mouse roll-over indicating why the button is disabled.

Excel Userform Textbox Constant Set Focus

First of all I would like to thank all of you guys. Maybe you did not notice but you help me to grasp VBA to some level from scratch. I am still in learning process so I may be missing something really simple, please be gentle :)
First of all I would like to give a small backgroud update about my issue. I have been writing a small program to scan incoming parts to my work to be able to keep inventory status. Latest look of the program is like below:
And numbers on the picture are my nightmares lately:
1. Scanned Part Number: This is the textbox where scanner inputs the value. After I receive the input I immidietly convert that data to a variable and clear the textbox value as below:
Private Sub PN_CurrentScan_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then
EnteredPN = Replace(PN_CurrentScan.Value, Chr(32), "", 1) '<---PN_CurrentScan is the name of text box
EnteredPN = Left(EnteredPN, 12)
PN_CurrentScan.Value = ""
After making some corrections on the scanned data I basically write it to a sheet in the workbook. Then I also have a pivot table in the same workbook which uses this scanned data as source and counts how many parts scanned from each part number.
2. Current Status: This ListBox contains all the part numbers scanned (Coming from the pivot table mentioned above) and waiting to be scanned (Coming from another worksheet). Then it refreshes it self every time a new part is scanned.
3. ListBox Scroll Bar: Since I have very long part number list it is not possible for me to fit everything on the screen that is why listbox creates this scroll bar.
Enough with the background I think :)
So if we come to my concern. Since my collages using cordless scanner to do this operation sometimes they don't have the chance to see the screen so they can not understand if the cursor is on the "Scanned Part Number Text Box" or not. That is why I need focus to be on that box no matter what happens (Of course we can not do anything if warehouse burns down, earth quake or tsunami hits the place but let do not think about those).
WHAT I HAVE TRIED:
First of all I disabled all the remaining objects from properties window
Then I diabled tab stops of all controls:
Dim contr As Control
For Each contr In ScannerInterface.Controls
On Error Resume Next
contr.TabStop = False
Next
ScannerInterface.PN_CurrentScan.TabStop = True
Added setfocus property to all button clicks:
Me.PN_CurrentScan.SetFocus
Added setfocus property to listbox click:
Private Sub CurrentStatus_List_Click()
Me.PN_CurrentScan.SetFocus
End Sub
Added set focus to enter and exit events of listbox however this did not work:
Private Sub CurrentStatus_List_Enter()
Me.PN_CurrentScan.SetFocus
End Sub
Private Sub CurrentStatus_List_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Me.PN_CurrentScan.SetFocus
End Sub
So, with all these counter measures I have managed to improve up to somepoint, only concern remaining is when I click on the scroll bar next to the listbox, text box lose focus and without clicking in the textbox I could not manage to set the focus again. I tried all events with listbox non of them worked. Is there any way to solve this problem or do I need to deal with this? Thanks in advance for your supports.
SOLUTION:
Thanks to #Rory we have managed to solve my problem. As he noticed and explained in the answer below, both my textbox and listbox were in frames. I have tried several setfocus options but I always gave the focus to the textbox. However, solution was to give the focus to the frame which was containing the target textbox:
Private Sub CurrentStatus_Frame_Enter() '<-- Enter event of the frame which contains listbox
Me.PN_CurrentScan.SetFocus '<-- Setfocus to target textbox
Me.Scanned_Frame.SetFocus '<-- Setfocus to frame which contains target textbox
End Sub
Having (eventually) noticed that both of your controls are inside container Frame controls, you can actually use the Enter event of the Frame that contains the listbox to set focus to the Frame that contains the textbox, rather than to the textbox itself.

Cut status strip label to width of form

I have a form with a status strip, which contains a progress bar an a label. Both of these are used to show the user the status/progress of several background workers.
My problem is that sometimes the label is longer than the form is wide (it contains Parameter names that vary quite widely in length). The form has a constant width and is not re-sizable by the user. When this issue occurs the label just appears as blank, I would instead like to cut the label to the length of the form and concatenate "..." on the end.
Can anyone give me some advise on where to start with this? i have tried Google and SO searches and have been unable to come up with anything similar. I essentially need to find the length of the string as it will display on the form, but I don't know where to start with that.
First thing to do is to change the StatusStrip.LayoutStyle from Table to Flow. Which will prevent the label from disappearing. Next, you still want the user to have a chance to read the full text of the label even though it is truncated. Set the StatusStrip.ShowItemToolTips property to True and the label's AutoToolTip to True.
Getting the label's text to not overlap the grip is an uglier problem to fix but one you don't have since you made your form un-resizable. Set the form's SizeGripStyle property to Hide.
This will fix your problem, no code required.
You can try something like this:
Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click
If Label1.Text.Length > iMaxLblLenght Then
Label1.Text = Label1.Text.Substring(0, iMaxLblLenght) & "..."
End If
End Sub

How do I color CheckedListBox items in VB.NET?

I am making a personal application in VB.NET that uses a CheckedListBox to store items. I have three buttons on my form, with which I would like to change the selected item's color with (to green, orange, and red.)
I have tried numerous approaches to this issue and have had no such luck. Could someone lend a helping hand?
Use a ListView instead. It has support for checkboxes and selected item colors.
There is a very similar answer here:
For each <item> in CheckedListBox. <item> returns as Object and not as Control
Basically, this control won't do what you want it to (at least not without much complexity). You need to upgrade your control to a ListView.
You can also use TreeView that looks and acts like a checked list box:
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.TreeView1.ShowLines = False
Me.TreeView1.CheckBoxes = True
Dim MyColors() As Color = {Color.Black, Color.Blue, Color.Red, Color.Green, Color.Aqua}
For x As Integer = 0 To 4
Dim NewNode As TreeNode = Me.TreeView1.Nodes.Add("Node" & x)
NewNode.ForeColor = MyColors(x)
Next
End Sub
Took the advice of using a ListView. Looked and worked great on my Windows 7 and Vista boxes but on XP, the ListView did not display properly (items were crunched overtop of one another, checkboxes didn't always display). Checked to make sure it was not a framework version issue and that it was not a screen resolution issue. Ended up retreating back to the CheckedListBox implementation which did NOT have the inconsistency.
Found this solution that accomplished the removal of the blue highlight in the CheckedListBox scenario for me. Using it however you have to keep track of the selection in another manner (global variable, looking at the checked item(s), etc.).
I simply clear the selected item(s) after processing the "..._SelectedIndexChanged". The first thing I do in the "..._SelectedIndexChange" is test for no Selection and do nothing if that is the change. The result is that the currently selected item appears unselected (and actually is unselected, i.e. no blue highlight) however the CheckBox remains checked indicating the most recent selection for the user.
Example ==>
Private Sub ModelCheckedListBox_SelectedIndexChanged(ByVal sender As System.Object,...
Dim x As Short = ModelCheckedListBox.SelectedIndex
If x >= 0 Then
'Something I always do since the Selection Mode = "One" doesn't bother to clear
'the checks itself
ModelCheckedListBox.SetItemChecked(x, True)
If ModelCheckedListBox.CheckedItems.Count > 1 Then
For Each item In ModelCheckedListBox.CheckedIndices
If item <> x Then
ModelCheckedListBox.SetItemChecked(item, False)
End If
Next
End If
ModelCheckedListBox.Refresh()
'More of your code
ModelCheckedListBox.ClearSelected()
End If
End Sub

Winform Textbox CanGrow?

I don't find a CanGrow property on the Textbox control. This is common in some other controls, and what it does is expand the control to acomodate more data. Anyway to get this feature in the TextBox?
Well, I came up with this:
Private Sub TextBox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox.TextChanged
'check to see if textbox has text
If (TextBox.TextLength > 0) Then
'resize height of textbox by count of lines (plus add some padding)
TextBox.ClientSize = New Size(TextBox.ClientSize.Width, Convert.ToInt32((TextBox.Lines.Length * TextBox.Font.Height) + (TextBox.Font.Height * 0.5)))
Else
'resize to one line height (plus padding)
TextBox.ClientSize = New Size(TextBox.ClientSize.Width, Convert.ToInt32(TextBox.Font.Height + (TextBox.Font.Height * 0.5)))
End If
End Sub
Note: it doesn't work with word-warp.
I'm not familiar with CanGrow. Are you looking for Anchor property perhaps?
Anyway to get this feature in the
TextBox?
Well, yes, but, you may need to look into doing this manually. The Graphic.MeasureString() function may be what you are looking for in order to set the width properly.
Keep in mind that MeasureSting may have issues measuring multiline strings.
If you set the anchor properties to top,left,bottom,right then the control will grow as the form resizes.
I think a better option is to use docking though. I usually set up a panel layout with one docked to client, then I put the control I want resized in the panel docked to client, and set the control to dock to client as well.