How to prevent manual input into a ComboBox in C# - c#

I have a form in C# that uses a ComboBox.
How do I prevent a user from manually inputting text in the ComboBox in C#?
this.comboBoxType.Font = new System.Drawing.Font("Arial", 15.75F);
this.comboBoxType.FormattingEnabled = true;
this.comboBoxType.Items.AddRange(new object[] {
"a",
"b",
"c"});
this.comboBoxType.Location = new System.Drawing.Point(742, 364);
this.comboBoxType.Name = "comboBoxType";
this.comboBoxType.Size = new System.Drawing.Size(89, 32);
this.comboBoxType.TabIndex = 57;
I want A B C to be the only options.

Just set your combo as a DropDownList:
this.comboBoxType.DropDownStyle = ComboBoxStyle.DropDownList;

I believe you want to set the DropDownStyle to DropDownList.
this.comboBoxType.DropDownStyle =
System.Windows.Forms.ComboBoxStyle.DropDownList;
Alternatively, you can do this from the WinForms designer by selecting the control, going to the Properties Window, and changing the "DropDownStyle" property to "DropDownList".

You can suppress handling of the key press by adding e.Handled = true to the control's KeyPress event:
private void Combo1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}

I like to keep the ability to manually insert stuff, but limit the selected items to what's in the list.
I'd add this event to the ComboBox. As long as you get the SelectedItem and not the Text, you get the correct predefined items; a, b and c.
private void cbx_LostFocus(object sender, EventArgs e)
{
if (!(sender is ComboBox cbx)) return;
int i;
cbx.SelectedIndex = (i = cbx.FindString(cbx.Text)) >= 0 ? i : 0;
}

Why use ComboBox then?
C# has a control called Listbox. Technically a ComboBox's difference on a Listbox is that a ComboBox can receive input, so if it's not the control you need then i suggest you use ListBox
Listbox Consumption guide here: C# ListBox

Related

C# ComboBox DropDownStyle=Simple no working at runtime

Why runtime-created ComboBox drop-down is displayed when I put the property DropDownStyle=Simple? Is there some other property I miss in order not to show the drop-down?
The code is:
private void button3_Click(object sender, EventArgs e)
{
ComboBox cmb = new ComboBox();
cmb.Left = 100;
cmb.Top = 500;
cmb.DropDownStyle = ComboBoxStyle.Simple;
this.Controls.Add(cmb);
}
And the output:
The DropDownStyle property specifies whether the list is always displayed or whether the list is displayed in a drop-down: https://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.dropdownstyle(v=vs.110).aspx
Setting it to Simple specifices that the list is always visible and that the text portion is editable: https://msdn.microsoft.com/en-us/library/system.windows.forms.comboboxstyle(v=vs.110).aspx.
If you don't want to show the list by default you should set the DropDownStyle property to either DropDown or DropDownList depending on whether you want the text portion to be editable:
cmb.DropDownStyle = ComboBoxStyle.DropDown;
In my opinion if you don't need to display the drop-down, you don't need a ComboBox.
You can disable your ComboBox setting
cmb.IsEnabled = false;
or I will use a read-only TextBox or something similar.

How to dynamically position a listbox in relation to textbox in winforms

