How to determine whether TextChanged was triggered by keyboard in C#? - c#

I have a method
private void textBoxPilot_TextChanged(object sender, TextChangedEventArgs e)
{ ... }
where the textbox in question takes a search string from the user and populates a ListBox with the results on every keystroke.
Subsequently, when an item is picked from the ListBox, I would like the choice reflected in the same Textbox. However, I don't want to trigger the search mechanism, which would cause the Listbox to forget its selection.
How can I determine whether the TextChanged event was triggered by the user (via they keyboard or maybe copy/paste) or by another method using textBoxPilot.Text = "Pilot name";?
Thanks.

bit of a hack, but....
public class MyForm : Form
{
private bool _ignoreTextChanged;
private void listView1_SelectionChanged( object sender, EventArgs e )
{
_ingnoreTextChanged = true;
textBoxPilot.Text = listView1.SelectedValue.ToString(); // or whatever
}
private void textBoxPilot_TextChanged( object sender, TextChangedEventArgs e )
{
if( _ignoreTextChanged )
{
_ignoreTextChanged = false;
return;
}
// Do what you would normally do.
}
}

A disabled control will not fire a event. So two options are either always disable update the text then re-enable or create a derived class wrapper (using this method you could still do data binding)
class myClass : TextBox
{
public virtual string TextWithoutEvents
{
get
{
return base.Text;
}
set
{
bool oldState = Enabled;
Enabled = false;
base.Text = value;
Enabled = oldState;
}
}
}

If the user selects "Pilot name" from the list, you set the text box to "Pilot name". This will cause the list box to select "Pilot name". So the selection should be kept. You just have to break the recursion.

In my scenario where user has to type in text to trigger auto-complete and we didn't want a re-trigger when the auto-complete changes the text again, I used the text lengths. This won't work if user copy/pastes and therefore adds more than 1 character at a time with the keyboard.
private void HandleTextChanged(object sender, TextChangedEventArgs e){
var oldText = e.OldTextValue;
var newText = e.NewTextValue;
// Assuming text changed from keyboard is always 1 character longer,
// ignore this text changed event if new text > 1 character longer.
if (newText.Length > oldText.Length + 1) {
return;
}
...
}
In your scenario, if you always know the values you want to skip, then you could check for them instead:
if (newText == "Pilot name") {
return;
}
or
if (myListOfNamesToIgnore.Contains(newText)) {
return;
}

Related

Is it possible to tell if the Text change on an entry was from code or from the UI?

I am working on a Xamarin project and I need to be able to tell if the changes that occur to the text in an Entry view are from the code or from the UI, is this possible in Xamarin? or is there a known work around to do this.
I know about the OnTextChanged event but this only tells you that the Text property has changed, and gives you access to the old and new value of the Text property. It does not differentiate between different causes of text change.
You can get some idea from this thread, check if the entry is focused to differentiate between different causes of text change:
public MainPage()
{
InitializeComponent();
myEntry.TextChanged += MyEntry_TextChanged;
}
private void MyEntry_TextChanged(object sender, TextChangedEventArgs e)
{
var entry = sender as Entry;
if (entry.IsFocused)
{
//change from UI
Console.WriteLine("change from UI");
}
else{
//change from code
Console.WriteLine("change from code");
}
}
Update: The better way to solve op's problem:
You can set a flag yourself that tells your code to ignore the event. For example:
private bool ignoreTextChanged;
private void textNazwa_TextCanged(object sender, EventArgs e)
{
if (ignoreTextChanged) return;
}
Create a method and use this to set the text instead of just calling Text = "...";::
private void SetTextBoxText(TextBox box, string text)
{
ignoreTextChanged = true;
box.Text = text;
ignoreTextChanged = false;
}
Refer: ignoreTextChanged
you can use EntryRenderer to detect keypress event and use that flag to detect the change by code or by UI.
Here are the step:
- Exetend your entry control with new event OnTextChangeByUI
- Write custom render for both platform
e.g for android it will be something like this
public class ExtendedEntryRender : EntryRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control != null)
{
Control.KeyPress += ((Entry)Element).OnTextChangeByUI;
}
}
}

C# communication between forms bug

