I'm letting users select a date/time for a scheduled task to run, using two NumericUpDowncontrols.
I'd like one-digit values to be padded with a leading 0, so as to display 09:00 instead of 9:0.
The definitive solution is to use a DateTimePickerwith ShowUpDown set to True and Format set to Time or Custom. In the latter case, you'd use hh:mm or HH:mm as a custom format.
class CustomNumericUpDown:System.Windows.Forms.NumericUpDown
{
protected override void OnTextBoxTextChanged(object source, EventArgs e)
{
TextBox tb = source as TextBox;
int val = 0;
if (int.TryParse(tb.Text,out val))
{
if (val < 10)
{
tb.Text = "0" + val.ToString();
}
}
else
{
base.OnTextBoxTextChanged(source, e);
}
}
}
I had to do this this morning and came up with a Customised Numeric Up Down for my Windows Forms application. You should be able to change this easily enough to VB.NET.
This is not possible with a NumericUpDown Control.
I have a clever idea~
Why don't you put a textbox covering the textbox part of the numericupdown control (only the scroll of numericupdown will be shown)?
Set your textbox with "00" as the initial value, then disable it, so that the user can't control your textbox.
Then type these codes:
Private Sub numericupdown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ndFrom.ValueChanged
If numericupdown1.Value < 10 Then
textbox1.Text = "0" & numericupdown1.Value
Else
textbox1.Text = numericupdown1.Value
End If
End Sub
class MyNumericUpDown : System.Windows.Forms.NumericUpDown
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (value.Length < 2)
value = "0" + value;
base.Text = value;
}
}
}
Related
Is this truly a bug in Winforms in 2015 or am I just doing something wrong...
1) Create a new winforms project (.net 4.0) and add a combobox to the main form.
2) Use this for your form load code:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim items As New Dictionary(Of Integer, String)
items.Add(1, "Value 1")
items.Add(2, "Value 2")
items.Add(3, "Value 3")
items.Add(4, "Value 3")
Dim dataSource As New BindingSource(items, Nothing)
ComboBox1.DataSource = dataSource
ComboBox1.DisplayMember = "Value"
ComboBox1.ValueMember = "Key"
End Sub
Notice how items 3 & 4 have the same value, but different keys and that the display and value members are set correctly (unless I am going crazy, which is possible). When you run the application, open the combobox and select the last item. Now, open the combobox back up and you will notice that the 2nd to last item is now selected. That is a problem.
Any thoughts?
Thanks!
EDIT: I added an Infragistics UltraComboEditor to the form and placed the following code in the form load event:
For Each item As KeyValuePair(Of Integer, String) In items
UltraComboEditor1.Items.Add(New ValueListItem With {.DataValue = item.Key, .DisplayText = item.Value})
Next
UltraComboEditor1.SelectedIndex = 0
UltraComboEditor1.AutoComplete = True
The Infragistics control allows me to autocomplete and enter my own text and it is not changing my selection when I select an item with the same text as the item above it. The Winforms control should not be changing my selection like that.
When the ComboBox allows the text portion to be edited, then it will pattern match and highlight the first prefix text that matches. This has the side effect that when the listbox is closed, the selected item is updated.
When the ComboBox's DropDownStyle == DropDownList mode, then the item previously selected will be highlighted in the dropdown list.
You can change the behavior by assigning a NativeWindow to the list window and then listen for the LB_SETCURSEL Msg.
You can use this thread as a starting point: Prevent AutoSelect behavior of a System.Window.Forms.ComboBox (C#)
Add an int index field to the Data object. Then in the Register method add:
combo.SelectedIndexChanged += delegate {
data.index = combo.SelectedIndex;
};
Then pass the Data to the native window, which keeps track of the previously selected index.
private class NW : NativeWindow {
Data data;
public NW(IntPtr handle, Data data) {
this.AssignHandle(handle);
this.data = data;
}
private const int LB_FINDSTRING = 0x018F;
private const int LB_FINDSTRINGEXACT = 0x01A2;
private const int LB_SETCURSEL = 0x0186;
protected override void WndProc(ref Message m) {
if (m.Msg == LB_FINDSTRING)
m.Msg = LB_FINDSTRINGEXACT;
if (m.Msg == LB_SETCURSEL)
m.WParam = (IntPtr) data.index;
base.WndProc(ref m);
}
}
I have predefined columns in my DataGridView.
There are two editable columns and one read-only column.
I have set all columns format to numeric style from cellstyle builder
When I input some text into the two columns, the format won't change, but the read-only column do.
So I've added format change on cellformatting event like this
Dim c As String
If e.ColumnIndex = colHrg.Index _
AndAlso e.Value IsNot Nothing AndAlso e.RowIndex >= 0 Then
c = e.Value.ToString
e.Value = c
End If
e.CellStyle.Format = "N3"
But it seems the event is not fired, so I decided to add format styling on cellendedit event.
Yet, it still didn't worked
dgv_beli.Columns("colHrg").DefaultCellStyle.Format = "N3"
I've also tried editingcontrolshowing and cellvaluechanged event, but still not working
Can someone guide me how to fixed this. I've spent a lot of time to solved this, really curious to find a good solution for my problem.
Add an event of EditingControlShowing
In EditingControlShowing, check that if the current cell lies in the desired column.
Register a new event of KeyPress in EditingControlShowing(if above condition is true).
Remove any KeyPress event added previously in EditingControlShowing.
In KeyPress event, check that if key is not digit then cancel the input.
Example:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
e.Control.KeyPress -= new KeyPressEventHandler(Column1_KeyPress);
if (dataGridView1.CurrentCell.ColumnIndex == 0) //Desired Column
{
TextBox tb = e.Control as TextBox;
if (tb != null)
{
tb.KeyPress += new KeyPressEventHandler(Column1_KeyPress);
}
}
}
private void Column1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
I have a unbound DataGridView with two columns. First column is just string values.
Second column I want to display a combobox, only when user click the cell(not the whole column as DataGridViewColumn). I use the below code which is incorrect and gives me the error : Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function.
The first column is popuated, and the second column is empty.
The code is as below :
Private Sub DGVFieldsMap_CellEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DGVFieldsMap.CellEnter
If e.ColumnIndex = 1 Then
If cboClmCell Is Nothing Then
Dim dgv As DataGridView = CType(sender, DataGridView)
cboClmCell = New DataGridViewComboBoxCell
cboClmCell.Items.Add("A")
cboClmCell.Items.Add("B")
cboClmCell.Items.Add("C")
cboClmCell.Items.Add("D")
cboClmCell.Items.Add("E")
cboClmCell.Items.Add("F")
dgv.Focus()
dgv(e.ColumnIndex, e.RowIndex) = cboClmCell '[Error Here]
isCombo = True
End If
End If
End Sub
Private Sub DGVFieldsMap_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles DGVFieldsMap.CellValidating
If e.ColumnIndex = 1 Then
Dim dgv As DataGridView = CType(sender, DataGridView)
If isCombo Then
isCombo = False
cboClmCell = Nothing
dgv(e.ColumnIndex, e.RowIndex) = New DataGridViewTextBoxCell()
End If
End If
End Sub
Can anybody give me a complete working example with two columns, the second column being a ComboBoxCell, but only when user clicks. Also I need to get the selected values in the DataGridView cell. Thanks In Advance.
Don't try to replace the columns in event handlers, instead create a DataGridView with 2 columns, have the 2nd column be your DataGridViewComboBoxColumn. There is a property on that column called "DisplayStyle" which determines how the column looks when not editing. Set it to "Nothing". Now it will look like a textbox until you go into edit mode at which point it looks like a combobox.
I have a similar DataGridView where the first column is a textual label and the second column is ComboBox.
Note: The code below is in C#, but the concept is the same as in vb.net
In the form's load event, call a function that sets up the datasource and creates the columns
private void frmCfgEdit_Load(object sender, EventArgs e)
{
// Fill CFG Data Grid
FillCfgDataGrid();
}
private void FillCfgDataGrid()
{
// Do not automatically generate the columns based on the datasource public fields
dgCFG.AutoGenerateColumns = false;
// Define data source
dgCFG.DataSource = _pDriveElement.CfgTableViewRecs;
// Define data grid columns
SetUpCFGDataGrid(dgCFG);
}
public void SetUpCFGDataGrid(DataGridView dgCFG, String TableIdentifier)
{
// Create datagridview text column
AddGridColumn(dgCFG, "Label", "CfgLabel", 350, typeof(System.String), true, false);
// Create datadridview combobox column
AddGridComboColumn(dgCFG, "Value", 350, typeof(System.String), false, true);
}
public void AddGridColumn(DataGridView dg, String sHeaderText, String sDataPropertyName, int iWidth, Type tyValueType, bool bReadOnly, bool bLastCol)
{
DataGridViewTextBoxColumn colTxt = new DataGridViewTextBoxColumn();
colTxt.HeaderText = sHeaderText;
colTxt.Width = iWidth;
colTxt.ReadOnly = bReadOnly;
// Add the text box to the data grid
dg.Columns.Add(colTxt);
int iColumn = dg.Columns.Count - 1;
// Define bindings to text columns
dg.Columns[iColumn].DataPropertyName = sDataPropertyName;
dg.Columns[iColumn].ValueType = tyValueType;
if (tyValueType == typeof(System.Single)) dg.Columns[iColumn].DefaultCellStyle.Format = "F6";
if (bLastCol) dg.Columns[iColumn].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
if (iColumn > 0) dg.Columns[iColumn].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
}
public void AddGridComboColumn(DataGridView dg, String sHeaderText, int iWidth, Type tyValueType, bool bReadOnly, bool bLastCol)
{
DataGridViewComboBoxColumn cb = new DataGridViewComboBoxColumn();
cb.FlatStyle = FlatStyle.Flat;
cb.HeaderText = sHeaderText;
cb.Width = iWidth;
cb.ReadOnly = bReadOnly;
dg.Columns.Add(cb);
int iColumn = dg.Columns.Count - 1;
// Combo box is always left aligned
dg.Columns[iColumn].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
if (bLastCol) dg.Columns[iColumn].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
Everytime when I start my program DateTimePicker automatically shows todays date and time. How can I stop this ? How can I make it blank ?
I have a DOB DateTimePicker. For some users I don't know their DOB so I would like the DateTimePicker to show null or empty field.
Set DateTimePicker.CustomFormat = " " Make sure there is a space. This will show up as a blank space.
I used a DataRowView drv = DBBindingSource(DB). along with a control statement to set null when needed.
if(drv.Row["DOB"] == DBNull.Value)
{
DateTimePicker.CustomFormat = " ";
}
else
{
DateTimePicker.CustomFormat = "dd MMMM yyyy";
}
I don't think there is a way to allow it to be blank but you could use the ShowCheckBox and Checked properties set to true. The DateTimePicker will then have a checkbox in addition to the date dropdown. The date dropdown is disabled when not checked. This allows you to have a 'no value' or null for the DOB when the checkbox is not checked.
See this CodeProject article on a Nullable DateTimePicker. It inhertis from DateTimePicker.
Use this :
Private Sub DateTimePicker1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DateTimePicker1.ValueChanged
DateTimePicker1.Value = DateTimePicker1.Value.Today
End Sub
Set it's Value property to the date you want.
if you are talking about datetimepicker from Trent Richardson, have a look at this thread
https://stackoverflow.com/a/12645192/551811
basically, set the inputbox value in the onClose event.
$('input.datetime').datetimepicker({
onClose: function (value) {
$('input.datetime').val(value);
}
});
my solution:
Public Sub ClearDatePicker(ByVal DatePicker As DateTimePicker)
DatePicker.CustomFormat = " "
DatePicker.Format = DateTimePickerFormat.Custom
End Sub
then the datetimepicker will be displayed empty.
I know that the following code blocks the usser from ussing spaces in a textbox however how do i allow the user to only use numbbers and a fulstop (so i can add values like 1.5)
Private Sub Textbox4_keyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox4.KeyDown
If e.KeyCode = Keys.Space Then
TextBox4.Clear()
MsgBox("Invalid character. No spaces Permited...")
End If
From a usability point of view, testing for valid input in the KeyDown event isn’t good. For example, what happens when the user wants to paste text into your text box?
Furthmore, the user can still paste invalid input using the TextBox’ context menu, your code won’t notice this.
You should allow all input, and then test for validity when the user leaves the text box. VB has an extra event for this, which is fired whenever the text box loses focus: Validating. Use this event (and only this event) to test for valid input.
A simple approach for this might be to look for the "allowed" characters, if not one of them, show the error message.
In last 20years of writing code I always use the following rationale for TextBoxes Check Characters.
First you have to create a separate Class which you may call it (for your convenience) Char_Validation.
Inside to this Class you’ll put a Function which returns Boolean as follows .
Public Class Char_Validation
Public Const Gr As String = "Greek"
Public Const En As String = "English"
Public Const Num As String = "Numbers"
Public Const FullGr As String = "Full Greek"
Public Const FullEn As String = "Full English"
Public Const EnN As String = "English with Numbers"
Public Const GrN As String = "Greek with Numbers"
Public Shared Function ValidateChar(ByVal AsciiChar As String, ByVal CharTable As String, ByVal sender As Object, ByVal e As System.EventArgs) As Boolean
Dim ConvChar As Integer = CUInt(Microsoft.VisualBasic.Asc(AsciiChar))
Dim ConvCharW As Integer = CUInt(Microsoft.VisualBasic.AscW(AsciiChar))
ValidateChar = False
Select Case CharTable
Case En
Select Case ConvChar
Case 65 To 126, 145 To 150, 8, 32 To 47, 58 To 64, 128, 130
ValidateChar = True
End Select
Case EnN
Select Case ConvChar
Case 48 To 57, 65 To 126, 8, 32, 45
ValidateChar = True
End Select
.
.
.
.
.
Case Num
Select Case ConvChar
Case 44 To 57, 92, 8
ValidateChar = True
End Select
End Select
End Function
End Class
At your Class in Form you will use the TextBox_KeyPress on which you’ll use the following code.
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
ErrorProvider1.Clear()
ErrorLabel.ForeColor = Drawing.Color.Black
Select Case Char_Validation.ValidateChar(e.KeyChar, Char_Validation.Num, sender, e)
Case True
Case False
ErrorProvider1.SetError(TextBox1, "Wrong Character Only Numbers")
Beep()
e.KeyChar = ""
End Select
End Sub
Thus you will prohibit the user to place characters out of your decision.
I hope that will cover you from now.
Following code worked for me on : firefox, IE 8, chrome, Safari and iphone.
function dotplaced(myfield){
if(myfield.indexOf(".")===-1){
return false;
}
return true;
}
function NumbersOnly(myfield, e) {
var key;
var keychar;
if (window.event) {
key = window.event.keyCode;
}
else if (e) {
key = e.which;
}
else {
return true;
}
keychar = String.fromCharCode(key);
// control keys
if ((key == null) || (key == 0) || (key == 8) ||
(key == 9) || (key == 13) || (key == 27)) {
return true;
}
// numbers
else if ((("0123456789").indexOf(keychar) > -1)) {
return true;
}
// decimal point jump
else if (!dotplaced(myfield.value) && (keychar == ".")) {
//myfield.form.elements[dec].focus();
return true;
}
else {
return false;
}
}