I want to have a "select-only" ComboBox that provides a list of items for the user to select from. Typing should be disabled in the text portion of the ComboBox control.
My initial googling of this turned up an overly complex, misguided suggestion to capture the KeyPress event.
To make the text portion of a ComboBox non-editable, set the DropDownStyle property to "DropDownList". The ComboBox is now essentially select-only for the user. You can do this in the Visual Studio designer, or in C# like this:
stateComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
Link to the documentation for the ComboBox DropDownStyle property on MSDN.
To add a Visual Studio GUI reference, you can find the DropDownStyle options under the Properties of the selected ComboBox:
Which will automatically add the line mentioned in the first answer to the Form.Designer.cs InitializeComponent(), like so:
this.comboBoxBatch.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
Stay on your ComboBox and search the DropDropStyle property from the properties window and then choose DropDownList.
Before
Method1
Method2
cmb_type.DropDownStyle=ComboBoxStyle.DropDownList
After
COMBOBOXID.DropDownStyle = ComboBoxStyle.DropDownList;
To continue displaying data in the input after selecting, do so:
VB.NET
Private Sub ComboBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles ComboBox1.KeyPress
e.Handled = True
End Sub
C#
Private void ComboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
for winforms .NET change DropDownStyle to DropDownList from Combobox property
Related
I use a ComboBox DropDown to show a number of items that can be selected. I also use a default text "Select item". It works perfectly apart from the fact that once I picked an item from the list, I can select the text and remove it (using the backspace) so that the area for the selected item is blank (see image).
I would like to prevent this or, in case this is not possible, to have the default text shown again. The latter doesn't work so far, so I tried the DropDownList but then the background of the entire list becomes grey. If I then select OwnerDrawFixed or OwnerDrawVariable in DrawMode, the background turns white again but also the font color becomes white (instead of black).
I found that I have to use DrawItem to change the layout but even that doesn't work. I simply want the same style as I indicated for DropDown. Does anyone know how to do this or where to find a similar question that has already been answered?
How about something like this?
You could also try setting the DropDownStyle to DropDownList and FlatStyle to Flat. This gives you a slightly different result.
private void InitialiseCombo(ComboBox combo)
{
combo.Items.Clear();
combo.Items.AddRange(new object[] { 3391200121, 3391200122 });
combo.DropDownStyle = ComboBoxStyle.DropDown;
combo.Text = "Select Item";
combo.KeyPress += combo_KeyPress;
}
void combo_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
The suggested solution did not do the trick but I found a workaround to the initial problem, which is the manual deletion of the ComboBox Text, so I'll just put it here in case someone else has the same problem. When using
MyComboBox_TextChanged(object sender, EventArgs e)
I can set a restriction myself: if the text is blank, it should show the default text. If the typed text is equal to one of the item in the ComboBox, it should set the selectedItem equal to the typed text.
I also included GotFocus and Leave EventHandlers.
I have maybe an easy question but I would like to ask about possibilities how to bind textbox Text property to combobox SelectedItem property. I do it through combobox SelectedItemChanged event and set text like this:
if(cmbMeasuring.SelectedItem != null)
txtMethod.Text = ((ListBoxItem)cmbMeasuring.SelectedItem).Value;
I have class ListBoxItem which holds 2 strings "Name" and "Value". Then I created BindingList for combobox:
private BindingList<ListBoxItem> lst;
and then set combobox data source in constructor:
cmbMeasuring.DataSource = lst;
cmbMeasuring.DisplayMember = "Name";
This works fine but I dont know if its the best way how to do it. But problem occurs when I change the textbox content. I do it through textbox Leave event:
private void txtMethod_Leave(object sender, EventArgs e)
{
if (cmbMeasuring.SelectedItem != null)
((ListBoxItem)cmbMeasuring.SelectedItem).Value = txtMethod.Text;
}
If textbox lost focus I assign item value. But I have also a menustrip to save input and when I click to it directly this event dont occur so the last input is not saved. I know that this could be done through textbox TextChanged event but it consume a lot of time.
Do you have any better solutions or is it OK? Im not using WPF.
Thanks.
If you have a Click event for the MenuStrip item, you can do the following
MyMenuStripItem.Focus();
This should cause the MenuStrip item to gain focus and therefore causing the TextBox to lose focus.
Try data binding on the TextBox in your form's constructor:
txtMethod.DataBindings.Add("Text", lst, "Value",
false, DataSourceUpdateMode.OnPropertyChanged);
I have this code
private void FrmNovedadMedidas_SelectionChangeCommitted(object sender, EventArgs e)
{
ComboBox c = (ComboBox)sender;
CargarMedidasPorIdTipoMedida(Convert.ToInt16(c.SelectedValue));
this.txtBoxNombreTipoMedida.Text = c.SelectedText;
}
in c.SelectedValue got the new value of the selection (the one that the user has selected in the Combo).
But in c.SelectedText I got the old value of the ComboBox (I mean, the one that was before the user change the selection).
Is there any property that can give me the new Selected Text?
I want to avoid to search in the DataSet binded to the ComboBox everytime.
I've read this but doesn't work, I don't have CommitEdit() in ComboBox
edit:
c.Text also gives me the old one
I seem to remember this situation having to do with the DropDownStyle of the ComboBox.
Can you please try different styles and see if the Text property is set to the new value inside SelectionChangeCommited ?
As per your comment, it seems using DropDownList style solves the issue.
Cheers
I found something.
c.GetItemText(c.SelectedItem)
Is there a directly properties, post it please.
Thanks for readme anyway.
Try the SelectedIndexChanged event on the ComboBox versus the SelectionChangeCommited event. Then use c.Text to get the value the user just selected.
c.SelectedValue() returns null for me.
c.GetItemText(c.SelectedItem) works for me though. Changing the dropdownstyle wasn't an option.
I'm working on a custom control that internally uses a ComboBox.
My problem is when the ComboBox is focused and has the drop-down open, it appears to focus the entire control. I would like to automatically highlight the first item in the drop drown, but right now you have to push the Down key to do so.
Is there a way to programmatically Highlight the first item in a ComboBox (set the readonly IsHighlighted property to true)? I believe the concept of IsHighlight within a ComboBox is different than Focus. Also, I am binding via ItemsSource, so I have no reference to ComboBoxItems.
Here's a way of doing it, although it might not cover all the cases - but you didn't provide too many details (for example, what happens when there is already an element selected? Do you still want to select the first element in the list? The code below will highlight the first element only when there is no selection in the combobox. To make it always select the first element, the DropDownOpened event should be handled too).
public MainWindow()
{
InitializeComponent();
combobox.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
}
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (combobox.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
(combobox.ItemContainerGenerator.ContainerFromIndex(0) as ComboBoxItem).Focus();
}
}
(Hope I understood correctly and this is what you want to do).
It might not be what you are looking for but if you set mycombo.SelectedIndex = 0 then mycombo.IsDropDownOpen = True it should open it up and have the first item selected. It will be highlighted but will also be the value in the combobox as well. I'm not sure if this is not the desired effect though..
I have a binary field in my database that is hard to describe in a UI using a single "Is XXXX?"-type checkbox. I'd rather use a pair of radio buttons (e.g. "Do it the Foo way" and "Do it the Bar way"), but right now all the other fields on my form are data-bound to a business object. I'd like to data-bind the pair of radio buttons to the business object as well, but haven't come up with a good way to do it yet. I can bind one of the buttons to the field, such that the field is set "true" if the button is selected, but while selecting the other button does de-select the first one (that is, the two radio buttons are properly paired), the value of the field does not update to reflect this.
I'd like to be able to say
button1.DataBindings.Add(new Binding("checked", source, "useFoo"));
button2.DataBindings.Add(new Binding("checked", source, "!useFoo"));
but I'm pretty sure that will throw when it runs. Is there an easier way, or should I just put more thought into how to word a single checkbox? I don't want to add extra functions to handle something this trivial...
ETA: A commenter has suggested considering a dropdown (ComboBox). I had thought about this, but how would I data-bind that to a boolean field in a database/Property in a business object? If I bind the SelectedItem to the useFoo property, what would go in the Items collection? Would I have to add just "True" and "False", or could I somehow add a key/value pair object that ties a displayed item ("Use Foo" / "Do Not Use Foo") to the boolean value behind it? I'm having trouble finding docs on this.
About the answer: the solution I wound up using involved modifying the business object -- the basic idea is very similar to the one posted by Gurge, but I came up with it separately before I read his response. In short, I added a separate property that simply returns !useFoo. One radio button is bound to source.UseFoo, and the other is bound to source.UseBar (the name of the new property). It's important to make sure the new property has both getters and setters, or you'll wind up with really odd behavior.
Bind the RadioButton that is directly linked to your boolean value (ie is checked when the value is true).
Add an event handler to the CheckedChanged event on this RadioButton that looks like the following :
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
foreach (Binding b in ((Control)sender).DataBindings)
b.WriteValue();
}
I have found a way of doing this using DataSet/DataTable.
I make a calculated column in the DataTable with the expression IIF(Foo=true, false, true). Let's call that column Bar.
Bar is of type Boolean. Now you can bind one RadioButton.Checked to Foo and one to Bar.
To get Bar checking/unchecking to propagate back to Foo you must go to the generated DataTable code and add one line, the last one in this sample:
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public bool Bar {
get {
try {
return ((bool)(this[this.tableradio.BarColumn]));
}
catch (global::System.InvalidCastException e) {
throw new global::System.Data.StrongTypingException("The value for column \'Bar\' in table \'radio\' is DBNull.", e);
}
}
set {
this[this.tableradio.BarColumn] = value;
this[this.tableradio.FooColumn] = !value;
}
}
If your business object implements INotifyPropertyChanged (which makes binding work nicer), you can add the following code to the visual interface where BO is your business object and is declared withevents and BO.Value is the boolean property you would like to bind to.
Public Property NotValue() As Boolean
Get
Return Not BO.Value
End Get
Set(ByVal value As Boolean)
BO.Value = Not value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotValue"))
End Set
End Property
Private Sub BO_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Handles BO.PropertyChanged
If e.PropertyName = "Value" Then
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotValue"))
End If
End Sub
The following bindings will hook up the radio buttons.
RBTrue.DataBindings.Add(New Binding("Checked", Me.BO, "Value", False, DataSourceUpdateMode.OnPropertyChanged))
RBFalse.DataBindings.Add(New Binding("Checked", Me, "NotValue", False, DataSourceUpdateMode.OnPropertyChanged))
The visual interface should also implement INotifyPropertyChanged. This method works both ways: the original value gets updated if the interface changes and if the original value changes the interface will update correctly.
I came across the same problem, and found out it's actually possible with standard databinding:
button1.DataBindings.Add(new Binding("checked", source, "useFoo", false, DataSourceUpdateMode.OnPropertyChanged);
// no need to databind button 2, since button1.checked
// is set to false when button2 is checked
By default, DataSourceUpdateMode is set to OnValidation. By setting it to OnPropertyChanged, the change is propagated immediately to the databound object.
My business object implements INotifyPropertyChanged;
By testing this solution, I found out that my OnPropertyChanged event was fired twice when I was clicking button2. To prevent this, simply set
button1.CausesValidation = false;
button2.CausesValidation = false;
as shown here:
TextBox leave causes PropertyChanged get fired twice
Do it manually in code. When you load the form set your radio buttons according to your database. When you press a "save" button store de state as you wish. This example stores radios as bit fields in the database.
// Load radio state
radioButton1.Checked = ((myModel)myBindingSource.DataSource).boolOption1;
radioButton2.Checked = ((myModel)myBindingSource.DataSource).boolOption2;
-
// Save radio state
((myModel)myBindingSource.DataSource).boolOption1 = radioButton1.Checked;
((myModel)myBindingSource.DataSource).boolOption2 = radioButton2.Checked;
I tried to drag items from the "Data Sources" panel in Visual Studio 2015 when I defined my radio buttons as booleans in the table but there is issues with the booleans not being updated to false when another radio button is selected. When changing the "causesValidation" to false radiobuttons unchecked automatically when jumping between other text input fields.
You should only have to bind one of the controls as long as you make sure they are in the same group.
You could also consider a DropDown.