I'm working on a GUI for an admin interface for management of a student complex. Currently the GUI has a listbox with predefined 6 rules for the students. In the beginning of the code, I add them to a list
private void Form1_Load(object sender, EventArgs e)
{
foreach (string rule in lbRules.Items)
ruleList.Add(rule);
}
Then, the GUI provides the admin with an option to modify the rules. To do so he selects a rule from the listbox and clicks a "Modify" button, which opens another form:
private void BtnModify_Click(object sender, EventArgs e)
{
if (lbRules.SelectedItems.Count > 0)
{
selectedRule = lbRules.SelectedItem.ToString();
selectedIndex = lbRules.SelectedIndex;
selectedRuleNumber = selectedRule.Substring(0, 3);
selectedRule = selectedRule.Substring(6);
var rulesForm = new Rules();
rulesForm.Show();
}
}
On the second form load event I get the rule's text and number:
private void Rules_Load(object sender, EventArgs e)
{
tbRule.Text = Form1.selectedRuleNumber;
tbModifyRule.Text = Form1.selectedRule;
}
The text gets added to a RichTextBox, from where the rule can be edited.
Then the admin clicks a "Save" button, which gets the edited text from the RichTextBox(tbModifyRule) and adds it to a static ruleList in form1, sets a static boolean from form1 to true. Afterwards the second form gets closed:
private void BtnSave_Click(object sender, EventArgs e)
{
saveRule = Form1.selectedRuleNumber + " - " + tbModifyRule.Text;
Form1.ruleList.Insert(Form1.selectedIndex, saveRule);
Form1.ruleList.RemoveAt(Form1.selectedIndex+1);
Form1.formOpen = true;
this.Dispose();
}
At this point we are back to form1, in which we have a timer with timer_tick event. In there we check whether the boolean formOpen is true (which it is set before closing form2). Inside the if statement we clear the listbox and add each rule from the ruleList (previously edited in form2) to the listbox, then sets the formOpen back to false so it doesn't get executed all the time:
if (formOpen)
{
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
formOpen = false;
Now this is really weird, and at this point makes absolutely no sense to me, since I tried debugging it for over an hour, trying different ways, which also led me to mysterious wonders of WHY TF IT WORKS WHENEVER IT WANTS...
So this works randomly, like it would work the first time, the second and third times it won't. Or vice versa. It's all random.
Strangely, I tried adding a breakpoint on the
lbRules.Items.Add(item);
in the foreach loop, so it stops on each item. And I actually saw the changed rule getting added from the ruleList into the listBox, however in the end it was not there.
And weirdly enough, I also tried adding the text from form2 in the listBox in form1, without using a list, but for whatever odd reason, I use the int selectedIndex, which gets the index of the selected item from the BtnModify_Click event to insert the text in that particular index, but this very index gets RANDOMLY set to bloody 0 after form2 closes.
hence, it again works from time to time, because at some tries it doesn't get set to 0 and it works.
if (formOpen)
{
selectedRule = Rules.saveRule;
lbRules.Items.Insert(selectedIndex, selectedRule);
lbRules.Items.RemoveAt(selectedIndex+1);
}
formOpen = false;
I don't assign value to this integer ANYWHERE else in the code.
I really tried digging some sense, but I hit a solid hard rock.
Any help appreciated!
And thanks for the time!
edit1:
as requested - rest of the timer method
private void Timer1_Tick(object sender, EventArgs e)
{
foreach (string text in ws.messages)
message = text;
if (ws.messages.Count > 0)
{
if (message.Contains("comp"))
{
Complaints();
message = String.Empty;
ws.messages.Clear();
}
}
if (formOpen)
{
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
formOpen = false;
}
I would change your code to the following:
if (formOpen)
{
formOpen = false;
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
The issue with having the formOpen = false; outside the if statement is that there is a chance that once the user clicks the Save button the timer could be about to execute the formOpen = false instruction setting it to false making the code inside the If statement to never be executed.
I truly believe this is not random but just a timing issue due to complicated logic.
If I were you, I'd do a couple things:
Use a separate class for data exchange between forms, avoid using public static (I assume) form members for this.
Instead of a timer, subscribe to the Form.Closed event of RulesForm
This might make code flow a bit more predictable and allow you to find errors more easily.
Better yet, use the following pattern:
class Form1
{
private void BtnModify_Click(object sender, EventArgs e)
{
var ruleData = ..... //get current rule data
var rulesForm = new Rules();
rulesForm.SetData(ruleData); //pass initial state to the form
rulesForm.SaveChanges = this.ApplyRules; //pass a method which will be called on save
rulesForm.Show();
}
private bool ApplyRules(RuleData ruleData)
{
//do whatever you like with the rules here
return true;
}
}
class RuleForm
{
public void SetData(RuleData ruleData)
{
//initialize fields, etc
}
public Func<RuleData, bool> SaveChanges { get; set; }
private void BtnSave_Click(object sender, EventArgs e)
{
var ruleData = .... //get data from form fields
if(this.SaveChanges(ruleData))
this.Close();
}
}
class RuleData
{
//whatever data you need
}

RepositoryItemLookupEdit new value disappears before being processed

I have a LookupEdit in the grid that needs to be able to accept new values. When I enter the new value and press "Enter" or "Tab", it saves normally via the ProcessNewValue event, however when I enter a value and click elsewhere in the grid, on another cell or just in white space, the value vanishes completely. By implementing several other events and setting breakpoints all I figured out was that the value disappears before the "CloseUp" event fires. Validating, EditValueChanged, EditValueChanging, ProcessNewValue, Closed, Leave, and even GetNotInListValue never even get called because of the empty value.
Can anyone think of some setting I haven't found yet, or any other reason why this value would disappear...And how I might stop it from happening?
Found a valid Workaround
I implemented the following 3 events, in sequence, to solve this issue. I still have no idea what caused it, or how to go about preventing it. This is a Workaround, not a solution, and should be treated as such. I end up having to manually call the ProcessNewValue method, as well as forcing the value to equal the text field, and the text field back into the value later on. Not the smoothest of operations, but it does work.
private void repPatchNum1_EditValueChanging(object sender, DevExpress.XtraEditors.Controls.ChangingEventArgs e)
{
string surfaceSoftware = vwSurfaceSoftware.GetRowCellDisplayText(vwSurfaceSoftware.FocusedRowHandle, "SurfaceSoftware");
if (string.Compare(surfaceSoftware, SOFTWARE_CHECK, true) == 0)
{
string version = vwSurfaceSoftware.GetRowCellDisplayText(vwSurfaceSoftware.FocusedRowHandle, "Version");
if (version.ToLower().Contains(VERSION_CHECK))
{//now we are certain we are in the right place
LookUpEdit editor = sender as LookUpEdit;
if (!((RPickListCollection)((BindingSource)editor.Properties.DataSource).DataSource).OfType<RPickList>().Any(a => a.RValue.Equals(e.NewValue)))
{
repPatchNum1_ProcessNewValue(sender, new DevExpress.XtraEditors.Controls.ProcessNewValueEventArgs(e.NewValue));
vwSurfaceSoftware.SetRowCellValue(vwSurfaceSoftware.FocusedRowHandle, colPatchNum, e.NewValue);
}
}
}
}
private void repPatchNum1_CloseUp(object sender, DevExpress.XtraEditors.Controls.CloseUpEventArgs e)
{
string surfaceSoftware = vwSurfaceSoftware.GetRowCellDisplayText(vwSurfaceSoftware.FocusedRowHandle, "SurfaceSoftware");
if (string.Compare(surfaceSoftware, SOFTWARE_CHECK, true) == 0)
{
string version = vwSurfaceSoftware.GetRowCellDisplayText(vwSurfaceSoftware.FocusedRowHandle, "Version");
if (version.ToLower().Contains(VERSION_CHECK))
{//now we are certain we are in the right place
LookUpEdit editor = sender as LookUpEdit;
if (!((RPickListCollection)((BindingSource)editor.Properties.DataSource).DataSource).OfType<RPickList>().Any(a => a.RValue.Equals(e.Value)))
{
e.Value = ((LookUpEdit)sender).Text;
}
}
}
}
private void repPatchNum1_Closed(object sender, DevExpress.XtraEditors.Controls.ClosedEventArgs e)
{
string surfaceSoftware = vwSurfaceSoftware.GetRowCellDisplayText(vwSurfaceSoftware.FocusedRowHandle, "SurfaceSoftware");
if (string.Compare(surfaceSoftware, SOFTWARE_CHECK, true) == 0)
{
string version = vwSurfaceSoftware.GetRowCellDisplayText(vwSurfaceSoftware.FocusedRowHandle, "Version");
if (version.ToLower().Contains(VERSION_CHECK))
{//now we are certain we are in the right place
LookUpEdit editor = sender as LookUpEdit;
string patch = vwSurfaceSoftware.GetRowCellValue(vwSurfaceSoftware.FocusedRowHandle, colPatchNum).ToString();
if (String.IsNullOrEmpty(editor.Text) && !String.IsNullOrEmpty(patch))
{
editor.Text = vwSurfaceSoftware.GetRowCellValue(vwSurfaceSoftware.FocusedRowHandle, colPatchNum).ToString();
vwSurfaceSoftware.UpdateCurrentRow();
}
}
}
}
As to the original question: Please post an answer if you know why this might be happening or how to prevent it.
Thanks all :-)
I think I found a simpler workaround, tested on DevExpress 13.
When user presses Tab/Enter, event sequence is ProcessNewValue -> CloseUp
However if user finishes lookup by clicking somewhere else, events are reversed: CloseUp -> ProcessNewValue and entered value is lost. We can use PopupCloseMode.Immediate (specifies that the dropdown window was closed because an end-user clicked outside the editor) to detect this case, manually take entered value from editor, set it to event Value field and manually call ProcessNewValue. No need for other events.
private void myLookUp_CloseUp( object sender, CloseUpEventArgs e )
{
var lookUpEdit = sender as LookUpEdit;
if( lookUpEdit != null )
{
var enteredLookUpText = lookUpEdit.Text;
if( e.CloseMode == PopupCloseMode.Immediate )
{
e.Value = enteredLookUpText;
myLookUp_ProcessNewValue( sender, new ProcessNewValueEventArgs( enteredLookUpText ) );
}
}
// Rest of event handler
}

Is there a BeforeUpdate for a C# ComboBox on a Winform

I come from the VBA world, and remember there was a BeforeUpdate call I could make on a combobox. Now I am in C# (and loving it) and I was wondering is there a BeforeUpdate call for a ComboBox on a Winform?
I can make an invisible textbox and store the info I need there and after the update, look at that box for what I need, but I was hoping there was a simplier solution.
One of the goodies of WF is that you can easily make your own. Add a new class to your project and paste the code below. Compile. Drop the new control from the top of the toolbox onto your form. Implement the BeforeUpdate event.
using System;
using System.ComponentModel;
using System.Windows.Forms;
public class MyComboBox : ComboBox {
public event CancelEventHandler BeforeUpdate;
public MyComboBox() {
this.DropDownStyle = ComboBoxStyle.DropDownList;
}
private bool mBusy;
private int mPrevIndex = -1;
protected virtual void OnBeforeUpdate(CancelEventArgs cea) {
if (BeforeUpdate != null) BeforeUpdate(this, cea);
}
protected override void OnSelectedIndexChanged(EventArgs e) {
if (mBusy) return;
mBusy = true;
try {
CancelEventArgs cea = new CancelEventArgs();
OnBeforeUpdate(cea);
if (cea.Cancel) {
// Restore previous index
this.SelectedIndex = mPrevIndex;
return;
}
mPrevIndex = this.SelectedIndex;
base.OnSelectedIndexChanged(e);
}
finally {
mBusy = false;
}
}
}
You may consider SelectionChangeCommited.
From MSDN:
SelectionChangeCommitted is raised
only when the user changes the combo
box selection. Do not use
SelectedIndexChanged or
SelectedValueChanged to capture user
changes, because those events are also
raised when the selection changes
programmatically.
This won't work when you have set your combobox to allow the user to type in the textbox though. Also, it won't tell you what the 'last' selected item was. You will have to cache this information. However, you don't need to store your information in a textbox. You can use a string.
You could try ValueMemberChanged, Validating, SelectedIndexChanged, or TextChanged. They don't fire like the BeforeUpdate, but you can look at what will be updated and handle the updated, or refuse it.
Out of the box, there's nothing like that. All of the events that deal with change in the combo box happen after the new value is already selected. At that point there's no way to tell what the value USED to be. You're best bet is what you eluded to. As soon as your ComboBox is populated save the SelectedItem to a temporary variable. Then, hook into the SelectedValueChanged event. At that point, your temporary variable will be your old value, and the SelectedItem will be your current value.
private object oldItem = new object();
private void button3_Click(object sender, EventArgs e)
{
DateTime date = DateTime.Now;
for (int i = 1; i <= 10; i++)
{
this.comboBox1.Items.Add(date.AddDays(i));
}
oldItem = this.comboBox1.SelectedItem;
}
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
//do what you need with the oldItem variable
if (oldItem != null)
{
MessageBox.Show(oldItem.ToString());
}
this.oldItem = this.comboBox1.SelectedItem;
}
I think what you wanted was the DropDown event. It will tell you what the value is before the user changes it. However, the user may end up not changing anything, so it's not exactly the same as BeforeUpdate.

How to make Combobox in winforms readonly

I do not want the user to be able to change the value displayed in the combobox. I have been using Enabled = false but it grays out the text, so it is not very readable. I want it to behave like a textbox with ReadOnly = true, where the text is displayed normally, but the user can't edit it.
Is there is a way of accomplishing this?
make DropDownStyle property to DropDownList instead of DropDown
then handle the TextChanged event to prevent user changing text.
The article ComboBox-with-read-only-behavior suggests an interesting solution:
Create both a readonly textbox and a combobox in the same place. When you want readonly mode, display the textbox, when you want it to be editable, display the combobox.
Not sure if this is what you're looking for but...
Set the DropDownStyle = DropDownList
Then on the SelectedIndexChanged event
if (ComboBox1.SelectedIndex != 0)
{
ComboBox1.SelectedIndex = 0;
}
This ugly part is that they will "feel" like they can change it. They might think this is an error unless you give them an alert telling them why they can't change the value.
The best thing I can suggest is to replace the combo-box with a read-only textbox (or just perhaps a label) - that way the user can still select/copy the value, etc.
Of course, another cheeky tactic would be to set the DropDownStyle to DropDownList, and just remove all other options - then the user has nothing else to pick ;-p
enter link description here
Just change the DropDownStyle to DropDownList. Or if you want it completely read only you can set Enabled = false, or if you don't like the look of that I sometimes have two controls, one readonly textbox and one combobox and then hide the combo and show the textbox if it should be completely readonly and vice versa.
Here is the Best solution for the ReadOnly Combo.
private void combo1_KeyPress(object sender, KeyPressEventArgs e)
{
e.KeyChar = (char)Keys.None;
}
It will discard the keypress for the Combo.
I've handled it by subclassing the ComboBox to add a ReadOnly property that hides itself when set and displays a ReadOnly TextBox on top containing the same Text:
class ComboBoxReadOnly : ComboBox
{
public ComboBoxReadOnly()
{
textBox = new TextBox();
textBox.ReadOnly = true;
textBox.Visible = false;
}
private TextBox textBox;
private bool readOnly = false;
public bool ReadOnly
{
get { return readOnly; }
set
{
readOnly = value;
if (readOnly)
{
this.Visible = false;
textBox.Text = this.Text;
textBox.Location = this.Location;
textBox.Size = this.Size;
textBox.Visible = true;
if (textBox.Parent == null)
this.Parent.Controls.Add(textBox);
}
else
{
this.Visible = true;
this.textBox.Visible = false;
}
}
}
}
Michael R's code works, but...
The DropDownHeight = 1; must be back to the default value when ReadOnly property is set to false. So, insert before base.OnDropDown(e): DropDownHeight = 106;
using System;
using System.Threading;
using System.Windows.Forms;
namespace Test_Application
{
class ReadOnlyComboBox : ComboBox
{
private bool _readOnly;
private bool isLoading;
private bool indexChangedFlag;
private int lastIndex = -1;
private string lastText = "";
public ReadOnlyComboBox()
{
}
public bool ReadOnly
{
get { return _readOnly; }
set { _readOnly = value; }
}
protected override void OnDropDown (EventArgs e)
{
if (_readOnly)
{
DropDownHeight = 1;
var t = new Thread(CloseDropDown);
t.Start();
return;
}
DropDownHeight = 106; //Insert this line.
base.OnDropDown(e);
}
private delegate void CloseDropDownDelegate();
private void WaitForDropDown()
{
if (InvokeRequired)
{
var d = new CloseDropDownDelegate (WaitForDropDown);
Invoke(d);
}
else
{
DroppedDown = false;
}
}
private void CloseDropDown()
{
WaitForDropDown();
}
protected override void OnMouseWheel (MouseEventArgs e)
{
if (!_readOnly)
base.OnMouseWheel(e);
}
protected override void OnKeyDown (KeyEventArgs e)
{
if (_readOnly)
{
switch (e.KeyCode)
{
case Keys.Back:
case Keys.Delete:
case Keys.Up:
case Keys.Down:
e.SuppressKeyPress = true;
return;
}
}
base.OnKeyDown(e);
}
protected override void OnKeyPress (KeyPressEventArgs e)
{
if (_readOnly)
{
e.Handled = true;
return;
}
base.OnKeyPress(e);
}
}
}
To complete this answer:
File -> New -> Project... Visual C# -> Windows -> Classic Desktop ->
Windows Forms Control Library
type the Name of your control - OK and paste this code.
You can choose the name of your dll file:
Project - yourproject Properties...
Assembly name: type the name. Just build the solution and you have your dll file. So, open the project where you want to use your Read Only combo, right click on References
Add Reference... and browse your dll file. To Insert your custom component into Toolbox, open your Toolbox, right click on General tab -> Choose Items...
Browse your dll file - Open. Now you can use your ReadOnlyComboBox in your projects. PS: I'm using VS2015.
You can change the forecolor and backcolor to the system colors for an enabled combo box, although this may confuse the users (why have it if they can't change it), it will look better.
This is how you would address the fact that a ComboBox with Enabled = False is hard to read:
A combobox that looks decent when it is disabled
Actually, its rather simple:
Private Sub combobox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles combobox1.KeyDown
' the following makes this the combobox read only
e.SuppressKeyPress = True
End Sub
Why don't you just use a text box? Text box has a "Read only" property, and since you want your combo box only to display data, I don't see why you would need a combo box.
An alternative is that you just cancel out the input for the "on value changed" event. That way you will be displaying your information no mater what user does ...
Set DropdownStyle Property to Simple
Add below code to to KeyPress event of ComboBox
private void comboBoxName_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
return;
}
Add below code to to KeyDown event of ComboBox
private void comboBoxName_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
return;
}
If you've already populated it, and selected the appropriate item, and made it a DropDownList, then you can use an extension method like this to quickly reduce the selection list down to just the selected item:
public static void MakeReadOnly(this ComboBox pComboBox) {
if (pComboBox.SelectedItem == null)
return;
pComboBox.DataSource = new List<object> {
pComboBox.SelectedItem
};
}
I know that I'm a little late to the party, but I was researching this exact question and I knew that there had to be some way to make the combobox readonly as if it were a textbox and disabled the list popping up. It's not perfect, but it is definitely better than all of the answers I've been finding all over the internet that don't work for me. After the button is pressed and the OnDropDown is called, a new thread is created that will set the DroppedDown property to false, thus creating the effect of "nothing happening." The mouse wheel is consumed and key events are consumed as well.
using System;
using System.Threading;
using System.Windows.Forms;
namespace Test_Application
{
class ReadOnlyComboBox : ComboBox
{
private bool _readOnly;
private bool isLoading;
private bool indexChangedFlag;
private int lastIndex = -1;
private string lastText = "";
public ReadOnlyComboBox()
{
}
public bool ReadOnly
{
get { return _readOnly; }
set { _readOnly = value; }
}
protected override void OnDropDown(EventArgs e)
{
if (_readOnly)
{
DropDownHeight = 1;
var t = new Thread(CloseDropDown);
t.Start();
return;
}
base.OnDropDown(e);
}
private delegate void CloseDropDownDelegate();
private void WaitForDropDown()
{
if (InvokeRequired)
{
var d = new CloseDropDownDelegate(WaitForDropDown);
Invoke(d);
}
else
{
DroppedDown = false;
}
}
private void CloseDropDown()
{
WaitForDropDown();
}
protected override void OnMouseWheel(MouseEventArgs e)
{
if (!_readOnly)
base.OnMouseWheel(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (_readOnly)
{
switch (e.KeyCode)
{
case Keys.Back:
case Keys.Delete:
case Keys.Up:
case Keys.Down:
e.SuppressKeyPress = true;
return;
}
}
base.OnKeyDown(e);
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (_readOnly)
{
e.Handled = true;
return;
}
base.OnKeyPress(e);
}
}
}
Simplest way in code:
instead of adding methods for KeyPress or KeyDown,
add this code on 'Form1_Load' method:
comboBox1.KeyPress += (sndr, eva) => eva.Handled = true;
or
comboBox1.KeyDown += (sndr, eva) => eva.SuppressKeyPress = true;
(sndr, eva) is for (object sender, EventArgs e)
I dont know if that is what you are looking but this prevents the user from chosing any item from the drop down and still be able to type text in the combobox. If you dont want the user to type text in the combobox you can make it Dropdown list from the properties menu.
So you get Read Only combobox.
On Selected Index Changed
Make the selected Index -1 "comboBox.SelectedIndex = -1";
private void MyComboBox_comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
MyComboBox_comboBox.SelectedIndex = -1;
}
Here is the Best solution for the ReadOnly Combo.
private void combo1_KeyPress(object sender, KeyPressEventArgs e) {
e.KeyChar = (char)Keys.None;
}
It will discard the keypress for the Combo. It doesn't have "e.KeyChar" !

Categories