I'm currently programming a grid with winforms. I have multiple textboxes which are making up the cells each. When I click on the cells I want to Display a listbox (it is a single predefined listbox that I added via the designer before, thus the same listbox for each of the cells).
Now my question is how can I Position the listboxes under the textboxes?
The Events I Need to use I know already (as I'm using a Framework there I needed to use the Events there and already know the appropriate one where I can make the listbox visible and invisible).
I have handlers for the current TextBox in the Event. The Problem I have is that I'm not sure
how I can use These informations to Position the Listbox itself.
Thus which commands do I Need to use to Position the listbox?
Add all the textboxes to the enter and leave event
Use the sender to make it work for all textboxes.
TextBox TextB = (TextBox)sender;"
Then use the textbox location X and Y to set the list box.
You need to add to the Y the height of the textbox and the space you want it to have under you're textbox.
"listBox1.Location = new Point(TextB.Location.X, TextB.Location.Y + TextB.Height + 5);"
Use the code below and it works
private void textBox1_Enter(object sender, EventArgs e)
{
TextBox TextB = (TextBox)sender;
listBox1.Location = new Point(TextB.Location.X, TextB.Location.Y + TextB.Height + 5);
listBox1.Visible = true;
}
private void textBox1_Leave(object sender, EventArgs e)
{
listBox1.Visible = false;
}

How to change ForeColor of ComboBox's Selected Item?

Is it possible to change appearance for selected (not in drop down!) item?
combobox.ForeColor is changing the text color only for all items into drop-down list.
Edit:
Variants are beelow, ours is
public static void CBoxDrawItem(object sender, DrawItemEventArgs args)
{
var box = sender as ComboBox;
if (box == null || args.Index < 0 || args.Index >= box.Items.Count)
return;
e.DrawBackground();
var data = box.Tag as ControlData;
var color = (args.State & DrawItemState.ComboBoxEdit) == 0 || data == null || !data.IsInDefaultState
? e.ForeColor : GetDefaultColor(e.ForeColor);
using (var brush = new SolidBrush(color))
{
args.Graphics.DrawString(box.Items[args.Index].ToString(), args.Font, brush, args.Bounds.X, args.Bounds.Y);
}
args.DrawFocusRectangle();
}
You don't have to change the FlatStyle to Popup or Flat to make this work. And you probably don't want to do that in the first place, because those styles tend to look really ugly when compared to the rest of your application's interface. Native Windows controls use a 3D-style appearance; the Flat and Popup styles are designed for Web or Windows Mobile applications, where they are a better fit.
I assume that you're asking this question because you have already written code to change the foreground color of the text displayed in the combobox, but have noticed that it isn't working under Windows Vista or later. That's because when the DropDownList style of combobox changed to look more like a button in those versions of Windows, it also lost support for custom text color. Instead, the selected text is always displayed in the standard "Window Text" color. Compare the DropDownList style to the regular DropDown style combobox:
Visually, the two comboboxes look the same in earlier versions of Windows, but not under Vista and later. The key to getting your custom foreground color to appear is changing the DropDownStyle property of your combobox control to DropDown (which is actually the default).
I also like to set the FlatStyle property to System so that you get all the nifty fade-in and fade-out effects offered by the native Windows controls. The Standard style attempts to emulate those effects in managed code, but it just doesn't have quite the right feel. I care about the little things.
Then you can use the following code (as originally suggested in Adrian's answer):
public Form1()
{
InitializeComponent();
// Set custom combobox styles
comboBox1.DropDownStyle = ComboBoxStyle.DropDown;
comboBox1.FlatStyle = FlatStyle.System;
// Attach relevant event handler methods
comboBox1.DropDown += new EventHandler(comboBox1_DropDown);
comboBox1.DropDownClosed += new EventHandler(comboBox1_DropDownClosed);
}
void comboBox1_DropDown(object sender, EventArgs e)
{
// Optionally, revert the color back to the default
// when the combobox is dropped-down
//
// (Note that we're using the ACTUAL default color here,
// rather than hard-coding black)
comboBox1.ForeColor = SystemColors.WindowText;
}
void comboBox1_DropDownClosed(object sender, EventArgs e)
{
// Change the color of the selected text in the combobox
// to your custom color
comboBox1.ForeColor = Color.Red;
}
To produce the following effect:
If you can change the FlatStyle of the combo box to Popup or Flat the color of the selected item will also change when you change the ForeColor.
To change only the color of the selected item you can implement some kind of workaround and change the ForeColor each time the DropDown is opened or closed.
Code Sample:
public Form1()
{
InitializeComponent();
comboBox1.FlatStyle = FlatStyle.Popup;
comboBox1.DropDown += new EventHandler(comboBox1_DropDown);
comboBox1.DropDownClosed += new EventHandler(comboBox1_DropDownClosed);
}
void comboBox1_DropDownClosed(object sender, EventArgs e)
{
comboBox1.ForeColor = Color.Red;
}
void comboBox1_DropDown(object sender, EventArgs e)
{
comboBox1.ForeColor = Color.Black;
}
You can use the Cody Gray' sugestion and add it to has the same DropDownList Style behaviour:
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
On this way the user can't edit the combobox.

How to create an Auto-complete combo-box or text box to filter text containing a string

How do I create an Auto-complete ComboBox or TextBox that filters text based on a string?
For example: if I type an "a" in a TextBox, I only get to see all strings containing an "a".
If you mean show suggestions then it's a simple matter of changing a property when you have the TextBox selected in your IDE of choice:
The options shown in the picture allow you to change the rules for autocompleting text in the text box as well as the source for the suggestions. (Visual Studio 2010)
You can go to the following link to learn more about the TextBox control.
MSDN Text Box Control
Windows Forms's autocomplete implementation uses Shell's autocomplete object, which can only do a "BeginWith" match until Windows Vista.
If you can demand your users to upgrade to Windows Vista, you can use IAutoComplete2::SetOptions to specify ACO_NOPREFIXFILTERING. Otherwise I am afraid you need to write your own.
Here is how I auto-complete for a specific value in a comboDropDown box.
void comboBox_Leave(object sender, EventArgs e)
{
ComboBox cbo = (sender as ComboBox);
if (cbo.Text.Length > 0)
{
Int32 rowIndex = cbo.FindString(cbo.Text.Trim());
if (rowIndex != -1)
{
cbo.SelectedIndex = rowIndex;
}
else
{
cbo.SelectedIndex = -1;
}
}
else
{
cbo.SelectedIndex = -1;
}
}
This filters results based on user input. Optimizing for large lists, populating your own data and error handling left out for you to complete:
public partial class Form1 : Form
{
List<String> data;
ListView lst = new ListView();
TextBox txt = new TextBox();
public Form1()
{
InitializeComponent();
data = new List<string>("Lorem ipsum dolor sit amet consectetur adipiscing elit Suspendisse vel".Split());
}
private void Form1_Load(object sender, EventArgs e)
{
this.Controls.Add(txt);
lst.Top = 20;
txt.TextChanged += new EventHandler(txt_TextChanged);
lst.View = View.List;
this.Controls.Add(lst);
list_items("");
}
void txt_TextChanged(object sender, EventArgs e)
{
list_items(txt.Text);
}
void list_items(string filter)
{
lst.Items.Clear();
List<string> results = (from d in data where d.Contains(filter) select d).ToList();
foreach (string s in results)
{
lst.Items.Add(s);
}
}
}
To get the combobox to auto complete, set the AutoCompleteSource and AutoCompleteMode properties:
cbo.AutoCompleteSource = AutoCompleteSource.ListItems;
cbo.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
The ListItems source tells the combo to use it's items collection as the auto complete source.
I know this is an old topic but i tried so hard to find a solution for c# autocomplete filtering too and couldn't find any so i came up with my own simple and easy way so i'll just share it for those who may think it's useful and wanna use in their projects. It does not use the control's autocomplete features. What it does just simply get the text entered from the combobox, search it in the source then display only the matching ones from the source as the combobox' new source. I implemented it in the combobox' KeyUp event.
Let's say (actually this is what i do for almost all the cases when i want autocompleting) we have a globally assigned DataTable called dt_source to be the combobox' source and it has two columns: id(int) and name(string).
DataTable dt_source = new DataTable("table");
dt_source.Columns.Add("id", typeof(int));
dt_source.Columns.Add("name", typeof(string));
And this is what my KeyUp method looks like:
private void cmb_box_KeyUp(object sender, KeyEventArgs e)
{
string srch = cmb_box.Text;
string srch_str = "ABackCDeleteEFGHIJKLMNOPQRSpaceTUVWXYZD1D2D3D4D5D6D7D8D9D0";
if (srch_str.IndexOf(e.KeyCode.ToString()) >= 0)
{
cmb_box.DisplayMember = "name"; // we want name list in the datatable to be shown
cmb_box.ValueMember = "id"; // we want id field in the datatable to be the value
DataView dv_source = new DataView(dt_source); // make a DataView from DataTable so ...
dv_source.RowFilter = "name LIKE '%"+ srch +"%'"; // ... we can filter it
cmb_box.DataSource = dv_source; // append this DataView as a new source to the combobox
/* The 3 lines below is the tricky part. If you repopulate a combobox, the first
item in it will be automatically selected so let's unselect it*/
cmb_box.SelectedIndex = -1; // unselection
/* Again when a combobox repopulated the text region will be reset but we have the
srch variable to rewrite what's written before */
cmb_box.Text = srch;
/* And since we're rewriting the text region let's make the cursor appear at the
end of the text - assuming 100 chars is enough*/
cmb_box.Select(100,0);
cmb_box.DroppedDown = true; // Showing the dropdownlist
}
}
I think your best bet is to override the OnKeyDown(KeyEventArgs e) event, and use the value to filter the ComboBox.AutoCompleteCustomSource. Then as noted above, change the AutoCompleteSource to AutoCompleteSource.ListItems.

DataGridViewCombBoxColumn cell value and different dropdown list

I've a very trivial requirement which makes me go nuts. I've a DataGridView in windows forms application. This contains one databound ComboBox Column. I'm using DisplayMember and ValueMember properties of that combobox.
Now my requirement is ComboBox should show the list of DisplayMembers in drop down list but when user selects one item from it, I should display the part of that DisplayMember in the combobox cell visible to the user. For example.
My display member list looks as below:
"Cust1 - Customer 1"
"Cust2 - Customer 2"
"Cust3 - Customer 3"
and when user selects any one of them from the above list (Say user selected 'Cust2 - Customer 2') then I need to display the value in the combobox column cell as only "Cust2" instead of complete DisplayMember text.
This DisplayMember list is a combination of two fields from the datasource bound to it i.e. First part points to CustomerCode field and second part points Customer name. I need to display only CustomerCode in the ComboBox cell after user selects one item from the drop down list.
How can I do this? Or should I come up with my own control which will have a different AutoCompleteCustomSource and display member value. Even I'm confused with that approach too.
Update: As no one has come up with any solution to my problem. Now I'm starting a bounty for that, also if anyone can suggest me other way to implement the same functionality, it would be great.
I've even tried to come up with my own control and tried to work on simple combobox to display a different value than the selected dropdown list, even that didn't work. Is there any other way to implement this? Any tips and tricks are greatly appreciable.
#Anurag: Here is the code which I've used.
Created a datagridview in the design mode. Created one column of type 'DataGridViewComboBoxColumn' that and named it as CustomerColumn.
In the designer file it looks like below:
private System.Windows.Forms.DataGridViewComboBoxColumn CustomerColumn;
This is the entity class which I've used for datasource
public class Customer
{
public int Id { get; set; }
public string CustCode { get; set; }
public string CustName { get; set; }
public string NameWithCode { get; set; }// CustCode - CustName format
}
In the form load event I'm doing the following:
CustomerColumn.DataSource = GetCustomers();
CustomerColumn.DisplayMember = "NameWithCode";
CustomerColumn.ValueMember = "Id";
I'm answering my own question because I've implemented my own solution to this by using custom control.
This custom control is created by keeping a textbox above combo box in such a way that only drop down button of combobox is visible.
Now I've created a custom column in datagridview deriving the DataGridViewEditingControl from my usercontrol.
I've added a property in Usercontrol which will take drop down list source from the control which is hosting datagridview.
Now in the EditingControlShowing event I'm setting this property as below
private void dataGridView2_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if(dataGridView2.CurrentCell.ColumnIndex.Equals(0) && e.Control is UserControl1)
{
var uscontrol = e.Control as UserControl1;
uscontrol.DropDownListSource = source;
}
}
This drop down list source is used in the usercontrol to set the autocompletesource to the textbox and datasource to the combobox as below:
Whenever I set the DropDownDataSource I'm firing an event in the usercontrol which will do the following. This is to ensure that every time EditingControlShowing event occurs for this column in DataGridView, this source is updated for textbox and combobox in usercontrol.
private void DropDownSourceChanged(object sender, EventArgs eventArgs)
{
textBox1.AutoCompleteCustomSource = DropDownListSource;
textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
comboBox1.DataSource = DropDownListSource;
}
Now whenever user starts typing in the textbox autocomplete source will display dropdown list with 'NameWithCode' values and if user selects one of them then I'll set it to the Text propery overidden in my usercontrol which will be used for the cell value in the DataGridView. Now based on the Textbox text (which is NameWithCode) I can get the code part and set it to the text property.
If user uses combobox dropdown button to select the item then I'll get the combobox selected text and set it in the Textbox which is ultimately used by the cell for getting value.
This way I could achieve the solution I want.
#Homam, solution also works but when I change the ComboBox's DropDownStyle to allow the user to type the value in the combobox it behaves weirdly and not getting up to the mark solution for my requirement. Hence I used this solution.
I know that this is not perfect solution, but I looked for a better one and I didn't find, so I went to a workaround
I did the following:
when the user open the ComboBox, I change the DisplayMember to "NameWithCode"
when the user close it, I return it to "CustCode"
You can Access to the ComboBox control by DataGridView.EditingControlShowing event for the DataGridView.
The code:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
var comboBox = e.Control as ComboBox;
comboBox.DropDown += (s1, e1) => comboBox.DisplayMember = "NameWithCode";
comboBox.DropDownClosed += (s2, e2) =>
{
// save the last selected item to return it after
// reassign the Display Member
var selectedItem = comboBox.SelectedItem;
comboBox.DisplayMember = "CustCode";
comboBox.SelectedItem = selectedItem;
};
}
Note: You have to start the DisplayMember with "CustCode"
Good luck!
Each time at the offensive of event dataGridView1_EditingControlShowing there is addition of new handlers for events comboBox.DropDown and comboBox.DropDownClosed. It results in the increase of number of these handlers and their repeated calls. This code decides this problem.
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
var comboBox = e.Control as ComboBox;
comboBox.DropDown += comboBox_DropDown;
comboBox.DropDownClosed += comboBox_DropDownClosed;
}
private void comboBox_DropDown(object sender, System.EventArgs e)
{
var comboBox = sender as ComboBox;
if(comboBox != null)
{
comboBox.DropDown -= comboBox_DropDown;
comboBox.DisplayMember = "NameWithCode";
}
}
private void comboBox_DropDownClosed(object sender, System.EventArgs e)
{
var comboBox = sender as ComboBox;
if(comboBox != null)
{
comboBox.DropDownClosed -= comboBox_DropDownClosed;
var selectedItem = comboBox.SelectedItem;
comboBox.DisplayMember = "CustCode";
comboBox.SelectedItem = selectedItem;
}
}

Categories

Resources